我有一个名为A
的课程:
>>> class A:
def __init__(self):
self.register = {}
>>>
班级A
将由班级B
进行细分。但是,类B
包含需要在类name: function
字典的实例中注册为A
对的方法。这样,类A
可以使用这些方法工作。
这是我的意思的一个例子:
>>> class B(A):
def foo(self):
pass
def bar(self):
pass
>>> b = B()
>>> b.register # foo and bar were registered
{'key': <foo function>, 'key2': <bar function>}
>>>
有解决这个问题的惯用方法吗?或者这样的事情是不可能的,最好改变我的代码结构。
请注意,这不是Auto-register class methods using decorator的副本,因为我的寄存器不是全局的,它是类的实例变量。这意味着使用所选答案中显示的元类将无效。
答案 0 :(得分:2)
如果我理解正确的话,我认为您在帖子中提到的this question链接确实可用于解决您的问题。
您尝试注册的信息是全球信息。虽然您希望每个实例都有一个包含此全局信息的寄存器,但您真正需要做的就是将__init__
复制全局寄存器到实例寄存器中。
答案 1 :(得分:1)
如果您要声明所需的所有类,并且在此之后担心 instance 寄存器对所有子类中的所有声明的方法都有引用,您只需要执行&#34; register&#34;声明子类本身时的信息。使用新的__init_subclass__
mechanism在Python 3.6(但不是3.5)中很容易做到这一点。在Python 3.5中,在此之前,使用元类更容易执行。
class FallbackDict(dict):
def __init__(self, fallback):
self.fallback = fallback
def __missing__(self, key):
value = self.fallback[key]
self[key] = value
return value
class A:
register = {}
def __init__(self):
# instance register shadows global register
# for access via "self."
self.register = FallbackDict(__class__.register)
def __init_subclass__(cls):
for attrname, value in cls.__dict__.items():
if callable(value):
__class__.register[attrname] = value
这里的代码很简单 - 自定义dict类将&#34;复制读取&#34; A.regiser字典的值到实例字典中。如果您需要包含此行为的更一致的字典(例如,正确迭代其自身和后备字典的键,值和项目的字典),您可以更好地实现&#34; FallbackDict&#34; class作为collections.abc.MutableMapping的实例(而只是使用聚合字典来实际保存数据)
如果您计划在创建&#34; A&#34;的任何实例之前创建所有注册新方法的类,则根本不需要自定义dict。 - 或者如果新创建的类不必更新现有实例 - 但在这种情况下,您应该将A.register复制到实例&#34; self.register&#34;在__init__
内。
如果您无法更改为Python 3.6,您还需要一个自定义元类来触发上面的__init_subclass__
方法。保持原样,以便您的代码可以移动到Python 3.6并消除元类,并添加类似于以下内容的元类:
class MetaA(type):
def __init__(cls, name, bases, namespace):
super().__init__(name, bases, namespace)
cls.__init_subclass__()
class A:
...
@clasmethod
def __init_subclass__(cls):
# as above
...