【问题标题】:How to hide/remove some methods in inherited class in Python?如何在 Python 中隐藏/删除继承类中的某些方法?
【发布时间】:2014-04-20 11:24:21
【问题描述】:

想在从class A继承class B的过程中隐藏一些公共方法

class A(object):
  def someMethodToHide():
    pass

  def someMethodToShow():
    pass

class B(A):
  pass

len(set(dir(A)) - set(dir(B))) == 1

如果可能的话,如何在 python 中做到这一点?

【问题讨论】:

  • 您对子类的删除方法有什么用例?你确定要在这种情况下使用类继承吗?
  • 您可以从只有要显示的方法的第三类 C 扩展 A 和 B。然后你可以只在A类中实现methodToHide。
  • @Selcuk 看起来这是实现它的最简单方法:)
  • @Ffisegydd 是的,因为根本不想要重复代码 - 不像 Java 那样需要与代码重复作斗争。
  • 但我想我的观点是“你为什么只想部分继承超类?”如果它只订阅部分功能,它真的会被认为是一个子类吗?

标签: python


【解决方案1】:

这是我评论的答案形式:您可以从第三个类 C 继承 A 和 B。就像这样:

class C(object):
  def someMethodToShow():
    pass

class A(C):
  def someMethodToHide():
    pass

class B(C):
  pass

作为旁注,如果你想要的东西是可能的,它会破坏多态性。这个不会。

【讨论】:

  • 这是面向对象设计中最常见的解决方案和有效的模式——我将研究 CURSED 一种,因为要隐藏一些方法。
【解决方案2】:

Selcuk 的suggestion 最好不过有时重构太麻烦。

所以,相反,这会导致你的同事像女妖一样尖叫并诅咒你的名字。

它通过使用元类hide_meta 添加重载的__getattribute____dir__ 方法来工作。只需设置 __metaclass__ = hide_meta__excluded__ = ["list", "of", "unwanted", "attributes/methods"] 即可将其应用于所需的类。

class hide_meta(type):
    def __new__(cls, cls_name, cls_bases, cls_dict):
        cls_dict.setdefault("__excluded__", [])
        out_cls = super(hide_meta, cls).__new__(cls, cls_name, cls_bases, cls_dict)

        def __getattribute__(self, name):
            if name in cls_dict["__excluded__"]:
                raise AttributeError(name)
            else:
                return super(out_cls, self).__getattribute__(name)
        out_cls.__getattribute__ = __getattribute__

        def __dir__(self):
            return sorted((set(dir(out_cls)) | set(self.__dict__.keys())) - set(cls_dict["__excluded__"])) 
        out_cls.__dir__ = __dir__

        return out_cls

class A(object):
    def someMethodToHide(self):
        pass

    def someMethodToShow(self):
        pass

class B(A):
    __metaclass__ = hide_meta
    __excluded__  = ["someMethodToHide"]

a = A()
print dir(a)
b = B()
print dir(b)
b.someMethodToShow()
b.someMethodToHide()

【讨论】:

  • 这是非常复杂的,因为它提供的价值很小。我认为这个对相同问题的回答给出了一个更清晰的解决方案:stackoverflow.com/a/11204743/7432
  • @BryanOakley,这个答案更简单,但是NotImplementedError 并没有“隐藏”该方法,它只是使它无法使用。该答案也不适用于属性(无论如何都不会涉及@property)。
  • @dilbert 确实NotImplementedError 不是我问的。你的解释很好 - 看起来这是最好的答案!有时需要像你说的那样做 CURSED CODE 隐藏方法。 BTW #Seluck 解决方案应该经常使用,但有时需要隐藏方法 - 用 NotImplementedError 覆盖是错误的模式,因为错误类型无效并建议其他内容 - 有效的是 AttributeError。如果没有更好的解决方案,我会尽快标记答案。
【解决方案3】:

您可以创建一个descriptor 类来模拟“已删除”属性。然后,您可以为该类的实例分配“待删除”名称。

这是一个完整的示例,显示了访问子类上的该属性及其实例时出现的错误/回溯。通过引发自定义错误,回溯显式表明该属性已被故意“删除”。

In [1]: class DeletedAttributeError(AttributeError): 
   ...:     pass 
   ...:  
   ...:  
   ...: class DeletedAttribute: 
   ...:     def __set_name__(self, owner, name): 
   ...:         self.name = name 
   ...:  
   ...:     def __get__(self, instance, owner): 
   ...:         cls_name = owner.__name__ 
   ...:         accessed_via = f'type object {cls_name!r}' if instance is None else f'{cls_name!r} object' 
   ...:         raise DeletedAttributeError(f'attribute {self.name!r} of {accessed_via} has been deleted') 
   ...:  
   ...:  
   ...: class Foo: 
   ...:     def hide_me(self): 
   ...:         pass 
   ...:  
   ...:  
   ...: class Bar(Foo): 
   ...:     hide_me = DeletedAttribute() 
   ...:                                                                                       

In [2]: Foo.hide_me                                                                           
Out[2]: <function __main__.Foo.hide_me(self)>

In [3]: Bar.hide_me                                                                           
---------------------------------------------------------------------------
DeletedAttributeError                     Traceback (most recent call last)
<ipython-input-3-240c91cc1fc8> in <module>
----> 1 Bar.hide_me

<ipython-input-1-0f699423deb7> in __get__(self, instance, owner)
     10         cls_name = owner.__name__
     11         accessed_via = f'type object {cls_name!r}' if instance is None else f'{cls_name!r} object'
---> 12         raise DeletedAttributeError(f'attribute {self.name!r} of {accessed_via!r} has been deleted')
     13 
     14 

DeletedAttributeError: attribute 'hide_me' of type object 'Bar' has been deleted

In [4]: Bar().hide_me                                                                         
---------------------------------------------------------------------------
DeletedAttributeError                     Traceback (most recent call last)
<ipython-input-4-9653f0da628c> in <module>
----> 1 Bar().hide_me

<ipython-input-1-0f699423deb7> in __get__(self, instance, owner)
     10         cls_name = owner.__name__
     11         accessed_via = f'type object {cls_name!r}' if instance is None else f'{cls_name!r} object'
---> 12         raise DeletedAttributeError(f'attribute {self.name!r} of {accessed_via!r} has been deleted')
     13 
     14 

DeletedAttributeError: attribute 'hide_me' of 'Bar' object has been deleted

以上代码适用于 Python 3.6+。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 2011-04-18
    相关资源
    最近更新 更多