Search code examples
pythonvariablespyquery

Why can this unbound variable work in Python (pyquery)?


The code is from the guide of pyquery

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

My question is this in the 3rd line is an unbound variable and is never defined in current environment, but the above code still works.

How can it work? Why it doesn't complain NameError: name 'this' is not defined?

It seems that something happens at https://bitbucket.org/olauzanne/pyquery/src/c148e4445f49/pyquery/pyquery.py#cl-478 , could anybody explain it?


Solution

  • This is done via Python's func_globals magic, which is

    A reference to the dictionary that holds the function’s global variables — the global namespace of the module in which the function was defined.

    If you dive into PyQuery code:

    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))