Python 继承 - 如何禁用函数

发布于 2024-07-07 10:16:00 字数 84 浏览 7 评论 0原文

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

In C++ you can disable a function in parent's class by declaring it as private in the child class. How can this be done in Python? I.E. How can I hide parent's function from child's public interface?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

拥有 2024-07-14 10:16:00

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'

There really aren't any true "private" attributes or methods in Python. One thing you can do is simply override the method you don't want in the subclass, and raise an exception:

>>> 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'
廻憶裏菂餘溫 2024-07-14 10:16:00

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 使用“wrap”模式来限制对包装对象的访问。 Martelli 有一个很好的演讲来处理这个问题。 Baz 使用内置属性来实现描述符协议要覆盖的属性。

kurosch's method of solving the problem isn't quite correct, because you can still use b.foo without getting an AttributeError. If you don't invoke the function, no error occurs. Here are two ways that I can think to do this:

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 uses the "wrap" pattern to restrict access to the wrapped object. Martelli has a good talk dealing with this. Baz uses the property built-in to implement the descriptor protocol for the attribute to override.

娇女薄笑 2024-07-14 10:16:00

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

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

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

A variation on the answer of 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

This raises an AttributeError on the property instead of when the method is called.

I would have suggested it in a comment but unfortunately do not have the reputation for it yet.

两人的回忆 2024-07-14 10:16:00
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")
class X(object):
    def some_function(self):
        do_some_stuff()

class Y(object):
    some_function = None

This may lead to some nasty and hard to find exceptions being thrown though, so you might try this:

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

class Y(object):
    def some_function(self):
        raise NotImplementedError("function some_function not implemented")
愛上了 2024-07-14 10:16:00

那可能更简单。

@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

That could be even simpler.

@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
半夏半凉 2024-07-14 10:16:00

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

重写这些方法并让每个被重写的方法调用您的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()

This is the cleanest way I know to do it.

Override the methods and have each of the overridden methods call your disabledmethods() method. Like this:

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()
巴黎盛开的樱花 2024-07-14 10:16:00

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

    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

Another approach is define an descriptor that errors on access.

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

This is similar in nature to the property approach a few people have used above. However it has the advantage that hasattr(Bar, 'foo') will return False as one would expect if the function really didn't exist. Which further reduces the chance of weird bugs. Although it does still show up in dir(Bar).

If you are interested in what this is doing and why it works check out the descriptor section of the data model page https://docs.python.org/3/reference/datamodel.html#descriptors and the descriptor how to https://docs.python.org/3/howto/descriptor.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文