我需要父项中的设置来包含子项中的函数。 (此父级的每个子级都将使用该设置,但定义函数的方式将更改)
这可能吗?目前它似乎从父类读取未定义的函数(因此中断)
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
答案 0 :(得分:2)
来自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