2012-08-05 25 views
11

Mã này là từ hướng dẫn của pyqueryTại sao biến không liên kết này hoạt động trong 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') 

Câu hỏi của tôi là this trong dòng thứ 3 là một biến ràng buộc và không bao giờ được xác định trong môi trường hiện tại, nhưng các mã trên vẫn hoạt động.

Làm cách nào nó có thể hoạt động? Tại sao nó không khiếu nại NameError: name 'this' is not defined?

Dường như có điều gì đó xảy ra tại https://bitbucket.org/olauzanne/pyquery/src/c148e4445f49/pyquery/pyquery.py#cl-478, mọi người có thể giải thích điều đó không?

+1

Cảm ơn, tôi chưa bao giờ nghe nói về PyQuery. Chắc chắn sẽ cố gắng và sử dụng nó. – Blender

+0

Tương tự ở đây. Không bao giờ biết về PyQuery trước đây, âm thanh thú vị .. – SuperSaiyan

Trả lời

4

này được thực hiện thông qua func_globals diệu Python, mà là

Tham chiếu vào từ điển chứa các biến toàn cầu của chức năng - không gian tên toàn cầu của các module trong đó hàm được xác định.

Nếu bạn bổ nhào vào mã 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

Cảm ơn, BasicWolf. Nhưng ý nghĩa của 'cho tôi, cái này trong liệt kê (self) ', tại sao đó sẽ là một vòng lặp để thiết lập giá trị của' func_globals (selector) [' this '] '? –

+0

Vâng, liệt kê tạo ra một chuỗi [(chỉ mục, phần tử)] ra khỏi một iterable (và lớp PyQuery có thể lặp lại như là một lớp con của 'list'). Vì vậy, 'i' là chỉ mục của một phần tử và' this' là một phần tử được lưu trữ trong đối tượng PyQuery. Cách tốt nhất để hiểu cách PyQuery hoạt động sâu như thế nào, là đi sâu vào mã của nó. –

-2

này không ném một NameError vì biến có thể tồn tại đồng thời các chức năng thực tế được gọi.

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

Ở trên không có lỗi cho đến khi bạn gọi hàm mà bạn đã loại bỏ. Trong mã ví dụ bạn đã hiển thị, chúng được đặt theo cách thủ công biến được gọi là this trong func_globals trước khi gọi hàm lambda selector.

+0

Tại sao điều này bị giảm giá? Nó có thể không hoàn chỉnh như một số câu trả lời khác, nhưng nó vẫn chứng minh chính xác những gì đang xảy ra .. –

1

Những người khác đã chỉ ra chính xác cách this được định nghĩa bên trong lambda mà bạn đang nói đến.

Để xây dựng hơn một chút, hãy thử đoạn mã sau:

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

này được chính xác những gì đang xảy ra ở đó. 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__ 
Các vấn đề liên quan