是否可以与父 class 实例共享子 class 实例中定义的方法引用?
Is it possible to share a method reference defined in subclass insatnces with instances of the parent class?
我有一个 class 叫 A
:
>>> class A:
def __init__(self):
self.register = {}
>>>
class A
将被 class B
子class编辑。然而,class B
包含需要在 class A
字典的实例中注册为 name: function
对的方法。这样 class 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>}
>>>
有没有惯用的方法来解决这个问题?或者这样的事情是不可能的,最好改变我的代码结构。
注意这不是 的副本,因为我的寄存器不是全局的,它是 class 的一个实例变量。这意味着使用所选答案中所示的 meta-class 将不起作用。
我认为你在post中提到的link到this question确实可以用来解决你的问题,如果我理解正确的话。
您尝试注册的信息是全局信息。虽然您希望每个实例都有一个包含此全局信息的寄存器,但您真正需要做的就是让 __init__
将全局寄存器复制到实例寄存器中。
如果你将声明所有你需要的 classes,然后担心 instance 寄存器引用所有子 class 中声明的所有方法es,你只需要在声明子classes时执行一个"register"信息。这在 Python 3.6(但不是 3.5)和新的 __init_subclass__
mechanism 中很容易做到。在 Python 3.5 和之前的版本中,使用 metaclass 更容易执行。
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
这里的代码很简单 - 自定义字典 class 会将 A.regiser 字典的 "copy on read" 值放入实例字典中。如果您需要一个包含此行为的更一致的字典(例如,一个将正确迭代其自身和后备字典的键、值和项目的字典),您最好实现 "FallbackDict" class作为 collections.abc.MutableMapping 的一个实例(并且只使用一个聚合字典来实际保存数据)
如果您计划在创建 "A" 的任何实例之前创建所有注册新方法的 classes - 或者如果新创建 classes 不必更新现有实例 - 但在这种情况下,您应该将 A.register 复制到 __init__
.
中实例的 "self.register"
如果您不能更改为 Python 3.6,您还需要一个自定义元 class 来触发上面的 __init_subclass__
方法。保持原样,这样您的代码就可以迁移到 Python 3.6 并删除元 class,并添加一个元 class,例如:
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
...
我有一个 class 叫 A
:
>>> class A:
def __init__(self):
self.register = {}
>>>
class A
将被 class B
子class编辑。然而,class B
包含需要在 class A
字典的实例中注册为 name: function
对的方法。这样 class 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>}
>>>
有没有惯用的方法来解决这个问题?或者这样的事情是不可能的,最好改变我的代码结构。
注意这不是
我认为你在post中提到的link到this question确实可以用来解决你的问题,如果我理解正确的话。
您尝试注册的信息是全局信息。虽然您希望每个实例都有一个包含此全局信息的寄存器,但您真正需要做的就是让 __init__
将全局寄存器复制到实例寄存器中。
如果你将声明所有你需要的 classes,然后担心 instance 寄存器引用所有子 class 中声明的所有方法es,你只需要在声明子classes时执行一个"register"信息。这在 Python 3.6(但不是 3.5)和新的 __init_subclass__
mechanism 中很容易做到。在 Python 3.5 和之前的版本中,使用 metaclass 更容易执行。
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
这里的代码很简单 - 自定义字典 class 会将 A.regiser 字典的 "copy on read" 值放入实例字典中。如果您需要一个包含此行为的更一致的字典(例如,一个将正确迭代其自身和后备字典的键、值和项目的字典),您最好实现 "FallbackDict" class作为 collections.abc.MutableMapping 的一个实例(并且只使用一个聚合字典来实际保存数据)
如果您计划在创建 "A" 的任何实例之前创建所有注册新方法的 classes - 或者如果新创建 classes 不必更新现有实例 - 但在这种情况下,您应该将 A.register 复制到 __init__
.
如果您不能更改为 Python 3.6,您还需要一个自定义元 class 来触发上面的 __init_subclass__
方法。保持原样,这样您的代码就可以迁移到 Python 3.6 并删除元 class,并添加一个元 class,例如:
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
...