Overwrite method or derive? - python

For a given class, is it better/fancier/more in accordance with Python Zen to overwrite a method (I.e., assign another function to it) or derive from that class and overwrite it in the new class.
So this:
from foo import Bar
def mybaz(self):
pass
Bar.baz = mybaz
Or:
from foo import bar
class Mybar(Bar):
def baz(self):
pass
If it makes a difference, please refer to Python3
Follow up: is the answer different for magic methods?

Second way is more preferable as it doesn't change the base class, but extends it, take a look at the open/closed principle.

Related

How to override a method in python of an object and call super?

I have an Object of the following class which inherates from the algorithm class.
class AP(Algorithm):
def evaluate(self, u):
return self.stuff *2 +u
The Algorithm class has a method called StoppingCritiria.
At some point in the project the object objAP = AP() gets created. Later on I can then actually access it.
And at that point in time I want to override the method StoppingCriteria by some function which calls the old StoppingCriteria.
I tried simply
def new_stopping(self):
return super().StoppingCriteria() and custom(self.u)
objAP.StoppingCriteria = newStoppingCriteria
But that did not work. What did work were two rather inconviniend solutions:
New AP class (not desirable since I possibly need to do that for lots of classes)
class AP_custom(AP):
def StoppingCriteria(self):
return super().StoppingCriteria() and custom(self)
Override the Method but not using super but rather copy pasting the code into the new function and adding my code to that. Not desirable since I want to changes in the original method to be applyed to my new function as well.
See Override a method at instance level for many possible solutions. None of them will really work with super though, since you're simply not defining the replacement function in a class. You can define it slightly differently though for it to work:
class Foo:
def bar(self):
print('bar')
f = Foo()
def _bar(self):
type(self).bar(self) # or Foo.bar(self)
print('baz')
from typing import MethodType
f.bar = MethodType(_bar, f)
f.bar() # outputs bar baz
Since you're replacing the method at the instance level, you don't really need to access the method of the super class, you just want to access the method of the class, which still exists in its original form.

class overwrite __init__ default parameter

I import a class Foo that has a default parameter dir upon which if performs a function doit. How can I change the default dir? Do I need to inherit this class and then change it, how?
class Foo(object):
def __init__(self, dir='xxx'):
self.bar = doit(dir) # fails because xxx is wrong
why don't you just provide a different argument when you construct an instance of the class:
foo = Foo(dir='something else')
btw: dir is a python built-in and therefore not the best choice as variable name.
if you want the default changed, you can inherit indeed:
class MyFoo(Foo):
def __init__(self, d='somethig else'):
super().__init__(d=d)
Just create a factory function for Foo objects and be done with it:
def create_foo():
return Foo(dir='my correct value goes here')
Since you're importing Foo, you could go a step further and just shadow Foo like this:
def Foo():
import foo
return foo.Foo(dir='my correct value goes here')
Of course you can inherit from Foo. Be sure to look up how to call the base
class constructors. I find that sooo hard to memorize that I just end up google it. Every. Single. Time.
BTW: Looks like #hiro protagonist already has the calling super figured out.

Python mixins how to differentiate same method?

From here, if you define some objects like that:
class Mixin1(object):
def test(self):
print "Mixin1"
class Mixin2(object):
def test(self):
print "Mixin2"
class BaseClass(object):
pass
class MyClass(Mixin2, Mixin1, BaseClass):
pass
You'll get:
>>> obj = MyClass()
>>> obj.test()
Mixin2
Is there a way to call Mixin1 test() method?
Call it explicitly:
Mixin1.test(obj)
The attribute process in Python is relatively complex. For your given example, this is the process for finding the value of obj.test:
First, look at the instance itself. In this case, the instance does not have a test attribute.
Look at the class which obj is an instance of: MyClass. MyClass does not have a test attribute.
Start looking at the classes in the method resolution order of MyClass. In this case, MyClass.__mro__ tells you to look first at Mixin2, then Mixin1, then object.
Mixin2 has a test attribute, so we finally have a match.
Mixin2.test is a function with a __get__ method, so that is called and the return value is used.
You can safely ignore step 5 here, and just assume that Mixin2.test is a method. One that is returned, you can see that obj.test() calls Mixin2.test.
This might help explain why I asked the question I did in a comment. There is a wide variety of ways you can fiddle with the program to get obj.test() to produce a call to Mixin1.test() instead. You can patch the object, you can fiddle with MyClass.__mro__, you can tweak what Mixin2.test actually does, etc.
Override the test method and call Mixin1.test explicitly:
class MyClass(Mixin2, Mixin1, BaseClass):
def test(self):
Mixin1.test(self)

