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?
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.
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.
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.
as I know the subclass can only add functionality and properties to the parent class, but can't remove them.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With