如何重写顶级类的属性定义的内部类方法
我有一段代码如下:
class A(object):
class b:
def print_hello(self):
print "Hello world"
b = property(b)
我想要修改里面的类 b
的行为(别担心这个小写的名字)。比如,我想添加一个新方法,或者想改一个已有的方法,像这样:
class C(A):
class b(A.b):
def print_hello(self):
print "Inner Class: Hello world"
b = property(b)
现在如果我创建 C
的对象,写成 c = C()
,然后调用 c.b
,我会遇到一个错误,提示 TypeError: 'property' object is not callable
。我该怎么做才能解决这个问题,并调用扩展后的内部类的 print_hello
方法呢?需要说明的是:我不想修改 A
类的代码。
更新:基础类 A
是为了模拟我在某个开源API中看到的一个类。所以我不想改变核心API,而是想根据自己的需求进行扩展。
3 个回答
每当你访问A的'b'属性时,A的实例会被传递给这个属性的获取器(getter),然后这个实例又作为参数传递给b的构造函数。这一过程从一开始就让你的构造变得不对劲,因为b的(默认)构造函数并不接受额外的参数。
看起来你的C类之所以不工作,是因为它内部的'b'类是从A的'b'属性对象继承而来的。
我很好奇你为什么在这里需要一个属性——它只会让事情变得复杂。实际上,去掉这个属性会让你可以在每个实例中替换A的内部'b'类,而不需要使用继承。你能给我们更多的信息吗,比如这个构造的意图和目的是什么?
这个问题失败的原因是因为在 b = property(b)
这一行,A.b 不是你定义的类,而是一个属性对象。我其实有点惊讶它在创建类的时候没有出错。如果你用 A.b.fget
作为基类,那就可以正常工作。但正确的做法是:不要这样做。Python 并没有真正意义上的内部类,在类定义的范围内定义的类和普通类没有区别。实际上,这段代码的最终结果是完全一样的:
class A(object):
pass
class b(object):
def print_hello(self):
print("Hello world")
A.b = property(b)
我不太确定你到底想要实现什么。如果我理解得没错,你有一个父类,它有一个属性返回另一个类的实例,而你想要一个子类,它的属性返回另一个类的子类的实例。要想让返回的类成为子类,你需要获取对那个类的引用,以便用它作为基类。然后你可以简单地重写这个属性,让它返回你子类的实例。如果你使用一个从实例中查找类的属性,其实你并不需要重写属性的定义:
class A(object):
class B(object):
def print_hello(self):
print("Hello from A.B")
b = property(lambda self: self.B())
class C(A):
class B(A.B):
def print_hello(self):
print("Hello from C.B")
A().b.print_hello()
C().b.print_hello()
我不太明白为什么要把内部类定义为外部类的一个属性。(我不是Python专家,所以可能有我不知道的原因。)
看起来没有这些属性也能正常工作:
class A(object):
class b:
def print_hello(self):
print "A Hello world"
class C(A):
class b(A.b):
def print_hello(self):
print "C Hello world"
outer = C()
inner = outer.b()
inner.print_hello() # prints "C Hello world"