Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing specific methods from child class which are inherited from parent class

The code is as below, just the basic structure:

class FooType(type):
    def __new__( cls, name, bases, classdict ):
        instance = type.__new__( cls, name, bases, classdict )
        # What can I do here?
        return instance

class FooBase( object, metaclass=FooType ):
    def __init__( self ):
        pass

class Foo( FooBase ):
    def __init__( self, name ):
        self.name = name

    def method1( self ):
        pass

    def method2( self ):
        pass

    def specialmethod( self ):
        pass

class A( Foo ):
    pass

class B( Foo ):
    pass

class C( Foo ):
    _disallowed_methods = ['specialmethod']

What I want to do is that instances of class C should not have specialmethod, but that method should be available to instances A and B.

I can override this method in class C and raise an error, but I would prefer not to do this.

I realize I can add in code to check for _disallowed_methods in the FooType and on the basis of that check if the instance has any of them in the output of dir(instance). But I cannot seem to remove the method from __dict__ of C using any methods I have tried so far. The methods I tried are delattr(instance, 'specialmethod'), and del instance.__dict__['specialmethod'].

The delattr method results in "AttributeError: specialmethod", and the del method results in "TypeError: 'dict_proxy' object does not support item deletion"

Basically many different classes will inherit from Foo, but some of them should not have specific methods available to them like C which should not have specialmethod available to it.

What am I doing wrong? Or how else can I accomplish this?

like image 909
skulled Avatar asked Jul 14 '11 13:07

skulled


People also ask

What is the result of a child class inheriting a method from a parent class?

Child Classes Child or subclasses are classes that will inherit from the parent class. That means that each child class will be able to make use of the methods and variables of the parent class.

What if parent and child class has same method?

If subclass (child class) has the same method as declared in the parent class, it is known as method overriding in Java. In other words, If a subclass provides the specific implementation of the method that has been declared by one of its parent class, it is known as method overriding.

Can parent classes access child class methods?

The only unusual aspect is that, within child class method definitions, you can't directly access parent class instance variables. For example, if the parent had a height instance variable, child class method definitions wouldn't be able to access this directly.

Can a subclass remove a method that it inherits if it doesn't want to expose it?

as I know the subclass can only add functionality and properties to the parent class, but can't remove them.


2 Answers

If you have a parent, which you don't want to be modified, and a child with one or more inherited methods you want to be unaccessible, you could do so with descriptors. One of the simplest approach is to use property built-in:

class Parent:
    def good_method(self):
        print('Good one')

    def bad_method(self):
        print('Bad one')

class Child(Parent):
    bad_method = property(doc='(!) Disallowed inherited')

one = Parent()
one.good_method()  # > 'Good one'
one.bad_method()   # > 'Bad one'

two = Child()
two.good_method()  # > 'Good one'
two.bad_method()   # > AttributeError: unreadable attribute
two.bad_method     # > AttributeError: unreadable attribute
two.bad_method = 'Test'  # > AttributeError: can't set attribute

How help(two) prints it:

class Child(Parent)
 |  Method resolution order:
 |      Child
 |      Parent
 |      builtins.object
 |  
 |  Data descriptors defined here:
 |  
 |  bad_method
 |      (!) Disallowed inherited
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from Parent:
 |  
 |  good_method(self)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from Parent:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)

Pretty good, in my opinion. But you should be careful not to define inherited methods this way if other methods rely on them (this could be avoided by using proxy class, which inherits from parent and redefines such methods to use super().bad_method() instead of just self.bad_method() and points the bad_method itself to disallowing descriptor). You could code more complicated descriptor logic if needed

like image 173
thodnev Avatar answered Oct 07 '22 04:10

thodnev


Well, you can't accomplish this in such a way, since you have to modify not C class, but Foo class, which really contains specialmethod. But actually you can't do it since class is the global mutable object and any changes to Foo will affect all child classes.

Try to think in another way. E.g. you can modify logic of accessing attributes of C class:

class C( Foo ):
    def __getattribute__(self, name):
        if name in ['specialmethod']:
            raise AttributeError('no such method')
        return super(C, self).__getattribute__(name)

After that C('a').specialmethod() produces a traceback:

Traceback (most recent call last):
  File "meta.py", line 37, in <module>
    C('a').specialmethod()
  File "meta.py", line 34, in __getattribute__
    raise AttributeError('no such method')
AttributeError: no such method
like image 24
Roman Bodnarchuk Avatar answered Oct 07 '22 02:10

Roman Bodnarchuk