1、问题背景
在Python中,super方法用于在子类中调用父类的方法。Guido van Rossum曾给出了一个纯Python实现的super方法,以便更好地理解其工作原理。然而,在这个实现中,存在一个问题:当传入的对象不是要调用的父类的实例时,该实现会出错。
2、解决方案
为了解决这个问题,需要对Guido的实现进行修改。具体来说,需要在__getattr__()
方法中添加一个检查,以确保传入的对象是给定类型的实例。如果传入的对象不是给定类型的实例,那么就引发一个错误。
以下是修改后的__getattr__()
方法:
def __getattr__(self, attr):
if isinstance(self.__obj__, self.__type__):
starttype = self.__obj__.__class__
else:
# 检查传入的对象是否是给定类型的实例
if not isinstance(self.__obj__, self.__type__):
raise TypeError("obj must be an instance or subtype of type")
starttype = self.__obj__
mro = iter(starttype.__mro__)
for cls in mro:
if cls is self.__type__:
break
# Note: mro is an iterator, so the second loop
# picks up where the first one left off!
for cls in mro:
if attr in cls.__dict__:
x = cls.__dict__[attr]
if hasattr(x, "__get__"):
x = x.__get__(self.__obj__)
return x
raise AttributeError, attr
通过这个修改,就可以确保传入的对象是给定类型的实例,从而避免了错误的发生。
以下是修改后的代码示例:
class Super(object):
def __init__(self, type, obj=None):
self.__type__ = type
self.__obj__ = obj
def __get__(self, obj, type=None):
if self.__obj__ is None and obj is not None:
return Super(self.__type__, obj)
else:
return self
def __getattr__(self, attr):
# 检查传入的对象是否是给定类型的实例
if not isinstance(self.__obj__, self.__type__):
raise TypeError("obj must be an instance or subtype of type")
if isinstance(self.__obj__, self.__type__):
starttype = self.__obj__.__class__
else:
starttype = self.__obj__
mro = iter(starttype.__mro__)
for cls in mro:
if cls is self.__type__:
break
# Note: mro is an iterator, so the second loop
# picks up where the first one left off!
for cls in mro:
if attr in cls.__dict__:
x = cls.__dict__[attr]
if hasattr(x, "__get__"):
x = x.__get__(self.__obj__)
return x
raise AttributeError, attr
class A(object):
def m(self):
''' m in A'''
return "A"
class B(A):
def m(self):
''' m in B'''
return "B" + Super(B, self).m()
class C(A):
def m(self):
''' m in C '''
return "C" + Super(C, self).m()
class D(C):
def m(self):
''' m in D'''
return "D" + Super(B, self).m()
print(D().m()) # "DCBA"
现在,该代码就可以正确地运行,并且不会引发错误。