Tôi đang cố gắng để viết một trang trí lớp học mà áp dụng một trang trí cho tất cả các lớp phương pháp: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
import inspect
def decorate_func(func):
def wrapper(*args, **kwargs):
print "before"
ret = func(*args, **kwargs)
print "after"
return ret
for attr in "__module__", "__name__", "__doc__":
setattr(wrapper, attr, getattr(func, attr))
return wrapper
def decorate_class(cls):
for name, meth in inspect.getmembers(cls, inspect.ismethod):
setattr(cls, name, decorate_func(meth))
return cls
@decorate_class
class MyClass(object):
def __init__(self):
self.a = 10
print "__init__"
def foo(self):
print self.a
@staticmethod
def baz():
print "baz"
@classmethod
def bar(cls):
print "bar"
obj = MyClass()
obj.foo()
obj.baz()
MyClass.baz()
obj.bar()
MyClass.bar()
Nó gần như làm việc, nhưng @classmethod
S cần một điều trị đặc biệt:
$ python test.py
before
__init__
after
before
10
after
baz
baz
before
Traceback (most recent call last):
File "test.py", line 44, in <module>
obj.bar()
File "test.py", line 7, in wrapper
ret = func(*args, **kwargs)
TypeError: bar() takes exactly 1 argument (2 given)
Có cách nào xử lý vấn đề này một cách độc đáo không? Tôi đã kiểm tra @classmethod
các phương pháp trang trí, nhưng tôi không thấy bất kỳ điều gì để phân biệt chúng với các loại phương pháp khác.
Cập nhật
Đây là giải pháp hoàn chỉnh cho các hồ sơ (sử dụng mô tả để xử lý @staticmethod
S và @classmethod
S độc đáo, và lừa aix để phát hiện @classmethod
S VS phương pháp bình thường):
import inspect
class DecoratedMethod(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, cls=None):
def wrapper(*args, **kwargs):
print "before"
ret = self.func(obj, *args, **kwargs)
print "after"
return ret
for attr in "__module__", "__name__", "__doc__":
setattr(wrapper, attr, getattr(self.func, attr))
return wrapper
class DecoratedClassMethod(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, cls=None):
def wrapper(*args, **kwargs):
print "before"
ret = self.func(*args, **kwargs)
print "after"
return ret
for attr in "__module__", "__name__", "__doc__":
setattr(wrapper, attr, getattr(self.func, attr))
return wrapper
def decorate_class(cls):
for name, meth in inspect.getmembers(cls):
if inspect.ismethod(meth):
if inspect.isclass(meth.im_self):
# meth is a classmethod
setattr(cls, name, DecoratedClassMethod(meth))
else:
# meth is a regular method
setattr(cls, name, DecoratedMethod(meth))
elif inspect.isfunction(meth):
# meth is a staticmethod
setattr(cls, name, DecoratedClassMethod(meth))
return cls
@decorate_class
class MyClass(object):
def __init__(self):
self.a = 10
print "__init__"
def foo(self):
print self.a
@staticmethod
def baz():
print "baz"
@classmethod
def bar(cls):
print "bar"
obj = MyClass()
obj.foo()
obj.baz()
MyClass.baz()
obj.bar()
MyClass.bar()
lớp DecorativeClassMethod và DecorativeMethod của bạn giống hệt nhau. chỉnh sửa để đặt một giải pháp chính xác xin vui lòng. –
Chúng khác nhau: DecorativeMethod vượt qua đối tượng đối tượng trong khi DecorativeClassMethod thì không. –
Chúng tương tự nhau nên phải kết hợp chúng để tránh trùng lặp. Hãy suy nghĩ dọc theo dòng 'self.func (cls hoặc obj, * args, ** kwargs)'. Tôi biết điều đó không giống nhau nhưng một tuyên bố 'if' đơn giản với bài kiểm tra đúng sẽ cuối cùng giúp bạn tránh khỏi việc có hai lớp gần như giống hệt nhau này. – robru