我有一个基类,有两个从其派生的类。我希望基类的方法表现不同,这取决于参数是与派生类属于同一类型,还是仅是基类的实例但具有不同的类型。这是当前的实现:
class MyBase:
def __init__(self, foo: int):
self.foo = foo
def __eq__(self, other):
return self.foo == other.foo
class MyDerived_1(MyBase):
def __init__(self, foo: int, bar: int):
super().__init__(foo)
self.bar = bar
class MyDerived_2(MyBase):
def __init__(self, foo: int, bar: int):
super().__init__(foo)
self.bar = bar
def __eq__(self, other):
if type(other) == type(self):
return self.bar == other.bar
elif isinstance(other, MyBase):
return super().__eq__(other)
else:
return False
在最后第四行中,我必须显式引用MyBase。也许这很好,但我的理解是,“ super”关键字的要点是它应允许您更改基类,而不必重新编写该类中的任何内容。所以此解决方案的潜在问题是,如果更改MyBase,则 init 会很好,因为它称为“ super”,但 eq 不会更新其行为。
因此,我尝试用“ type(super)”或“ type(super())”替换“ MyBase”,但是它们没有引用父类,而是引用了对象“ super”的类。
请注意,此问题与以下内容不同:
Get parent class name? Get defining class of unbound method object in Python 3 等
因为一旦对象被初始化,他们就在寻找父类。
我想我应该可以通过运行MRO来找到超类。但是,鉴于我不是要查找整个继承树,而是只想知道超类的类型,所以这似乎是一个糟糕的解决方案。
有没有办法将这些信息从“超级”中拉出来?
答案 0 :(得分:1)
首先,当遇到不支持的类型时,您想从NotImplemented
返回__eq__
,以便Python也可以使第二个操作数有机会参与相等性测试。来自Python datamodel documenation:
数值方法和丰富比较方法如果未实现所提供操作数的操作,则应返回此值。 (然后,取决于操作员,解释器将尝试执行反射操作或其他一些后备操作。)
当super().__eq__()
不是相同类型的实例时,您的代码实际上应该仅委托给other
,在这里无需测试基本类型;基类应该已经在测试正确的类型或协议。
接下来,您可以使用Python 3 __class__
closure访问在其上定义方法的类;每当您在嵌套在类定义内的函数定义中使用super()
或__class__
时,Python都会添加此闭包:
class MyBase:
# ...
def __eq__(self, other):
if not isinstance(other, __class__):
# we can't handle the other type, inform Python
return NotImplemented
return self.foo == other.foo
class MyDerived_2(MyBase):
# ...
def __eq__(self, other):
if isinstance(other, __class__):
# if other is an instance of MyDerived_2, only test for 'bar'
return self.bar == other.bar
# otherwise fall back to the base behaviour
return super().__eq__(other)
请注意,我使用的是isinstance()
而不是type()
测试,您希望MyDerived_2
的子类继承此行为。
除了测试特定的类层次结构之外,您还可以依赖鸭子类型。如果另一个对象具有正确的属性名称,则只需假设它可以与以下对象进行比较即可:
class MyBase:
# ...
def __eq__(self, other):
try:
self.foo == other.foo
except AttributeError:
# we can't handle the other type, inform Python
return NotImplemented
class MyDerived_2(MyBase):
# ...
def __eq__(self, other):
try:
self.bar == other.bar
except AttributeError:
# otherwise fall back to the base behaviour
return super().__eq__(other)
答案 1 :(得分:0)
我认为您可能需要使用inspect
模块,并且它是getclasstree()
函数:https://docs.python.org/3/library/inspect.html#inspect.getclasstree
class MyDerived_2(MyBase):
def mytree(self):
print(inspect.getclasstree([self.__class__]))
c = MyDerived_2(1, 2)
c.mytree()
此输出:
[(<class '__main__.MyBase'>, (<class 'object'>,)), [(<class '__main__.MyDerived_2'>, (<class '__main__.MyBase'>,))]]