Tôi đang cố gắng tìm ra cách để có được tên của tất cả các trang trí trên một phương pháp. Tôi đã có thể nhận được tên phương thức và docstring, nhưng không thể tìm ra cách để có được một danh sách các trang trí.Introspection để có được tên trang trí trên một phương pháp?
Trả lời
Nếu bạn có thể thay đổi cách bạn gọi trang trí từ
class Foo(object):
@many
@decorators
@here
def bar(self):
pass
để
class Foo(object):
@register(many,decos,here)
def bar(self):
pass
sau đó bạn có thể đăng ký trang trí theo cách này:
def register(*decorators):
def register_wrapper(func):
for deco in decorators[::-1]:
func=deco(func)
func._decorators=decorators
return func
return register_wrapper
Ví dụ:
def many(f):
def wrapper(*args,**kwds):
return f(*args,**kwds)
return wrapper
decos = here = many
class Foo(object):
@register(many,decos,here)
def bar(self):
pass
foo=Foo()
Ở đây chúng ta truy cập vào tuple của trang trí:
print(foo.bar._decorators)
# (<function many at 0xb76d9d14>, <function decos at 0xb76d9d4c>, <function here at 0xb76d9d84>)
Ở đây chúng ta in chỉ là tên của các trang trí:
print([d.func_name for d in foo.bar._decorators])
# ['many', 'decos', 'here']
Đây là một giải pháp tuyệt vời. : D Giả sử bạn có quyền truy cập vào mã chỉ định trang trí, mặc dù ... – Faisal
Ok điều này có thể hoạt động, nhưng tại sao tôi không thể thêm mã func._whatever = 'something' vào trang trí hiện có của tôi và kiểm tra cho giá trị của thuộc tính _whatever khi thực hiện nội suy trên phương thức? – Tony
Bạn có thể, nhưng sau đó bạn sẽ phải bẩn mỗi trang trí bạn viết với mối quan tâm chéo cắt bỏ các bài hát của nó đằng sau trong chức năng nó sửa đổi. – Faisal
Điều đó là không thể theo ý kiến của tôi. Trình trang trí không phải là một loại thuộc tính hoặc dữ liệu meta của một phương thức. Trình trang trí là một cú pháp thuận tiện để thay thế một hàm bằng kết quả của một cuộc gọi hàm. Xem http://docs.python.org/whatsnew/2.4.html?highlight=decorators#pep-318-decorators-for-functions-and-methods để biết thêm chi tiết.
Nó là không thể làm một cách tổng quát, bởi vì
@foo
def bar ...
là chính xác giống như
def bar ...
bar = foo (bar)
Bạn có thể làm điều đó trong một số trường hợp đặc biệt, như lẽ @staticmethod
bằng cách phân tích đối tượng chức năng , nhưng không tốt hơn thế.
Đó là bởi vì trang trí là "đường cú pháp". Giả sử bạn có các trang trí sau:
def MyDecorator(func):
def transformed(*args):
print "Calling func " + func.__name__
func()
return transformed
Và bạn áp dụng nó cho một hàm:
@MyDecorator
def thisFunction():
print "Hello!"
này tương đương với:
thisFunction = MyDecorator(thisFunction)
Bạn có thể nhúng một "lịch sử" vào đối tượng chức năng, có lẽ, nếu bạn kiểm soát các trang trí. Tôi đặt cược có một số cách thông minh khác để làm điều này (có lẽ bằng cách gán trọng), nhưng tôi không phải là thạo trong Python không may. :(
Như Faisal notes, bạn có thể có những trang trí tự đính kèm siêu dữ liệu với chức năng, nhưng theo tôi biết nó không phải là thực hiện tự động.
Bạn không có thể, theo định nghĩa.Decorator:
@dec
def foo():
return 1
chỉ là phím tắt cho:
def foo_internal()
return 1
foo = dec(foo_internal)
Chú ý rằng, trang trí dec
chỉ đơn giản là một số điều gì đó có thể được gọi trở lại (chức năng, có thể một số đối tượng có thể được gọi khác). Bạn thậm chí không biết nếu foo
có bất cứ điều gì để làm với nét trang trí, ví dụ:
def dec(f):
def not_foo():
return 0
return not_foo
Nếu bạn cần phải đặt thêm một số thông tin về phương pháp, các lớp học vv .--- như ví dụ thuộc tính trong .NET --- chỉ cần đặt một số thuộc tính trên chúng.
def foo()
return 1
foo.decorated = True
Hoặc triển khai trang trí đặt các thuộc tính đó, nếu nó thực sự giúp dễ đọc.
def dec(f):
f.decorated = True
return f
Vâng. Python là mã nguồn mở. Bạn luôn có thể mở rộng trình thông dịch Python để theo dõi các trang trí được áp dụng cho đối tượng. Vì đối tượng trang trí (như được hiển thị ở trên) không phải liên quan đến bất kỳ cách nào để trang trí đối tượng, việc triển khai này sẽ phải lưu trữ thông tin từ đối tượng được trang trí trước khi áp dụng trang trí, áp dụng trang trí, thay thế thông tin trang trí trên đối tượng được trả lại và thêm thông tin về trang trí cuối cùng.
Có thể thực hiện. Nhưng tôi không chắc nó có thực sự hữu ích hay không. Và nó thêm một số chi phí cho mỗi trang trí. Vì vậy, tôi sẽ không mong đợi cơ chế như vậy trong Python chính thống, trừ khi nó cung cấp một số lợi ích khác, như đơn giản hóa việc thực hiện trang trí, v.v.
"Bạn không thể, theo định nghĩa" có vẻ như một câu trả lời sai 100%, cho rằng Jaymon đã đăng cách thực hiện nó với gói phản ánh tiêu chuẩn ('kiểm tra nhập khẩu') ở trên. http://stackoverflow.com/a/31197273/1424877 Tôi đề nghị xóa câu trả lời này ... trừ khi tôi đang thiếu một cái gì đó tinh tế. – Quuxplusone
Bạn không thể, nhưng thậm chí tệ hơn là có thư viện để giúp che giấu thực tế là bạn có trang trí một chức năng để bắt đầu. Xem Functools hoặc thư viện trang trí (@decorator
nếu tôi có thể tìm thấy nó) để biết thêm thông tin.
Tôi ngạc nhiên rằng câu hỏi này là quá cũ và không ai đã dành thời gian để thêm cách thực tế nội tâm để làm điều này, vì vậy ở đây là:
Mã bạn muốn kiểm tra ...
def template(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
baz = template
che = template
class Foo(object):
@baz
@che
def bar(self):
pass
Bây giờ bạn có thể kiểm tra lớp trên Foo
với một cái gì đó như thế này ...
import ast
import inspect
def get_decorators(cls):
target = cls
decorators = {}
def visit_FunctionDef(node):
decorators[node.name] = []
for n in node.decorator_list:
name = ''
if isinstance(n, ast.Call):
name = n.func.attr if isinstance(n.func, ast.Attribute) else n.func.id
else:
name = n.attr if isinstance(n, ast.Attribute) else n.id
decorators[node.name].append(name)
node_iter = ast.NodeVisitor()
node_iter.visit_FunctionDef = visit_FunctionDef
node_iter.visit(ast.parse(inspect.getsource(target)))
return decorators
print get_decorators(Foo)
điều đó sẽ in một cái gì đó như thế này ...
{'bar': ['baz', 'che']}
hoặc ít nhất nó đã làm khi tôi thử nghiệm này với Python 2.7.9 thật nhanh :)
Được rồi, điều này có vấn đề trong python 3: (ít nhất nó có vẻ như, và tôi chắc chắn rằng tôi không * người tốt nhất với kiến thức về kiểm tra/ast để bình luận với mức độ chắc chắn); về cơ bản tôi có một mã từ những gì bạn có ở trên, và 'inspect.getsource()' dường như trở lại với các khoảng trống ở phía trước 'def wrapper', sau đó đưa ra một lỗi thụt lề không mong muốn trên cuộc gọi' ast.parse' . – Jmons
* CSONG * khi tôi cố gắng chứng minh điều này bằng cách sử dụng các công cụ chạy kịch bản trực tuyến hte (mà tôi nghĩ kịch bản thay vì chạy từ tệp), tôi nhận được 'OSError: mã nguồn không có sẵn' vì vậy tôi nghi ngờ có trường hợp (có lẽ bin chạy), nơi quá trình này sẽ không hoạt động. Có lẽ nó sẽ không hoạt động khi bin-chỉ chạy python tồn tại? – Jmons
Phiên bản python3 nào? Tôi chỉ thử nghiệm nó trong python 2.7.13 và python 3.6.4 (đó là các phiên bản tôi có trên máy tính của tôi) và cả hai đều làm việc tốt. Ngoài ra, tôi không chắc chắn điều này sẽ làm việc ở khắp mọi nơi, nhưng nó làm việc ở khắp mọi nơi tôi đã cần nó. Tôi chắc chắn có thể thấy kịch bản chạy trực tuyến có bảo vệ cho các mô-đun như ast và kiểm tra, và có lẽ những thứ khác như mở tệp, vì nó là, theo định nghĩa, một môi trường có nhiều hơn. – Jaymon
- 1. Introspection trên pygtk3 có thể?
- 2. Trang trí một phương pháp đã là một classmethod?
- 3. Làm thế nào tôi có thể bước vào một phương pháp được trang trí với DebuggerStepThroughAttribute?
- 4. Giảm boilerplate khi trang trí phương pháp
- 5. Trang trí và phương pháp python
- 6. Làm thế nào để khẳng định rằng một phương pháp được trang trí với python unittest?
- 7. Phương pháp có thể là một trang trí của một phương pháp khác của cùng một lớp không?
- 8. Phương pháp Java bị thiếu (ala Ruby) để trang trí?
- 9. Mẫu trang trí với các phương pháp trang trí cụ thể trong Java
- 10. Làm thế nào để trang trí một phương pháp bên trong một lớp học?
- 11. Viết một trang trí lớp học mà áp dụng một trang trí cho tất cả các phương pháp
- 12. Lấy tên của một chức năng được trang trí?
- 13. Python: staticmethod trang trí recives phương pháp không thể gọi
- 14. Python Phương pháp Định nghĩa Sử dụng trang trí
- 15. Làm thế nào để trang trí các phương pháp Objective C với tài liệu?
- 16. phương pháp đường ray để có được tên liên kết của một mô hình
- 17. Làm thế nào để có được (sub) tên lớp từ một phương pháp tĩnh trong Python?
- 18. Làm thế nào để undecorate tên từ tên trang trí?
- 19. Áp dụng trang trí python với các phương pháp trong một lớp học
- 20. phương pháp tĩnh mà không có một tên
- 21. Có phải tên C++ mangling (trang trí) xác định?
- 22. Hai phương pháp chung có cùng tên
- 23. Làm cách nào để thực hiện Introspection trên một đối tượng trong Python 2.x?
- 24. thêm phương thức vào một lớp động với trang trí
- 25. Cách tốt hơn để có được trang Tên
- 26. Nhận tất cả các phương pháp được trang trí bằng một thuộc tính cụ thể sử dụng T4/EnvDTE
- 27. Làm cách nào để tiêm/tạo mã ống nước vào các phương pháp được trang trí với Thuộc tính?
- 28. Introspection ở Clojure
- 29. Phương thức mở rộng - Mẫu trang trí
- 30. Tại sao một phương pháp ClassInitialize được trang trí làm cho tất cả các thử nghiệm của tôi thất bại?
Điều này có vẻ không cần thiết. Bạn có nguồn. Có gì sai khi đọc nguồn? –
@ S.Lott: bạn không thể trả lời cùng một cách về bất kỳ câu hỏi nào liên quan đến nội tâm? Tuy nhiên, nội tâm là hữu ích. –
@ S.Lott: Không có gì sai khi đọc nguồn, giống như không có gì sai khi đọc nội dung của cơ sở dữ liệu trực tiếp thay vì sử dụng khung nhìn hoặc kịch bản, trừ khi tôi muốn tự động hóa. Tôi sử dụng trang trí để xác thực và tôi tạo báo cáo với các chế độ xem khác nhau để hiển thị những nhóm người dùng nào có quyền truy cập vào tài nguyên nào. Vì vậy, tôi cần truy cập có lập trình vào nguồn, giống như tôi cần truy cập có lập trình vào nguồn dữ liệu. – Tony