【问题标题】:Call child functions from parent property with same abstract functions使用相同的抽象函数从父属性调用子函数
【发布时间】:2016-12-01 19:51:35
【问题描述】:

我需要父项中的设置来包含子项的功能。 (此父级的每个子级都将使用该设置,但定义函数的方式会改变)

这可能吗?目前它似乎从父类中读取未定义的函数(因此中断)

class Mine(object):
    __metaclass__ = ABCMeta
    @abstractmethod
    def _get_stuff(self):
        raise NotImplementedError()

    @abstractmethod
    def _set_stuff(self, value):
        raise NotImplementedError()

    settings = property(_get_stuff, _set_stuff)

    def do_stuff_with_settings(self):
        return settings

class Child(Mine):
    def _get_stuff(self):
        return {"a": 2}
    def _set_stuff(self):
        pass
    def do_stuff(self):
        self.a = do_stuff_with_settings.a

【问题讨论】:

  • 你想通过这种方式解决什么问题?
  • 有许多通用功能(每个孩子都一样)使用该设置。我不希望这些函数引用父级中不存在的变量(尽管 python 不会抱怨)。
  • 可以do_stuff_with_settings return property(self._get_stuff, self._set_stuff)
  • do_stuff_with_settings 有很多函数可以访问设置中包含的参数,而 _get_stuff 正在从另一个字典中检索值字典

标签: python abstract


【解决方案1】:

来自docs

从 ABCMeta 派生的元类不能被实例化,除非所有 它的抽象方法和属性被覆盖。

我将您创建基类的方式更改为class Mine(metaclass=ABCMeta): 并收到错误

Traceback (most recent call last):
  File "g.py", line 24, in <module>
    Child().settings
TypeError: Can't instantiate abstract class Child with abstract methods settings

这样可以使问题更加明确。要解决此问题,只需让子类创建自己的 settings 属性。现在它们被绑定到具体方法而不是抽象方法。

from abc import ABCMeta,abstractmethod

class Mine(object):
    __metaclass__ = ABCMeta
    @abstractmethod
    def _get_stuff(self):
        raise NotImplementedError()

    @abstractmethod
    def _set_stuff(self, value):
        raise NotImplementedError()

    settings = property(_get_stuff, _set_stuff)

    def do_stuff_with_settings(self):
        return settings

class Child(Mine):
    def _get_stuff(self):
        return 1
    def _set_stuff(self):
        pass
    settings = property(_get_stuff, _set_stuff)

Child().settings

更新

这不仅仅是一个 ABC 问题。任何覆盖属性方法的子类都有这个问题。在这里,我尝试覆盖一个getter,但发现我仍然得到了父母的看法:

>>> class Foo:
...     def __init__(self, val):
...         self._val = val
...     def _get_val(self):
...         return self._val
...     def _set_val(self, val):
...         self._val = val
...     val = property(_get_val, _set_val)
... 
>>> class Bar(Foo):
...     def _get_val(self):
...         return self._val + 2
... 
>>> print('want 3, got', Bar(1).val)
want 3, got 1

更新 2

问题是property在定义的时候绑定了类方法。如果你不介意实现中间函数,那么你可以让它们在子进程覆盖它们之后在运行时解析目标方法。在这里,_get_stuff 在运行时调用_get_stuff_impl,您将获得子版本。

from abc import ABCMeta,abstractmethod

class Mine(metaclass=ABCMeta):
    def _get_stuff(self):
        return self._get_stuff_impl()

    @abstractmethod
    def _get_stuff_impl(self):
        raise NotImplementedError()

    def _set_stuff(self, value):
        return self._set_stuff_impl(value)

    @abstractmethod
    def _set_stuff_impl(self, value):
        raise NotImplementedError()

    settings = property(_get_stuff, _set_stuff)

    def do_stuff_with_settings(self):
        return settings

class Child(Mine):
    def _get_stuff_impl(self):
        return 1
    def _set_stuff_impl(self):
        pass
#    settings = property(_get_stuff, _set_stuff)

Child().settings

【讨论】:

  • @north.mister - 如果你想使用属性,那么是的,这是唯一的方法。父 settings = property(_get_stuff, _set_stuff) 绑定到父方法。它也不是一个真正的抽象方法。任何重写属性实现函数的子类都会遇到同样的问题。
  • @north.mister - 你可以玩弄系统,不过……我提供了一个更新示例。
猜你喜欢
  • 2019-04-05
  • 2019-07-11
  • 1970-01-01
  • 2021-04-07
  • 1970-01-01
  • 1970-01-01
  • 2013-10-01
  • 2019-09-10
  • 1970-01-01
相关资源
最近更新 更多