Python factory method with external function

I've read this SO discussion about factory methods, and have an alternate constructor use case.
My class looks like this:
class Foo(object):
def __init__(self, bar):
self.bar = bar
#classmethod
def from_data(cls, datafile):
bar = datafile.read_bar()
# Now I want to process bar in some way
bar = _process_bar(bar)
return cls(bar)
def _process_bar(self, bar)
return bar + 1
My question is, if a #classmethod factory method wants to use a function in its code, should that function (_proces_bar) be:
A #classmethod, which seems a bit weird because you won't ever call it like Foo._process_bar()
A method outside of the class Foo but in the same .py file. I'd go with this, but it seems kind of weird. Will those methods always be available to an instance of Foo, regardless of how it was instantiated? (e.g. what if it's saved to a Pickle then reloaded? Presumably methods outside the class will then not be available!)
A #staticmethod? (see 1. This seems weird)
Something else? (but not this!)
The "right solution" depends on your needs...
If the function (_process_bar) needs an access to class Foo (or the current subclass of...) then you want a classmethod - which should be then called as cls._process_bar(), not Foo._process_bar().
If the function doesn't need an access to the class itself but you still want to be able to override it in subclasses (IOW : you want class-based polymorphism), you want a staticmethod
Else you just want a plain function. Where this function's code lives is irrelevant, and your import problems are othogonal.
Also, you may (or not, depending on your concrete use case) want to allow for more flexiblity using a callback function (possibly with a default), ie:
def process_bar(bar):
return bar + 1
class Foo(object):
#classmethod
def from_data(self, datafile, processor=process_bar):
bar = datafile.read_bar()
bar = processor(bar)
return cls(bar)

Is it safe to make two class objects with the same name?

It's possible to use type in Python to create a new class object, as you probably know:
A = type('A', (object,), {})
a = A() # create an instance of A
What I'm curious about is whether there's any problem with creating different class objects with the same name, eg, following on from the above:
B = type('A', (object,), {})
In other words, is there an issue with this second class object, B, having the same name as our first class object, A?
The motivation for this is that I'd like to get a clean copy of a class to apply different decorators to without using the inheritance approach described in this question.
So I'd like to define a class normally, eg:
class Fruit(object):
pass
and then make a fresh copy of it to play with:
def copy_class(cls):
return type(cls.__name__, cls.__bases__, dict(cls.__dict__))
FreshFruit = copy_class(fruit)
In my testing, things I do with FreshFruit are properly decoupled from things I do to Fruit.
However, I'm unsure whether I should also be mangling the name in copy_class in order to avoid unexpected problems.
In particular, one concern I have is that this could cause the class to be replaced in the module's dictionary, such that future imports (eg, from module import Fruit return the copied class).
There is no reason why you can't have 2 classes with the same __name__ in the same module if you want to and have a good reason to do so.
e.g. In your example from module import Fruit -- python doesn't care at all about the __name__ of the class. It looks in the module's globals for Fruit and imports what it finds there.
Note that, in general, this approach isn't great if you're using super (although the same can be said for class decorators ...):
class A(Base):
def foo(self):
super(A, self).foo()
B = copy_class(A)
In this case, when B.foo is called, it will end up calling super(A, self) which could lead to funky behaviour in a number of circumstances. . .

Categories

Resources