2012-02-08 16 views
9

Tôi muốn đọc giá trị cục bộ của một đối tượng từ một trình trang trí kết thúc tốt đẹp nó. Tôi có quyền truy cập vào chức năng và func_code từ bên trong trang trí nhưng có vẻ như tất cả những gì tôi có thể thoát ra khỏi đó là tên của các vars cục bộ, nhưng không phải là giá trị của chúng.Python: Có cách nào để lấy biến hàm cục bộ từ bên trong một trình trang trí kết thúc tốt đẹp không?

Có thể không?

Trả lời

7

Xem https://stackoverflow.com/a/4249347/224295, http://code.activestate.com/recipes/577283-decorator-to-expose-local-variables-of-a-function-/

dụ làm việc:

import sys 

class persistent_locals(object): 
    def __init__(self, func): 
     self._locals = {} 
     self.func = func 

    def __call__(self, *args, **kwargs): 
     def tracer(frame, event, arg): 
      if event=='return': 
       self._locals = frame.f_locals.copy() 

     # tracer is activated on next call, return or exception 
     sys.setprofile(tracer) 
     try: 
      # trace the function call 
      res = self.func(*args, **kwargs) 
     finally: 
      # disable tracer and replace with old one 
      sys.setprofile(None) 
     return res 

    def clear_locals(self): 
     self._locals = {} 

    @property 
    def locals(self): 
     return self._locals 

@persistent_locals 
def func(): 
    local1 = 1 
    local2 = 2 

func() 
print func.locals 
+0

đó làm việc. Tôi đã đồng ý với ý tưởng tồi của nó ngay từ đầu nhưng tôi đã quan tâm để xem liệu nó có khả thi hay không. – Harel

+0

Bí quyết tuyệt vời. Tôi đang thực hiện một trình gỡ rối phải lén lút lấy nội bộ từ một chức năng được trang trí và cho rằng nó hữu ích một cách hợp pháp. Một điều cần lưu ý là tracer() được gọi không chỉ trên sự trở lại của hàm được trang trí, mà còn trên sự trả về của tất cả các hàm được gọi từ bên trong hàm đó. Kể từ khi chức năng trang trí luôn luôn có sự trở lại cuối cùng, (và do đó đặt _locals cuối cùng) nó không quan trọng trong trường hợp này. – Peter

-2

Thay vì quan trọng xung quanh với internals của chức năng (mà sẽ phá vỡ nếu chức năng trang trí có nguồn gốc), viết wrapper của riêng bạn, như thế này:

def myDecorator(f): 
    def wrapper(*args, **kwargs): 
    print('Arguments to this function %r/%r' % (args, kwargs)) 
    return f(*args, **kwargs) 
    return wrapper 
3

<edit> Tôi chỉ nhận ra tôi misread câu hỏi và rằng bạn không cố gắng lấy các thuộc tính hàm, nhưng các giá trị biến cục bộ từ hàm đó. Những gì bạn muốn làm là không thể vì những biến cục bộ không được tạo cho đến khi hàm được chạy, và phạm vi cục bộ cho hàm sẽ bị xóa ngay sau khi hàm trả về hoặc tăng ngoại lệ.

Tôi để nguyên câu trả lời ban đầu vì bạn có khả năng viết lại hàm của mình để sử dụng thuộc tính thay vì biến cục bộ và vẫn sử dụng trình trang trí này để thực hiện những gì bạn muốn.

Sẽ hữu ích nếu bạn đăng những gì bạn hiện đang thử và một số cuộc gọi mẫu với đầu ra dự kiến ​​nếu nó hoạt động chính xác. </edit>

Khi bạn cần một hàm có thuộc tính, thường là ý tưởng hay khi sử dụng lớp có thể gọi thay vì định nghĩa hàm bình thường.

Dưới đây là một ví dụ về một trang trí nơi wrapper là một lớp callable, cho phép trang trí để truy cập các biến một cách dễ dàng, bởi vì họ là các biến thể hiện của lớp wrapper:

def deco(func): 
    class Wrapper(object): 
     def __init__(self): 
      self.foo = None 
     def __call__(self, *args): 
      print 'old foo:', self.foo 
      result = func(*args) 
      print 'new foo:', self.foo 
      return result 
    return Wrapper() 

@deco 
def my_func(new_foo): 
    my_func.foo = new_foo 

mà kết quả trong my_func hành xử như thế này:

>>> my_func('test') 
old foo: None 
new foo: test 
>>> my_func.foo 
'test' 
>>> my_func(42) 
old foo: test 
new foo: 42 
>>> my_func.foo 
42 
-1

không, nó không thể truy cập các biến bên trong hàm bọc, bởi vì (như FJ chỉ ra trong chỉnh sửa của mình) họ không tồn tại vào thời điểm trang trí là trong phạm vi.

5

Điều bạn đang yêu cầu không thực sự hợp lý.

Biến cục bộ của hàm không có giá trị mọi lúc. Xem xét chức năng này:

def foo(x): 
    y = x + 27 
    return y 

giá trị của biến cục bộ foo 's y là gì? Bạn không thể trả lời, câu hỏi thậm chí không có ý nghĩa cho đến khi bạn gọi foo (và thậm chí sau đó, không cho đến khi dòng y = x + 27 được thực hiện).

Và thậm chí sau đó không chỉ có y có thể không có giá trị tại thời điểm này, có thể có bất kỳ số nào của các hành vi "đang bay" foo. Có thể có các chuỗi thực hiện foo hoặc foo có thể đệ quy (có thể gián tiếp) để có nhiều cuộc gọi đang diễn ra ngay cả trong một ngăn xếp cuộc gọi. Hoặc foo có thể là máy phát điện, vì vậy có thể có nhiều chuyến bay thực hiện foo trên chuyến bay ngay cả khi không có đệ quy (tức làchúng không phải tất cả đều có thể truy cập từ một số phạm vi ngoài cùng của foo). Vì vậy, mà y bạn sẽ nhận được giá trị của?

Giá trị y trong foo không phải là khái niệm được xác định rõ ràng trừ khi bạn đang nói về trong phạm vi foo.


Với sự linh hoạt của Python, tôi khá chắc chắn rằng nó có thể làm ngăn xếp khung mẫn và tìm thấy một stack frame cho foo khi có một hiện đang sống và kéo ra các giá trị của các biến cục bộ của nó lúc bấy giờ. Điều này sẽ là khá khó khăn (nếu không phải là không thể) để làm với một trang trí, bởi vì (trừ khi foo là một máy phát điện) trang trí chỉ có thể thêm mã wrapper "xung quanh" foo, có nghĩa là mã điều khiển bởi trang trí chạy trước và sau foo chạy , vì vậy bạn chỉ có quyền kiểm soát khi khung ngăn xếp của foo không tồn tại.

Tôi sẽ không cung cấp cho con trỏ cụ thể về chính xác cách thực hiện việc này, bởi vì tôi không biết cách thực hiện. Nghe có vẻ như nó gần như chắc chắn là một ý tưởng tồi mặc dù, trừ khi bạn đang viết một trình gỡ lỗi.

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