38

在 C++ 中,您可以通过在子类中将其声明为私有来禁用父类中的函数。如何在 Python 中做到这一点?IE 如何从孩子的公共界面隐藏父母的功能?

4

7 回答 7

31

Python 中确实没有任何真正的“私有”属性或方法。您可以做的一件事是简单地覆盖子类中不需要的方法,并引发异常:

>>> class Foo( object ):
...     def foo( self ):
...         print 'FOO!'
...         
>>> class Bar( Foo ):
...     def foo( self ):
...         raise AttributeError( "'Bar' object has no attribute 'foo'" )
...     
>>> b = Bar()
>>> b.foo()
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
  File "<interactive input>", line 3, in foo
AttributeError: 'Bar' object has no attribute 'foo'
于 2008-10-23T22:52:51.513 回答
19

kurosch 解决问题的方法并不完全正确,因为您仍然可以b.foo在没有AttributeError. 如果您不调用该函数,则不会发生错误。以下是我能想到的两种方法:

import doctest

class Foo(object):
    """
    >>> Foo().foo()
    foo
    """
    def foo(self): print 'foo'
    def fu(self): print 'fu'

class Bar(object):
    """
    >>> b = Bar()
    >>> b.foo()
    Traceback (most recent call last):
    ...
    AttributeError
    >>> hasattr(b, 'foo')
    False
    >>> hasattr(b, 'fu')
    True
    """
    def __init__(self): self._wrapped = Foo()

    def __getattr__(self, attr_name):
        if attr_name == 'foo': raise AttributeError
        return getattr(self._wrapped, attr_name)

class Baz(Foo):
    """
    >>> b = Baz()
    >>> b.foo() # doctest: +ELLIPSIS
    Traceback (most recent call last):
    ...
    AttributeError...
    >>> hasattr(b, 'foo')
    False
    >>> hasattr(b, 'fu')
    True
    """
    foo = property()

if __name__ == '__main__':
    doctest.testmod()

Bar 使用“包装”模式来限制对包装对象的访问。Martelli 对此进行了很好的讨论。Baz 使用内置的属性来实现要覆盖的属性的描述符协议。

于 2008-10-25T00:05:19.717 回答
14

kurosch 答案的一个变体:

class Foo( object ):
    def foo( self ):
        print 'FOO!'

class Bar( Foo ):
    @property
    def foo( self ):
        raise AttributeError( "'Bar' object has no attribute 'foo'" )

b = Bar()
b.foo

这会在属性上引发 an AttributeError,而不是在调用方法时引发。

我会在评论中建议它,但不幸的是还没有它的声誉。

于 2014-04-17T06:41:17.613 回答
5
class X(object):
    def some_function(self):
        do_some_stuff()

class Y(object):
    some_function = None

这可能会导致一些令人讨厌且难以找到的异常被抛出,所以你可以试试这个:

class X(object):
    def some_function(self):
        do_some_stuff()

class Y(object):
    def some_function(self):
        raise NotImplementedError("function some_function not implemented")
于 2008-10-23T22:49:22.863 回答
1

这是我知道的最干净的方法。

覆盖这些方法并让每个被覆盖的方法调用您的 disabledmethods() 方法。像这样:

class Deck(list):
...
@staticmethod
    def disabledmethods():
        raise Exception('Function Disabled')
    def pop(self): Deck.disabledmethods()
    def sort(self): Deck.disabledmethods()
    def reverse(self): Deck.disabledmethods()
    def __setitem__(self, loc, val): Deck.disabledmethods()
于 2014-04-17T06:32:24.403 回答
1

那可能更简单。

@property
def private(self):
    raise AttributeError

class A:
    def __init__(self):
        pass
    def hello(self):
        print("Hello World")

class B(A):
    hello = private # that short, really
    def hi(self):
        A.hello(self)

obj = A()
obj.hello()
obj = B()
obj.hi() # works
obj.hello() # raises AttributeError
于 2019-06-26T10:59:19.673 回答
1

另一种方法是定义一个访问错误的描述符。

    class NotHereDescriptor:
        def __get__(self, obj, type=None):
            raise AttributeError
    
    class Bar:
        foo = NotHereDescriptor()

这在本质上类似于一些人在上面使用的属性方法。但是,如果该函数确实不存在,它的优点是hasattr(Bar, 'foo')可以按预期返回。False这进一步减少了奇怪错误的机会。虽然它仍然出现在dir(Bar).

如果您对它的作用及其工作原理感兴趣,请查看数据模型页面https://docs.python.org/3/reference/datamodel.html#descriptors的描述符部分以及如何使用https:/的描述符/docs.python.org/3/howto/descriptor.html

于 2020-08-25T18:49:20.873 回答