【问题标题】:Non-inheritable method in pythonpython中的不可继承方法
【发布时间】:2021-04-11 13:10:07
【问题描述】:

假设我有两个类,一个继承自另一个:

class A():
    def __init__(self):
        pass

    def doSomething(self):
        print('It Works !') # Insert actual code here

class B(A):
    pass

如何使doSomething 方法无法继承,以便: (我想要让错误发生)

>>> a = A()
>>> a.doSomething()
'It Works !'
>>> b = B()
>>> b.doSomething()
Traceback (most recent call last):
  File "<pyshell#132>", line 1, in <module>
    b.doSomething()
AttributeError: 'B' object has no attribute 'doSomething'

【问题讨论】:

  • 无法复制,对我来说很好,你在什么环境下执行?
  • 为什么?这听起来与 Python 的一般精神不兼容。
  • 您的代码在我的 Jupyter 笔记本上运行良好。你有哪个python版本?
  • OP 的代码正在工作,但他们希望它工作。
  • 问题不是“为什么会发生这种异常?”它实际上并没有发生。问题是“我如何让这个异常发生?”

标签: python inheritance python-3.9


【解决方案1】:

您首先应该质疑您是否想要拥有不可继承的部分。更典型的做法是将AB 的公共部分抽象为一个公共父级,或者使用mixin pattern

    class Parent
     def doCommonThing1
     def doCommonThing2
     /          \
    /            \
   /              \
  /                \
class A            class B
 def doSomething    def doOtherThing

如果您坚持认为 B 必须是 A 的子类,那么“取消继承”方法的唯一方法就是重写它以执行其他操作。例如,引发属性错误的属性实际上与缺少属性相同:

>>> class A:
...     def doSomething(self):
...         print("it works")
... 
>>> class B(A):
...     @property
...     def doSomething(self):
...         msg = "{!r} object has no attribute 'doSomething'"
...         raise AttributeError(msg.format(type(self).__name__))
... 
>>> A().doSomething()
it works
>>> hasattr(B(), "doSomething")
False
>>> B().doSomething()
...
AttributeError: 'B' object has no attribute 'doSomething'

【讨论】:

    【解决方案2】:

    据我所知,在 Python 中没有内置的方法可以做到这一点,因为它并不是真正被认为是 Python 哲学的一部分。可以在 Python 中定义“受保护”和“私有”方法,方法是在前面加上一个 _ 或两个 __,但你仍然可以调用它们,只是不鼓励。

    实现类似功能的一种非常老套的方法可能是将方法本身设为“私有”并让__getattr__ 重定向到该方法,但前提是对象确实是A

    class A():
        def __init__(self):
            pass
    
        def __doSomething(self):
            print('It Works !')
            
        def __getattr__(self, attr):
            if attr == "doSomething":
                if type(self) == A:
                    return self.__doSomething
                else:
                    raise TypeError("Nope")
            return super(A).__getattr__(self, attr)
    

    但这仍然可以通过直接以_A__doSomething 调用“私有”方法或在B 中覆盖__getattr__ 来规避。

    另外,可能更安全且可能更简单(但恕我直言),您也可以将该检查添加到 doSomething 本身。

        def doSomething(self):
            if type(self) != A:
                raise TypeError("Nope")
            print('It Works !')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-28
      • 1970-01-01
      • 2011-08-03
      • 2011-07-07
      • 2014-07-09
      • 2012-01-11
      • 2019-03-16
      • 2018-02-04
      相关资源
      最近更新 更多