【问题标题】:Getting inherited property methods to work when wrapped inside method in child class将继承的属性方法包装在子类的方法中时工作
【发布时间】:2018-04-21 07:02:21
【问题描述】:

我试图让父类中描述的属性/设置器方法在继承到子类时工作。当我直接从父类分配调用时,我可以让它工作,如下所示。但就我而言,我需要将相同的调用包装在一个方法中,以便在调用父类之前进行一些计算。我可以通过使用 fget 方法并将对象传递给它来使其工作,但我希望前一种方法工作。

我在 StackOverflow 上查找了该问题,发现提到的一些方法涉及使用 super(),我尝试过,但没有成功。

感谢任何帮助让这个继承的属性方法在子类中工作!

class A(object):
    """ Base Class """
    def __init__(self, n):
        self.n = n
    @staticmethod
    def slices():
        def get_slices(self):
            return self.n
        def set_slices(self, n):
            self.n = n
        return property(get_slices, set_slices)

class B(A):
    def __init__(self, n):
        self.n = n
    his_slices = A.slices() # <--- works well
    def her_slices(self): # <--- does not work
        return A.slices()

if __name__ == "__main__":
    b = B(100)
    # This works
    print("%d slices" % b.his_slices)
    # 100 slices

    # This fails
    print("%d slices" % b.her_slices)
    # TypeError: %d format: a number is required, not method

    # Can be made to work like this, but I want above to work
    ss = b.her_slices()
    print("%d slices" % ss.fget(b))
    # 100 slices

【问题讨论】:

  • A.slices 下的缩进是否正确(我的意思是就像在您的代码中一样,粘贴在这里时没有更改)?如果是,那就错了。那么是定义2个实例的静态方法吗? (基于 arg 名称)方法。
  • 感谢您的快速回复!是的,这是正确的。这是一种定义属性/设置器函数的显式方式。从 his_slices 方法调用中可以看出,对该静态方法的调用有效。
  • 你的问题不清楚,至少对我来说是这样。父 A 没有属性,所以子 B 不能继承它。只有 slices 静态方法在每次调用时创建并返回一个描述符 - 实现一个属性。这没有什么意义(对我来说),因为描述符必须是类的成员才能在所有实例中都具有工作属性。但是,您的代码中并非如此。如果你不使用属性访问的内置规则,你需要自己调用 getter,创建一个代码以复杂的方式做一些琐碎的事情。
  • 您完全正确,但我正在开发一个开源项目,并且我正在尝试编写一个继承父类的子类,正如我在示例中所描述的那样。无论好坏,这就是父类的编写方式。我发现事情正因此变得令人费解。

标签: python inheritance subclass


【解决方案1】:

像对待任何其他继承一样对待它。如果您需要修改子类中常规函数的行为,您只需重新定义该函数并完全更改其内容,或者使用 super 扩展它并进一步修改它。

如果是 setter/getter,你会做同样的事情......重新定义/扩展它们。

在您的情况下,情况有些不同,因为正如其中一位评论者所指出的那样,slices 实际上是返回propertystaticmethod,而不是属性本身。因此,您确实没有可以继承和扩展的现有命名属性。

看看您在__main__ 中尝试做什么,您真正想要做的是在您的子类中创建一个名为his_slices 的新属性,并在getter 和@987654330 中适当地调用A.slices @。像这样

class A(object):
    """ Base Class """
    def __init__(self, n):
        self.n = n

    @staticmethod
    def slices():
        def get_slices(self):
            print("Get", self.n)
            return self.n

        def set_slices(self, n):
            print("Set", n)
            self.n = n

        return property(get_slices, set_slices)

class B(A):
    def __init__(self, n):
        self.n = n

    @property
    def his_slices(self):
        return A.slices().fget(self)

    @his_slices.setter
    def his_slices(self, v):
        value = self.n + v
        print("modified n in setter", value)
        A.slices().fset(self, value)

if __name__ == "__main__":
    b = B(100)

    # setter
    b.his_slices = 101
    # getter
    print("%d slices" % b.his_slices)

如果slices 确实是基类中的一个属性,那么这就是继承和修改getter 和setter 的方式。也有描述here

class A(object):
    """ Base Class """
    def __init__(self, n):
        self.n = n

    def get_slices(self):
        print("Get A", self.n)
        return self.n

    def set_slices(self, n):
        print("Set A", n)
        self.n = n

    slices = property(get_slices, set_slices)


class B(A):
    @property
    def slices(self):
        print("Get B", self.n)
        return A.slices.fget(self)

    @slices.setter
    def slices(self, v):
        value = self.n + v
        print(".. Modifing value before Set", value)
        A.slices.fset(self, value) 

if __name__ == "__main__":
    a = A(10)
    b = B(10)

    a.slices = 9
    b.slices = 11
    print("%d a-slices" % a.slices)
    print("%d b-slices" % b.slices)

上述代码的输出:

Set A 9
Modifing value before Set 21
Set A 21
Get A 9
9 a-slices
Get B 21
Get A 21
21 b-slices

...如果有疑问,回归基础并听听 Raymond Hettinger has to say about properties 的内容总是有用的

【讨论】:

  • 很详细的回复,谢谢。在子类中使用 fset 和 fget 作为属性和设置器是解决我的情况的正确方法。哦,还有,Raymond Hettinger 链接是否应该指向属性的 python 文档?只是想知道......
  • 没错,链接指向 Raymond 编写的 HOWTO 指南。滚动到该页面的顶部。
【解决方案2】:

我认为您正在寻找类似的东西。

class A(object):
    """ Base Class """
    def __init__(self, n):
        self.n = n
        self.slices
    def get_slices(self):
        return self.n
    def set_slices(self, n):
        self.n = n
    slices = property(get_slices, set_slices)


class B(A):
    def __init__(self, n):
        self.n = n
    his_slices = A.slices # <--- works well
    def her_slices(self): # <--- does not work
        return self.slices

if __name__ == "__main__":
    b = B(100)
    # This works
    print("%d slices" % b.his_slices)
    # 100 slices

    # This fails
    print("%d slices" % b.her_slices())
    # TypeError: %d format: a number is required, not method

不过,我不确定您要做什么。

【讨论】:

  • 谢谢。我应该澄清一下,我想避免更改父类,最好在子类中找到解决方法。这是因为基类已经被我正在开发的开源项目中的许多子类使用,并且我尽量避免更改它。
  • 我又花了一些时间来回答这个问题,发现您在 A 类中定义属性切片的方法是更好的方法,@Subbdue 的响应也表明了这一点。这有助于我更好地理解 python 属性,非常感谢!
  • 太好了,抱歉,我无法提供更多帮助。无论如何,@Subbdue 的回复似乎提供了更多信息。
猜你喜欢
  • 2015-05-08
  • 2017-04-14
  • 2014-01-13
  • 1970-01-01
  • 2014-09-06
  • 2021-02-12
  • 2019-11-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多