Overriding special methods on an instance
Python usually doesn't call the special methods (those with name surrounded by __
) on the instance, but only on the class. (Although this is an implementation detail, it's characteristic of CPython, the standard interpreter.) So there's no way to override __repr__()
directly on an instance and make it work. Instead, you need to do something like so:
class A(object):
def __repr__(self):
return self._repr()
def _repr(self):
return object.__repr__(self)
Now you can override __repr__()
on an instance by substituting _repr()
.
Override a method at instance level
Please do not do this as shown. You code becomes unreadable when you monkeypatch an instance to be different from the class.
You cannot debug monkeypatched code.
When you find a bug in boby
and print type(boby)
, you'll see that (a) it's a Dog, but (b) for some obscure reason it doesn't bark correctly. This is a nightmare. Do not do it.
Please do this instead.
class Dog:
def bark(self):
print "WOOF"
class BobyDog( Dog ):
def bark( self ):
print "WoOoOoF!!"
otherDog= Dog()
otherDog.bark() # WOOF
boby = BobyDog()
boby.bark() # WoOoOoF!!
Python overriding class (not instance) special methods
Special method __str__
defined in a class works only for the instances of that class, to have the different behavior for class objects you will have to do it in a metaclass of that class e.g. (python 2.5)
class Meta(type):
def __str__(self):
return "Klass"
class A(object):
__metaclass__ = Meta
def __str__(self):
return "instance"
print A
print A()
output:
Klass
instance
Is it a bad practice to override a method of a class in an instance?
The only valid answer here is the same as the old chestnut response the doctor gives when you ask what to do about the pain you feel when you jab yourself in the eye repeatedly: If it hurts, stop doing that. Your eye was not designed to have a finger jabbed in it.
So, yes, it is bad practice to add a method to an instance or a class when it breaks the expectations of the existing code that calls it.
Note that this has really nothing to do with the specifics of your examples. Any existing code can be broken this way, by replacing or shadowing something else with an implementation that doesn't fit the existing expectations.
Your examples can be trivially fixed; to replace the M.g
method on a class, use a class method. To replace A.g
on the instance, use a function that doesn't expect self
. Both would fit the expectations of the existing code: that calling g
does not require additional arguments.
Python is highly dynamic, and that gives you loads and loads of freedom, including the freedom to poke yourself in the proverbial eye. Try not to do that last thing or anything else that could hurt your code, and you should be fine.
How can I override a special method defined in a metaclass with a custom classmethod?
The __len__
defined in the class will always be ignored when using len(...)
for the class itself: when executing its operators, and methods like "hash", "iter", "len" can be roughly said to have "operator status", Python always retrieve the corresponding method from the class of the target, by directly acessing the memory structure of the class. These dunder methods have "physical" slot in the memory layout for the class: if the method exists in the class of your instance (and in this case, the "instances" are the classes "GoodBar" and "BadBar", instances of "FooMeta"), or one of its superclasses, it is called - otherwise the operator fails.
So, this is the reasoning that applies on len(GoodBar())
: it will call the __len__
defined in GoodBar()
's class, and len(GoodBar)
and len(BadBar)
will call the __len__
defined in their class, FooMeta
I don't really understand the interaction with the @classmethod
decorator.
The "classmethod" decorator creates a special descriptor out of the decorated function, so that when it is retrieved, via "getattr" from the class it is bound too, Python creates a "partial" object with the "cls" argument already in place. Just as retrieving an ordinary method from an instance creates an object with "self" pre-bound:
Both things are carried through the "descriptor" protocol - which means, both an ordinary method and a classmethod are retrieved by calling its __get__
method. This method takes 3 parameters: "self", the descriptor itself, "instance", the instance its bound to, and "owner": the class it is ound to. The thing is that for ordinary methods (functions), when the second (instance) parameter to __get__
is None
, the function itself is returned. @classmethod
wraps a function with an object with a different __get__
: one that returns the equivalent to partial(method, cls)
, regardless of the second parameter to __get__
.
In other words, this simple pure Python code replicates the working of the classmethod
decorator:
class myclassmethod:
def __init__(self, meth):
self.meth = meth
def __get__(self, instance, owner):
return lambda *args, **kwargs: self.meth(owner, *args, **kwargs)
That is why you see the same behavior when calling a classmethod explicitly with klass.__get__()
and klass().__get__()
: the instance is ignored.
TL;DR: len(klass)
will always go through the metaclass slot, and klass.__len__()
will retrieve __len__
via the getattr mechanism, and then bind the classmethod properly before calling it.
Aside from the obvious metaclass solution (ie, replace/extend FooMeta)
is there a way to override or extend the metaclass function so that
len(BadBar) -> 9002?
(...)
To clarify, in my specific use case I can't edit the metaclass, and I
don't want to subclass it and/or make my own metaclass, unless it is
the only possible way of doing this.
There is no other way. len(BadBar)
will always go through the metaclass __len__
.
Extending the metaclass might not be all that painful, though.
It can be done with a simple call to type
passing the new __len__
method:
In [13]: class BadBar(metaclass=type("", (FooMeta,), {"__len__": lambda cls:9002})):
...: pass
In [14]: len(BadBar)
Out[14]: 9002
Only if BadBar will later be combined in multiple inheritance with another class hierarchy with a different custom metaclass you will have to worry. Even if there are other classes that have FooMeta
as metaclass, the snippet above will work: the dynamically created metaclass will be the metaclass for the new subclass, as the "most derived subclass".
If however, there is a hierarchy of subclasses and they have differing metaclasses, even if created by this method, you will have to combine both metaclasses in a common subclass_of_the_metaclasses before creating the new "ordinary" subclass.
If that is the case, note that you can have one single paramtrizable metaclass, extending your original one (can't dodge that, though)
class SubMeta(FooMeta):
def __new__(mcls, name, bases, ns, *,class_len):
cls = super().__new__(mcls, name, bases, ns)
cls._class_len = class_len
return cls
def __len__(cls):
return cls._class_len if hasattr(cls, "_class_len") else super().__len__()
And:
In [19]: class Foo2(metaclass=SubMeta, class_len=9002): pass
In [20]: len(Foo2)
Out[20]: 9002
Java overriding methods when creating new instance of a class
protected
means (roughly) "available to sub-classes". (See this table.) Since the new View(this) { ... }
creates a subclass, it is possible to override the method within it.
In this case it doesn't matter that you're in a different package. (See the protected
line and second column in this table.) The fact that the method is in a subclass is sufficient to "get access" to a protected method.
Potential follow-up question: What sense does it make, if I can't call the method anyway?
All methods in Java are virtual. This means that whenever the View
class performs a seemingly internal call to the onDraw
method, this call will be dispatched to the overridden method.
Overriding the __str__ method for @classmethods in python
Python doesn't look for a __str__
on the class itself, just like it won't use __str__
set on an instance. This applies to all special methods, see Special method lookup in the Python datamodel:
For custom classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary.
In short, str(something)
does not use something.__str__()
, it essentially uses type(something).__str__(something)
(*) exactly because you wouldn't want the definition of __str__
on a class to break when you use str(class_object)
, where class_object.__str__()
doesn't have an instance to pass in as self
.
You'll have to define a metaclass, because that's the 'thing' that makes classes and is returned by type(class_object)
:
class MetaAbc(type):
def __repr__(cls):
return "__repr__ on the metaclass"
def __str__(cls):
return "__str__ on the metaclass"
class Abc(metaclass=MetaAbc):
def __init__(self, name):
self.name = name
def __str__(self):
return f"Added {self.name}"
def __repr__(self):
return "instance method repr"
The metaclass=MetaAbc
syntax tells Python to use MetaAbc
instead of just type
as metaclass of the Abc
class; now type(Abc)
returns MetaAbc
:
>>> type(Abc)
<class '__main__.MetaAbc'>
and MetaAbc.__repr__
and MetaAbc.__str__
are used when representing a class, or converting it to a string; the methods on the class are used when dealing with an instance:
>>> Abc
__repr__ on the metaclass
>>> print(Abc)
__str__ on the metaclass
>>> Abc('foo')
instance method repr
>>> print(Abc('foo'))
Added foo
The @classmethod
decorator does not put a method into a different namespace; class methods are normal attributes of a class and are simply bound differently. @classmethod
's are still accessible on the instance, for example, but will always be passed the class object, even when accessed via the instance:
>>> Abc.class_method()
class method '__str__ on the metaclass'
>>> Abc("foo").class_method()
class method '__str__ on the metaclass'
(*) Python uses descriptor binding to implement methods, classmethods and staticmethods. Special method lookups look up the function object directly by traversing the class hierarchy to avoid triggering the normal binding process, then bind them manually. So str(something)
translates to next(c.__dict__['__str__'] for c in type(something).__mro__ if '__str__' in c.__dict__).__get__(something, type(something))()
. That's a bit of a mouthful, for normal methods this can be simplified to type(something).__str__(something)
as that has the same effect.
Related Topics
Total Memory Used by Python Process
Get Last N Lines of a File, Similar to Tail
Pip Is Not Working for Python 3.10 on Ubuntu
Find Broken Symlinks with Python
A Simple Python Deployment Problem - a Whole World of Pain
What's the Advantage of Queues Over Pipes When Communicating Between Processes
How Can Python Handle Systemctl Stop
Pandas Column of Lists, Create a Row For Each List Element
How to Crop an Image in Opencv Using Python
How to Close a Socket Left Open by a Killed Program
Setting Ld_Library_Path from Inside Python
How to Get the Owner and Group of a Folder with Python on a Linux MAChine
Making Python Script Accessible System Wide