views:

1160

answers:

3

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?

+1  A: 
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")
Jason Baker
+9  A: 

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
>There really aren't any true "private" attributes or methods in Python.That is why I didn't ask how to make them private, but how to 'remove' them from the interface. Hope that the edited version is more accurate
bgbg
I agree that NotImplementedError is probably the best one to use, but if you really wanted to match not having the inherited method at all, raise AttributeError instead (which is what you'd get if the parent method didn't exist).
Tony Meyer
Good point regarding AttributeError. I will update my example.
kurosch
This doesn't do what you want -- an AttributeError will only be raised if the foo method is /invoked/ -- getattr(b, 'foo') still returns a method object (an attribute!).
cdleary
+4  A: 

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.

cdleary
Well, sure, in my answer it's still "visible", but you can't "use" it per se because it will raise the exception. A valid point, though.
kurosch