Tôi muốn mở rộng câu trả lời được chấp nhận. Tôi muốn có khả năng có một danh sách rất dài các phương pháp trang trí được áp dụng cho một danh sách rất dài các phương pháp.
import functools
def wrap_method(cls, name, wrapper_method_name):
# This unbound method will be pulled from the superclass.
wrapped = getattr(cls, name, wrapper_method_name)
@functools.wraps(wrapped)
def wrapper(self, *args, **kwargs):
wrapper_method = getattr(self, wrapper_method_name)
return wrapper_method(wrapped.__get__(self, cls), *args, **kwargs)
return wrapper
def wrap_methods(cls):
for wrapper_method_name in cls.WRAPPER_METHOD_NAMES:
for name in cls.WRAPPED_METHODS:
setattr(cls, name, wrap_method(cls, name, wrapper_method_name))
return cls
Và đây là lớp học mà kết thúc tốt đẹp ban đầu
@wrap_methods
class WrappedConnection(BaseConnection):
"""
This class adds some quality-of-life improvements to the BaseConnection class.
-WRAPPED_METHODS are wrapped by WRAPPER_METHOD_NAMES
-wrappers can be toggled on and off.
example:
connection = WrappedConnection(show_messages=True, log_errors=False, keep_authenticated=False)
default:
connection = WrappedConnection(show_messages=False, log_errors=True, keep_authenticated=True)
"""
WRAPPER_METHOD_NAMES = ['log_errors', 'keep_authenticated', 'show_messages']
WRAPPED_METHODS = ['a_method', 'b_method', 'c_method', 'd_method']
MESSAGE_OVERRIDE_MAP = {"a_method": "a_method_message_override_attribute",
"b_method": "b_method_message_override_attribute"}
def keep_authenticated(self, method, *args, **kwargs):
"""
If the session has expired, the session is re-authenticated. The incident is logged by the default logger.
This option can be turned off by setting keep_authenticated during initialization of a WrappedConnection object.
- connection = WrappedConnection(keep_authenticated=False) # why would you ever do this
:param method: (method) method to be wrapped
:param args: (args) passed args
:param kwargs: (kwargs) passed kwargs
:return: (method) method wrapped by @keep_authenticated
"""
response, expired_session = method(*args, **kwargs), None
if response["errors"] and self._keep_authenticated:
expired_session = list(filter(lambda x: 'expired session' in x, response["errors"]))
if expired_session:
self.__init__()
logging.info('Session has been re-authenticated.')
response = method(*args, **kwargs)
return response
def log_errors(self, method, *args, **kwargs):
"""
If there is an error the incident is logged. This option can be turned off by setting log_errors
during initialization of a WrappedConnection object.
- connection = WrappedConnection(log_errors=False)
:param method: (method) method to be wrapped
:param args: (args) passed args
:param kwargs: (kwargs) passed kwargs
:return: (method) method wrapped by @log_errors
"""
response = method(*args, **kwargs)
if response["errors"] and self._log_errors:
errors = response["errors"]
logging.error(errors)
return response
def show_messages(self, method, *args, **kwargs):
"""
Shows the xml that is sent during the request. This option can be turned on by setting show_messages during
initialization of a WrappedConnection object.
- connection = WrappedConnection(show_messages=True)
:param method: (method) method to be wrapped
:param args: (args) passed args
:param kwargs: (kwargs) passed kwargs
:return: (method) method wrapped by @show_messages
"""
response = method(*args, **kwargs)
if self._show_messages:
message_override_attr = WrappedConnection.MESSAGE_OVERRIDE_MAP.get(method.__name__)
if message_override_attr:
message_override = getattr(self, message_override_attr)
print(BeautifulSoup(message_override, "xml").prettify())
else:
self._show_message(method.__name__, *args, **kwargs)
return response
def __init__(self, *args, keep_authenticated=True, log_errors=True, show_messages=False, **kwargs):
super(WrappedConnection, self).__init__(*args, **kwargs)
self._keep_authenticated = keep_authenticated
self._log_errors = log_errors
self._show_messages = show_messages
bạn không thể cấu trúc lại mã của bạn để làm 'stuff' funky trong một '@ decorator' - hoặc là có một cái gì đó tôi không' Tôi đến đây? – Kimvais
@Kimvais: Vâng nhưng sau đó làm thế nào tôi sẽ ràng buộc chức năng trang trí với một tên trở lại lớp học? Tôi sẽ kết thúc bằng '@decorator ('recv_into'): def recv_into (self): pass', phải không? –
Điểm của 'super' khi không có siêu lớp là gì? –