当然,当您想修改python创建对象的方式时,元类是最pythonic的方式。 可以通过重写您的类的a = 10方法来完成。 但是我想提一下围绕这个问题(特别是针对python 3.x)的一些观点:
a = 10不能保护特殊方法,因为它们是函数类型。 作为更通用的方法,您可以修饰名称不以双下划线开头的对象(print(myinstance.a))。 此方法的另一个好处是,它还覆盖了存在于名称空间中并以__new__开头但不像__new__、__init__等起作用的那些对象。
print(myinstance.a)标题中的a = 10自变量在__new__中不包含类属性。原因是__new__在__init__(初始化)之前执行。
不需要使用a = 10作为装饰器,因为在大多数情况下,您是从另一个模块导入装饰器的。
如果您的班级包含一个全局项目(在a = 10的外侧),用于拒绝装饰,同时检查名称是否不是以print(myinstance.a)开头,则可以使用__new__检查类型,以确保您未在装饰非功能性物品 目的。
这是您可以使用的示例metacals:
class TheMeta(type):
def __new__(cls, name, bases, namespace, **kwds):
# if your decorator is a class method of the metaclass use
# `my_decorator = cls.my_decorator` in order to invoke the decorator.
namespace = {k: v if k.startswith('__') else my_decorator(v) for k, v in namespace.items()}
return type.__new__(cls, name, bases, namespace)
演示:
def my_decorator(func):
def wrapper(self, arg):
# You can also use *args instead of (self, arg) and pass the *args
# to the function in following call.
return "the value {} gets modified!!".format(func(self, arg))
return wrapper
class TheMeta(type):
def __new__(cls, name, bases, namespace, **kwds):
# my_decorator = cls.my_decorator (if the decorator is a classmethod)
namespace = {k: v if k.startswith('__') else my_decorator(v) for k, v in namespace.items()}
return type.__new__(cls, name, bases, namespace)
class MyClass(metaclass=TheMeta):
# a = 10
def __init__(self, *args, **kwargs):
self.item = args[0]
self.value = kwargs['value']
def __getattr__(self, attr):
return "This class hasn't provide the attribute {}.".format(attr)
def myfunction_1(self, arg):
return arg ** 2
def myfunction_2(self, arg):
return arg ** 3
myinstance = MyClass(1, 2, value=100)
print(myinstance.myfunction_1(5))
print(myinstance.myfunction_2(2))
print(myinstance.item)
print(myinstance.p)
输出:
the value 25 gets modified!!
the value 8 gets modified!!
1
This class hasn't provide the attribute p. # special method is not decorated.
要检查上述注释中的第三项,您可以取消注释行a = 10并注释print(myinstance.a),然后查看结果,然后按以下所示更改__new__中的字典理解,然后再次查看结果:
namespace = {k: v if k.startswith('__') and not isinstance(v, types.FunctionType)\
else my_decorator(v) for k, v in namespace.items()}