2013-06-17 63 views
6

Tôi có một đối tượng lambda được tạo trong hàm này:Làm cách nào để ánh xạ các mục nhập func_closure thành các tên biến?

def add_url_rule(self, rule, endpoint=None, view_func=None, **options): 
    self.record(lambda s: 
     s.add_url_rule(rule, endpoint, view_func, **options)) 

Sử dụng func_closure của đối tượng chức năng lambda tôi có thể truy cập vào phạm vi đóng cửa của hàm lambda:

(<cell at 0x3eb89f0: str object at 0x2fb4378>, 
<cell at 0x3eb8a28: function object at 0x3cb3a28>, 
<cell at 0x3eb8a60: str object at 0x3ebd090>, 
<cell at 0x3eb8b08: dict object at 0x3016ec0>) 

Một cái nhìn gần gũi hơn (tại thuộc tính cell_contents của mỗi đối tượng cell) hiển thị cho tôi điều này:

>>> [c.cell_contents for c in func.func_closure] 
['categoryDisplay', 
<function indico.web.flask.util.RHCategoryDisplay>, 
'/<categId>/', 
{}] 

Đó la MBDA chức năng được tạo ra bởi cuộc gọi này:

add_url_rule('/<categId>/', 'categoryDisplay', rh_as_view(RHCategoryDisplay)) 

Như bạn thấy, thứ tự không phù hợp với trình tự lập luận của hàm hoặc thứ tự mà các đối số được sử dụng bên trong lambda. Trong khi tôi có thể dễ dàng tìm ra yếu tố nào là dựa trên loại/nội dung của nó, tôi muốn làm điều đó một cách rõ ràng hơn.

Vì vậy, câu hỏi của tôi là: Làm thế nào tôi có thể liên kết nó với tên biến ban đầu của chúng (hoặc ít nhất là các vị trí trong trường hợp đối số hàm)?

+0

Hình như các đối số từ khóa được thực hiện đầu tiên, rồi các vị trí, sau đó là tất cả. –

+0

Đây có phải là thử nghiệm với Python 2 hoặc 3 không? –

+1

Tôi đang sử dụng Python 2.7 nhưng nó cần hỗ trợ 2.6 và 2.7. Tôi không nghĩ rằng có bất kỳ thay đổi có liên quan giữa hai phiên bản mặc dù. – ThiefMaster

Trả lời

12

Các đóng cửa được tạo ra bởi các LOAD_CLOSURE bytecode, theo thứ tự giống như bytecode của họ được sắp xếp:

>>> dis.dis(add_url_rule) 
    2   0 LOAD_FAST    0 (self) 
       3 LOAD_ATTR    0 (record) 
       6 LOAD_CLOSURE    0 (endpoint) 
       9 LOAD_CLOSURE    1 (options) 
      12 LOAD_CLOSURE    2 (rule) 
      15 LOAD_CLOSURE    3 (view_func) 
      18 BUILD_TUPLE    4 
      21 LOAD_CONST    1 (<code object <lambda> at 0x10faec530, file "<stdin>", line 2>) 
      24 MAKE_CLOSURE    0 
      27 CALL_FUNCTION   1 
      30 POP_TOP    
      31 LOAD_CONST    0 (None) 
      34 RETURN_VALUE   

để thứ tự được xác định tại thời gian biên dịch, theo compiler_make_closure(); hàm này sử dụng bộ tịnh tiến func.func_code.co_freevars làm hướng dẫn, trong đó liệt kê các bao đóng theo cùng thứ tự.

func.func_code.co_freevars được đặt khi tạo đối tượng mã trong makecode và bộ tuple được tạo từ các khóa của từ điển python, do đó thứ tự là tùy ý, như phổ biến cho từ điển. Nếu bạn tò mò, dict được xây dựng trong compiler_enter_scope(), sử dụng dictbytype() utility function từ tất cả các biến miễn phí có tên trong bảng biểu tượng trình biên dịch, chính nó là từ điển python.

Vì vậy, thứ tự của việc đóng cửa thực sự là tùy ý (bảng băm ra lệnh), và bạn muốn sử dụng func.func_code.co_freevars tuple để gắn tên với đóng cửa:

dict(zip(func.func_code.co_freevars, (c.cell_contents for c in func.func_closure))) 
5

Nhờ YHg1s trong #python trên Freenode tôi đã tìm ra: func_code.co_freevars là một bộ chứa tên biến của các phần tử trong phần đóng.

>>> func.func_code.co_freevars 
('endpoint', 'view_func', 'rule', 'options') 

Vì vậy, việc tạo ra một tên bản đồ dict để giá trị đóng cửa được dễ dàng:

>>> dict(zip(func.func_code.co_freevars, 
      (c.cell_contents for c in func.func_closure))) 
{'endpoint': 'categoryDisplay', 
'options': {}, 
'rule': '/<categId>/', 
'view_func': <function indico.web.flask.util.RHCategoryDisplay>} 
+0

Ah, và ở đây tôi sẽ trả lời * tại sao * chúng theo thứ tự chúng. –

Các vấn đề liên quan