2012-08-05 10 views
11

El código es de la guía de pyquery¿Por qué esta variable independiente puede funcionar en Python (pyquery)?

from pyquery import PyQuery 
d = PyQuery('<p class="hello">Hi</p><p>Bye</p>') 
d('p').filter(lambda i: PyQuery(this).text() == 'Hi') 

Mi pregunta es this en la tercera línea es una variable no unida y nunca se define en el entorno actual, pero el código anterior sigue funcionando.

¿Cómo puede funcionar? ¿Por qué no se queja NameError: name 'this' is not defined?

Parece que algo sucede en https://bitbucket.org/olauzanne/pyquery/src/c148e4445f49/pyquery/pyquery.py#cl-478, ¿alguien podría explicarlo?

+1

Gracias, nunca he oído hablar de PyQuery. Definitivamente va a intentar y usarlo. – Blender

+0

Lo mismo aquí. Nunca supe sobre PyQuery antes, suena interesante .. – SuperSaiyan

Respuesta

4

Esto se hace a través de la magia de func_globals Python, que es

Una referencia al diccionario que contiene las variables globales de la función - el espacio de nombres global del módulo en el que se define la función.

Si bucea en código PyQuery:

def func_globals(f): 
    return f.__globals__ if PY3k else f.func_globals 

def filter(self, selector): 
    if not hasattr(selector, '__call__'): 
     return self._filter_only(selector, self) 
    else: 
     elements = [] 
     try: 
      for i, this in enumerate(self): 

       # The magic happens here 
       func_globals(selector)['this'] = this 

       if callback(selector, i): 
        elements.append(this) 

     finally: 
      f_globals = func_globals(selector) 
      if 'this' in f_globals: 
       del f_globals['this'] 
     return self.__class__(elements, **dict(parent=self)) 
+0

Gracias, BasicWolf. Pero, ¿cuál es el significado de 'para i, esto en enumerate (self)', por qué sería un bucle establecer el valor de 'func_globals (selector) ['this']'? –

+0

Bueno, enumerate crea una secuencia de [(índice, elemento)] fuera de un iterable (y la clase PyQuery es iterable como una subclase de 'list'). Entonces, 'i' es el índice de un elemento y' this' se refiere a un elemento almacenado en el objeto PyQuery. La mejor manera de entender cómo funciona PyQuery en profundidad es sumergirse en su código. –

-2

Este no lanza un NameError porque la variable podría existir en el momento de la función real se llama.

>>> f = lambda i: some_non_named_var 
>>> f(1) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 1, in <lambda> 
NameError: global name 'some_non_named_var' is not defined 

Lo anterior no da error hasta que llame a la función que ha escondido. En el código de ejemplo que mostró, están configurando manualmente una variable llamada this en el func_globals antes de llamar a la función lambda selector.

+0

¿Por qué esto es downvoted? Puede que no sea tan completo como algunas de las otras respuestas, pero todavía demuestra exactamente lo que está sucediendo. –

1

Otros han señalado correctamente cómo se define this dentro de esa lambda de la que está hablando.

Elaborar un poco más, pruebe el siguiente código:

>>> def f(): 
...  print f_global 
... 
>>> f() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in f 
NameError: global name 'f_global' is not defined 
>>> f.__globals__['f_global'] = "whoa!!" #Modify f()'s globals. 
>>> f() 
whoa!! 

Esto es exactamente lo que está ocurriendo allí. On line 496, you would see the following code:

for i, this in enumerate(self):    #this is the current object/node. 
    func_globals(selector)['this'] = this #func_globals returns selector.__globals__ 
Cuestiones relacionadas