All we need is an easy explanation of the problem, so here it is.
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?
How to solve :
I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.
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'
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.
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.
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")
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()
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
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
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
Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