2010-08-14 34 views
5

Tính đến 2,4 (2,6 cho các lớp học), python cho phép bạn để trang trí một chức năng với chức năng khác:__decorated__ cho trang trí python

def d(func): return func 

@d 
def test(first): pass 

Đó là một cú pháp đường thuận tiện. Bạn có thể làm tất cả những thứ gọn gàng với trang trí mà không làm lộn xộn. Tuy nhiên, nếu bạn muốn tìm ra các chức năng ban đầu đã được trang trí, bạn phải nhảy qua hoops (như Cls.method.__func__.__closure__[0].cell_contents hoặc tệ hơn).

Tôi thấy mình muốn có một cách tốt hơn và nhận thấy rằng đã có một số thảo luận về python-dev về việc thêm một biến gọi là __decorated__ vào hàm [mới] được trả về bởi trang trí. Tuy nhiên, có vẻ như không đi đâu cả.

Là một người phiêu lưu, và đã có kinh nghiệm trăn khá nặng trong khoảng 4 năm, tôi nghĩ tôi sẽ xem xét triển khai __decorated__ trong nguồn trình biên dịch python, chỉ để xem nó như thế nào.

Thành thật mà nói tôi chưa bao giờ đi sâu vào bên dưới mui xe, vì vậy giờ đầu tiên của tôi chỉ là cố gắng hiểu được cách mã C hoạt động. Vì vậy, trước tiên, những gì sẽ là nguồn lực tốt nhất để có được đầu của tôi xung quanh những gì tôi sẽ phải thay đổi/thêm cho __decorator__?

Thứ hai, nếu người trang trí trả về hàm mới thì __decorated__ sẽ chỉ trả lại hàm ban đầu, được trang trí. Tuy nhiên, nếu người trang trí trả về hàm ban đầu, điều gì sẽ xảy ra? Dưới đây là ba tùy chọn tôi có thể nghĩ đến (thứ ba là yêu thích của tôi):

  1. Không thêm __decorator__.
  2. Thêm __decorator__ nhưng đặt thành Không.
  3. Thêm __decorator__ và đặt nó vào chức năng ban đầu.

Vì vậy, nếu điều đó xảy ra, bạn nghĩ điều gì sẽ là lựa chọn tốt nhất?

UPDATE:

Một người nào khác brought to my attention một kịch bản mà tôi đã bỏ lỡ. Điều gì sẽ xảy ra khi người trang trí trả về không phải chức năng gốc cũng như một hàm kết thúc tốt đẹp bản gốc? Tại thời điểm đó không có gì là giữ một tham chiếu đến chức năng ban đầu và nó sẽ nhận được rác thu thập được. (Cảm ơn Oddthinking!)

Vì vậy, trong trường hợp đó, tôi nghĩ rằng tôi vẫn sẽ đi với tùy chọn thứ ba. Đối tượng được trả về bởi người trang trí sẽ có được một tên __decorated__ tham chiếu đến hàm ban đầu. Điều này có nghĩa là nó sẽ không được thu gom rác.

Có vẻ lạ đối với tôi rằng hàm từ định nghĩa lớp sẽ biến mất hoàn toàn bởi vì bạn đã trang trí nó. Trong tâm trí của tôi thậm chí còn nhiều lý do hơn để có một thuộc tính __decorated__ được áp dụng cho mọi người trang trí. Tuy nhiên, có nhiều khả năng là trực giác của tôi bị lỗi và hành vi hiện tại là điều mà hầu hết mọi người mong đợi. Bất kỳ suy nghĩ nào?

p.s. đây là phần mở rộng của một tổng quan trước đó, tổng quát hơn question tôi đã có. Tôi cũng đã đi để biết thêm thông tin về phần đầu tiên với một bài viết separate.

+0

để bạn suy nghĩ về bước tiếp theo, tức là, chức năng trang trí sẽ thông báo rằng nó được trang trí như thế nào? http://stackoverflow.com/questions/3109289/how-can-python-function-access-its-own-attributes :) – mykhal

+0

Cách này hoạt động với '@ property'? Như trong, trang trí không phải trả lại chức năng nào cả. – habnabit

+0

@Aaron, tôi cho rằng bạn sẽ thêm '__decorated__' vào bất kỳ thứ gì được trả về, chức năng hay không. –

Trả lời

2

Vâng, không phụ thuộc vào bất kỳ cuộc thảo luận về việc liệu đây là một ý tưởng tốt, tôi 'd đi cho tùy chọn # 3 vì nó nhất quán nhất: nó luôn cho thấy hàm được trang trí bởi sự hiện diện của thuộc tính và truy cập giá trị của thuộc tính luôn trả về hàm, do đó bạn không phải kiểm tra chống lại None.

Bạn cũng nên cân nhắc điều này: mặc dù: bạn sẽ đề xuất gì về trang trí thủ công? ví dụ.

def test(first): pass 
test = d(test) 

Về phần đầu tiên của câu hỏi, tôi đã không nhìn vào mã nguồn thông dịch Python rất nhiều vì vậy tôi sẽ không thể chỉ cho bạn bất cứ điều gì đặc biệt hữu ích.

+0

Điểm tốt về trang trí thủ công. –

+0

Tôi nghĩ bạn sẽ phải thêm thuộc tính '__decorated__' theo cách thủ công vào hàm mới, điều này thậm chí còn xấu hơn. –

1

tôi cảm thấy tự do để sử dụng một số đơn nhấn "private" thuộc tính như _mydecor

thể giải pháp đa trang trí:

def decorate(decoration): 
    def do_decor(func): 
     if hasattr(func, '_mydecor'): 
      func._mydecor.add(decoration) 
     else: 
      func._mydecor = set([decoration]) 
     return func 
    return do_decor 

def isDecorated(func, decoration): 
    return (decoration in getattr(func, '_mydecor', set())) 

@decorate('red') 
@decorate('green') 
def orangefunc(): pass 

print isDecorated(orangefunc, 'green') # -> True 
print isDecorated(orangefunc, 'blue') # -> False 
+0

Điều đó hoạt động tốt nếu bạn kiểm soát trang trí. Tôi cho rằng bạn có thể bọc trang trí để thực hiện điều này khi bạn không kiểm soát nó. –

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