实现子类中的抽象属性而不重新定义 __init__ 方法

huangapple go评论112阅读模式
英文:

Implement abstract properties without redefining __init__ in child

问题

我正在学习abc模块,想知道我想做的是否可能。

基本上,我创建的每个子类都应该具有完全相同的__init__。基类将具有一些需要由子类定义的抽象属性。我想在不必每次都重写整个__init__的情况下定义这些抽象属性。

示例:

我最初尝试了类似于这样的方法:

  1. from abc import ABC, abstractmethod
  2. class test(ABC):
  3. def __init__(self):
  4. pass
  5. @property
  6. @abstractmethod
  7. def prop(self):
  8. pass
  9. class prop_ex(test):
  10. @property
  11. def prop(self):
  12. return "THIS WORKS"

然后我尝试了:

  1. from abc import ABC, abstractmethod
  2. class test(ABC):
  3. def __init__(self):
  4. self.prop = prop
  5. @property
  6. @abstractmethod
  7. def prop(self):
  8. pass
  9. class prop_ex(test):
  10. prop = "THIS WORKS"
  11. @property
  12. def prop(self):
  13. return self._prop

还不行,所以我尝试了:

  1. from abc import ABC, abstractmethod
  2. class test(ABC):
  3. def __init__(self):
  4. pass
  5. @property
  6. @abstractmethod
  7. def prop(self):
  8. pass
  9. class prop_ex(test):
  10. self.prop = "THIS WORKS"
  11. @property
  12. def prop(self):
  13. return self._prop

对于最后一个尝试,如果你在父类的__init__中设置断点并执行dir(self),你会看到其中包含了'prop'

所以我认为这应该可以工作。

编辑:

我看到我完全复杂化了这个问题。我本可以简单地这样做:

  1. from abc import ABC, abstractmethod
  2. class test(ABC):
  3. def __init__(self):
  4. pass
  5. @property
  6. @abstractmethod
  7. def prop(self):
  8. pass
  9. class prop_ex(test):
  10. prop = "THIS WORKS"

以这种方式做有问题吗?

英文:

I am learning the abc module and was wondering if what I want to do is possible.

Essentially, every child I make of the base class should have the SAME exact __init__. The base class will have a few abstract properties that will need to be defined by the child. I would to define those abstract properties without having to rewrite the entire __init__ every time.

Example:

I initially tried something like this

  1. from abc import ABC,abstractmethod
  2. class test(ABC):
  3. def __init__(self):
  4. pass
  5. @property
  6. @abstractmethod
  7. def prop(self):
  8. pass
  9. class prop_ex(test):
  10. @property
  11. def prop(self):
  12. return "THIS WORKS"
  1. >>> from abc_tests import prop_ex
  2. >>> blah = prop_ex()
  3. >>> blah.prop
  4. Traceback (most recent call last):
  5. File "<stdin>", line 1, in <module>
  6. AttributeError: 'prop_ex' object has no attribute 'prop'

it didn't work.

Then I tried

  1. from abc import ABC,abstractmethod
  2. class test(ABC):
  3. def __init__(self):
  4. self.prop = prop
  5. @property
  6. @abstractmethod
  7. def prop(self):
  8. pass
  9. class prop_ex(test):
  10. prop = "THIS WORKS"
  11. @property
  12. def prop(self):
  13. return self._prop

Test

  1. >>> from abc_tests import prop_ex
  2. >>> blah = prop_ex()
  3. Traceback (most recent call last):
  4. File "<stdin>", line 1, in <module>
  5. File "abc_tests.py", line 13, in __init__
  6. self.prop = prop
  7. NameError: name 'prop' is not defined

No good either, so then I tried

  1. from abc import ABC,abstractmethod
  2. class test(ABC):
  3. def __init__(self):
  4. pass
  5. @property
  6. @abstractmethod
  7. def prop(self):
  8. pass
  9. class prop_ex(test):
  10. self.prop = "THIS WORKS"
  11. @property
  12. def prop(self):
  13. return self._prop

test

  1. >>> from dunder_tests import prop_ex
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in <module>
  4. File "abc_tests.py", line 39, in <module>
  5. class prop_ex(test):
  6. File "abc_tests.py", line 40, in prop_ex
  7. self.prop = "THIS WORKS"
  8. NameError: name 'self' is not defined

For the last one if you set a breakpoint in __init__ of the parent and do a dir(self) you'll see 'prop' in it.

  1. >>> blah = prop_ex()
  2. > abc_tests.py(14)__init__()
  3. -> self.prop = prop
  4. (Pdb) dir(self)
  5. ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '__weakref__', '_abc_impl', 'prop']

So I thought that would work.

Edit:

I see I am completely over complicating this. I could have simply did

  1. from abc import ABC,abstractmethod
  2. class test(ABC):
  3. def __init__(self):
  4. pass
  5. @property
  6. @abstractmethod
  7. def prop(self):
  8. pass
  9. class prop_ex(test):
  10. prop = "THIS WORKS"

Is there an issue with doing it this way?

答案1

得分: 1

正如您正确总结的那样,最简单的解决方案是定义一个abstractproperty,并让子类定义它,根本不需要__init__

我会更进一步,在基类中引发一个异常,以确保没有不必要的super()调用。

  1. import abc
  2. class test(abc.ABC):
  3. @property
  4. @abc.abstractmethod
  5. def prop(self):
  6. raise NotImplementedException()
  7. class prop_ex(test):
  8. prop = "THIS WORKS"

顺便说一句:您的第一个示例已经对我起作用。其他两个不起作用的原因是,第二种方法尝试查找一个名为prop局部变量,而这个变量不存在,第三种方法在类体中引用了**self** - 但是self只在类的方法/属性中定义,而不在类体中。

此外,这并不阻止子类修改__init__,任何子类仍然可以修改__init__

英文:

As you've correctly summized, the most straight-forward solution would be to define an abstractproperty and simply let the subclass define it, no need for __init__ at all.

I would go a step further and throw an Exception in the base-class just to make sure there's no stray super() call on it.

  1. import abc
  2. class test(abc.ABC):
  3. @property
  4. @abc.abstractmethod
  5. def prop(self):
  6. raise NotImplementedException()
  7. class prop_ex(test):
  8. prop = "THIS WORKS"

By the way: Your first example already worked for me. The other two don't work because the second approach tries to find a local variable called prop which doesn't exist and the third approach references self in the class body - but self is only defined in methods/properties of a class, not in the class body.


Also this doesn't prevent __init__ from being overridden in subclasses, any subclass may still modify the __init__.

huangapple
  • 本文由 发表于 2020年1月6日 02:19:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/59602883.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定