我想自动向Python子类添加方法(更具体地说:方法别名)。如果子类定义了一个名为'get'的方法,我想在子类的字典中添加一个方法别名'GET'。
不重复自己我想在基类中定义这个修改例程。但是如果我检查基类__init__
方法,则没有这样的方法,因为它是在子类中定义的。一些源代码会更清楚:
class Base:
def __init__(self):
if hasattr(self, "get"):
setattr(self, "GET", self.get)
class Sub(Base):
def get():
pass
print(dir(Sub))
输出:
['__doc__', '__init__', '__module__', 'get']
它还应包含'GET'
。
有没有办法在基类中做到这一点?
答案 0 :(得分:2)
因为尚未启动类Sub,所以在其实例中执行
>>> s=Sub()
>>> dir(s)
['GET', '__doc__', '__init__', '__module__', 'get']
>>>
答案 1 :(得分:2)
您班级的__init__
方法会将绑定方法添加为您班级的实例的属性。这与将属性添加到类不完全相同。通常,方法通过将函数存储在类中作为属性,然后创建方法对象来工作,因为这些函数作为属性从类中检索(创建仅知道它们所属的类的未绑定方法)或实例(创建绑定方法,知道它们的实例。)
这与你正在做的有什么不同?好吧,您分配了特定实例的GET
实例属性,而不是类。绑定方法成为实例数据的一部分:
>>> s.__dict__
{'GET': <bound method Sub.get of <__main__.Sub object at 0xb70896cc>>}
请注意该方法在密钥GET
下的位置,但不在get
下。 GET
是实例属性,但get
不是。这在很多方面略有不同:该方法在类对象中不存在,因此您不能Sub.GET(instance)
调用Sub
的{{1}}方法,即使你可以做GET
。其次,如果你有Sub的子类定义了自己的Sub.get(instance)
方法而不是它自己的GET
方法,那么实例属性将隐藏子类{{1使用来自基类的绑定get
方法的方法。第三,它在绑定方法和实例之间创建循环引用:bound方法具有对实例的引用,实例现在存储对绑定方法的引用。通常绑定的方法不会部分地存储在实例上以避免这种情况。循环引用通常不是一个大问题,因为我们现在有了循环gc模块(GET
)来处理它们,但它不能总是清理引用循环(例如,当你的类也有一个get
方法。)最后,存储绑定的方法对象通常会使您的实例不可序列化:大多数序列化程序(如gc
)无法处理绑定的方法。
您可能不关心这些问题,但如果您这样做,那么您可以采用更好的方法来处理您的问题:元类。您可以在创建实例时将绑定方法分配给实例属性,而不是在创建类时将常规函数分配给类属性:
__del__
现在,pickle
和class MethodAliasingType(type):
def __init__(self, name, bases, attrs):
# attrs is the dict of attributes that was used to create the
# class 'self', modifying it has no effect on the class.
# So use setattr() to set the attribute.
for k, v in attrs.iteritems():
if not hasattr(self, k.upper()):
setattr(self, k.upper(), v)
super(MethodAliasingType, self).__init__(name, bases, attrs)
class Base(object):
__metaclass__ = MethodAliasingType
class Sub(Base):
def get(self):
pass
实际上是别名,并且在子类中覆盖一个而不是另一个按预期工作。
Sub.get
(当然,如果你不希望覆盖一个而不是另一个工作,你可以简单地在你的元类中犯这个错误。)你可以做同样的事情使用类装饰器的元类(在Python 2.6及更高版本中),但这意味着需要在Base的每个子类上使用类装饰器 - 类装饰器不会被继承。
答案 2 :(得分:-1)
在派生类中创建一个派生构造函数,用于设置属性。