Python 从父类控制子类方法
假设我有以下代码:Python 从父类控制子类方法,python,class,python-2.7,parent-child,Python,Class,Python 2.7,Parent Child,假设我有以下代码: class Foo: def write(self, s=""): # Make sure that overwritten # 'write' method in child class # does what it's specified, and # then what comes next... print "-From Foo" class Bar(Foo): de
class Foo:
def write(self, s=""):
# Make sure that overwritten
# 'write' method in child class
# does what it's specified, and
# then what comes next...
print "-From Foo"
class Bar(Foo):
def write(self, s=""):
print s
baz = Bar()
baz.write("Hello, World!")
最后一个调用显然会自动输出hello world。我还需要让它编写“-From Foo”,但不修改Bar类,只修改Foo类。我尝试过使用\uuu base\uuuu
和其他东西,但它对我的目的无效。如果不修改Bar()
,没有(好的)方法可以做到这一点-您想做的是在Bar()
内部使用super()
,这将允许您调用父方法
如果您使用的是一个不能修改的类,而这个类不能做到这一点,那么最好的解决方案是使用一个不太好的类来创建一个包装类,手动完成您想要的任务。例如:
class BarWrapper(Foo):
def __init__(self, *args, **kwargs):
self.bar = Bar(*args, **kwargs)
def write(self, *args, **kwargs):
super(BarWrapper, self).write(*args, **kwargs)
self.bar.write(*args, **kwargs)
(当然,根据类的大小,还需要更多,注意在3.x中,您可以通过删除参数来使用
super()
的更简单语法。)我100%同意Lattyware:您不应该这样做。父类不应该“知道”子类或它们是如何工作的
但我必须说,使用一些\uuu getattribute\uuu
魔法是可能的:
class Foo(object):
def __getattribute__(self, attr):
if attr != 'write':
return super(Foo, self).__getattribute__(attr)
meth = super(Foo, self).__getattribute__(attr)
if meth.im_func is Foo.write.im_func:
# subclass does not override the method
return meth
def assure_calls_base_class(*args, **kwargs):
meth(*args, **kwargs)
Foo.write(self, *args, **kwargs)
return assure_calls_base_class
def write(self, s=""):
print "-From Foo"
class Bar(Foo):
def write(self, s=""):
print s
运行代码:
>>> b = Bar()
>>> b.write('Hello, World!')
Hello, World!
-From Foo
但是请注意,这只是一种黑客行为,如果使用一点继承,或者即使您从类中访问write
,也可能会中断:
>>> Bar.write(b, 'Hello, World!') #should be equivalent to b.write('Hello, World!')
Hello, World!
这是一种使用元类魔法的方法;IMHO,它比其他方法更健壮和灵活,它还可以正确地处理无界调用(例如,
Bar.write(x,“hello”)
)和单个继承(参见下面的Baz):
控制台运行示例:
>>> class Foo(object):
... __metaclass__ = ReverserMetaclass
... def write(self, s=""):
... # Make sure that overwritten
... # 'write' method in child class
... # does what it's specified, and
... # then what comes next...
... print "Write - From Foo", s
... def read(self):
... print "Read - From Foo"
...
>>> class Bar(Foo):
... def write(self, s=""):
... print "Write - from Bar", s
... def read(self):
... print "Read - From Bar"
...
>>> class Baz(Bar):
... def write(self, s=""):
... print "Write - from Baz", s
...
>>> x = Bar()
>>> x.write("hello")
Write - From Foo hello
Write - from Bar hello
>>> Bar.read(x)
Read - From Foo
Read - From Bar
>>>
>>> x = Baz()
>>> x.read()
Read - From Foo
Read - From Bar
>>> x.write("foo")
Write - From Foo foo
Write - from Bar foo
Write - from Baz foo
Python元类功能非常强大,但正如其他人所说,您确实不想经常使用这种魔法。这里有另一种使用元类的方法。与使用
\uuu getattribute\uuu()
相比,它的一个重要优点是,访问或使用其他子类属性和方法不会产生额外的开销。如果定义了它的子类,它还支持单继承
class Foo(object):
class __metaclass__(type):
def __new__(metaclass, classname, bases, classdict):
clsobj = super(metaclass, metaclass).__new__(metaclass, classname,
bases, classdict)
if classname != 'Foo' and 'write' in classdict: # subclass?
def call_base_write_after(self, *args, **kwargs):
classdict['write'](self, *args, **kwargs)
Foo.write(self, *args, **kwargs)
setattr(clsobj, 'write', call_base_write_after) # replace method
return clsobj
def write(self, s=""):
print "-From Foo"
class Bar(Foo):
def write(self, s=""):
print 'Bar:', s
class Baz(Bar): # sub-subclass
def write(self, s=""):
print 'Baz:', s
Bar().write('test')
Baz().write('test')
输出:
Bar:测试
-来自富
Baz:测试
-来自富
如果希望子类write()
方法在以后调用基类的版本而不是根(Foo
)类,只需更改硬编码:
Foo.write(self, *args, **kwargs)
呼吁:
super(clsobj, self).write(*args, **kwargs)
在
Foo.\uuuu new\uuuuu()
中,如果这是Python 2.x,请确保从object继承以获得新样式的类,这些类具有更广泛的暗魔法功能。由于OP显然使用的是Python 2.x,我认为您应该用这些术语给出答案,不只是说如果最后没有修改的话,这个版本就不能用了。@martineau事实上,我并没有检查OP使用的是什么版本,编辑。也是+1,因为它符合OP的要求,并提到了一些注意事项……尽管它忽略了这样一个事实,即它在某种程度上减慢了对条
对象属性/方法的访问速度。我认为这是“要走的路”(如果我们想按照OP的要求去做),但是对我来说,\uuu getattribute\uuuu
比元类更容易理解。
super(clsobj, self).write(*args, **kwargs)