如何重写顶级类的属性定义的内部类方法

0 投票
3 回答
1964 浏览
提问于 2025-04-15 21:56

我有一段代码如下:

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 个回答

0

每当你访问A的'b'属性时,A的实例会被传递给这个属性的获取器(getter),然后这个实例又作为参数传递给b的构造函数。这一过程从一开始就让你的构造变得不对劲,因为b的(默认)构造函数并不接受额外的参数。

看起来你的C类之所以不工作,是因为它内部的'b'类是从A的'b'属性对象继承而来的。

我很好奇你为什么在这里需要一个属性——它只会让事情变得复杂。实际上,去掉这个属性会让你可以在每个实例中替换A的内部'b'类,而不需要使用继承。你能给我们更多的信息吗,比如这个构造的意图和目的是什么?

1

这个问题失败的原因是因为在 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()
1

我不太明白为什么要把内部类定义为外部类的一个属性。(我不是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"

撰写回答