Something that I see people doing all the time is:
class Man(object):
def say_hi(self):
print('Hello, World.')
class ExcitingMan(Man):
def say_hi(self):
print('Wow!')
super(ExcitingMan, self).say_hi() # Calling the parent version once done with custom stuff.
Something that I never see people doing is:
class Man(object):
def say_hi(self):
print('Hello, World.')
class ExcitingMan(Man):
def say_hi(self):
print('Wow!')
return super(ExcitingMan, self).say_hi() # Returning the value of the call, so as to fulfill the parent class's contract.
Is this because I hang with all the wrong programmers, or is it for a good reason?
I'd argue that explicitly returning the return value of the super class method is more prudent (except in the rare case where the child wants to suppress it). Especially when you don't know what exactly super is doing. Agreed, in Python you can usually look up the super class method and find out what it does, but still.
Of course the people who wrote the other version might have written the parent class themselves and/or known that it has no return value. In that case they'd have decided to do without and explicit return statement.
In the example you give the parent class method has no explicit return statement and so is returning None. So in this one case there's no immediate issue. But note that should someone modify the parent to return a value we now probably need to modify each child.
I think your suggestion is correct.
I would suspect that, at least in this case, because the parent function doesn't return anything, there is no point in returning its result. In general though, when the parent function does return something, I think it's a fine practice.
Really, whether or not you return what the super class does depends on exactly what you want the code to do. Do it if it's what you want and what's appropriate.
Related
The following code is of course totally pointless; it's not supposed to
do anything but illustrate what I'm confused about:
class func():
def __call__(self, x):
raise Exception("func.__call__ error")
def double(x):
return 2*x
doubler = func()
doubler.__call__ = double
print doubler(2)
Can someone explain why this works? I would have expected that if I
wanted to set doubler.__call__ to something it would be a function
that takes two variables; I'd expect the code above to raise some sort
of too-many-parameters error. What gets passed to what, when?
(And then: How could I set doubler.__call__ to a function that
will actually have access to both "self" and "x"?)
(Context: An admittedly silly of-academic-interest example of why I might want to set an instance method this way: Each computable instance needs its own Approx method; creating a separate subclass for each instance seems "wrong"...)
Edit. Probably a better example, making it clear it has nothing
to do with magic-method magic:
class func():
def call(self, x):
raise Exception("func.call error")
def double(x):
return 2*x
doubler = func()
doubler.call = double
print doubler.call(2)
On third thought, probably the following is the right way to do it.
(i) Seems cleaner somehow, using the Python object model instead of
tinkering with it (ii) even 24 hours ago with my then much cruder
understanding I would have expected it to work; somehow in this
version it simply seems to make sense to me that the function passed
to the constructor should take only one variable (iii) it seems to
work regardless of whether I inherit from object, which I think means it would also work in 3.0.
class func3(object):
def __init__(self, f):
self.f = f
def __call__(self, x):
return self.f(x)
def double(x):
return 2.0*x
f3=func3(double)
print f3(2)
When you assign to doubler.__call__, you're binding an function to an instance attribute. This hides the class attribute of the same name that was created in the class statement.
Python's method binding only kicks in when you are looking up a class attribute via an instance. If the attribute's value is a descriptor (which functions are), then the descriptor's __get__ method gets called with appropriate parameters. For a function object, that binds the method to the instance (so self gets passed in automatically as the first argument).
Your first example wouldn't actually work in Python 3, only in Python 2. That's because in Python 2 you're creating an "old-style" class, which does all its method lookups on the instance. In new-style classes (which you can get in Python 2 by inheriting from object, or by default in Python 3), __special__ methods, when they're invoked by the interpreter (e.g. when you do doubler(2) to run doubler.__call__) are looked up only in the class, not in the instance's attributes. So your first example won't work with a new-style class, but the version that uses a normal method (call instead of __call__) would be fine.
This is something between an answer to the question and a continuation of the question. I was kindly referred to another thread where more or less the same question was answered. I didn't follow the answers in that thread very well, being ignorant of the things the people there are talking about, hence the Question: Is what I say below correct? (If yes then this is an answer to the question above; if no I'd appreciate someone explaining why not...)
(i) Since I assign a function to an instance of func instead of to the class, it is now an "instance method", as opposed to a "class method".
(ii) And that's why it's not passed the instance as the first parameter; that happens with class methods but not with instance methods...
I want to be able to recycle a method from a parent class that uses a second method in that parent class. However the second method is overridden in the child class. I want the recycled parent method to use the new overridden second method when it is called from the child class. An example of how I want it to work will hopefully make this clearer:
class Parent:
def method1(self, num):
return num**2
def method2(self, list_size):
return [self.method1(i) for i in range(list_size)] #List of squares
class Child(Parent):
def method1(self, num): #Overrides corresponding parent method
return num**3
def method2(self, list_size):
return super().method2(list_size) #Returns a list of cubes using child's method 1.
Is this possible in python3? Or will calling the parent's method 2 also use the parent's method 1? I'm hoping to reuse large parts of a parent class as the child class differs in only a few ways. The methods nesting like that in the parent class make it a lot more general.
Thanks!
EDIT: I forgot to test it with simple code! It does work like I wanted if anyone was wondering!
Short answer: yes.
Just tried a slightly modified version of your code with prints.
class Parent:
def method1(self):
print("Parent method1")
def method2(self):
print("Parent method2")
self.method1()
class Child(Parent):
def method1(self):
print("Child method1")
def method2(self):
print("Child method2")
super().method2()
c = Child()
c.method2()
This is the output:
Child method2
Parent method2
Child method1
As you can see, the method1 used is the child one.
Yes, this works the way you want it to.
You can easily test this yourself. Unless you pass in nothing but 0s and 1s, it should be pretty obvious whether they're getting squared or cubed.
And, in cases where it's less obvious, just add a debugger breakpoint to Child.method1 and Parent.method1 and see which one gets hit. Or add print(f'Child1.method({self}, {num})') to the method and see if it gets printed out.
If you're coming from another language with C++ OO semantics instead of Smalltalk OO semantics, it may help to think of it this way: Every method is always virtual.
Are __init__ calls virtual? Yes.
What if you call a method during __init__? Yes.
What if you call a method inside a super call? Yes.
What about a #classmethod? Yes.
What if…? Yes.
The only exceptions are when you go out of your way to explicitly tell Python not to make a virtual function call:
Calls on super() use the implementation from the next class in the MRO chain, because that's the whole point of super.
If you grab a parent's bound method and call that, like Parent.method1(self, num), you obviously get Parent.method1, because that's the whole point of bound methods.
If you go digging into the class dicts and run the descriptor protocol manually, you obviously get whatever you do manually.
If you're not trying to understand Python in terms of Java, and just want a deeper understanding of Python on its own terms, what you need to understand is what happens when you call self.method1(i).
First, self.method1 doesn't know or care that you're going to call it. It's an attribute lookup, just like, say, self.name would be.
The way Python resolves this is described in the Descriptor HOWTO, but an oversimplified version looks like this:
Does self.__dict__ have anything named method1? No.
Does type(self).__dict__ have anything named method1? Yes.
Return type(self).__dict__['method1'].__get__(self).
If that second lookup failed, Python would loop over type(self).mro() and do the same test for each one. But here, that doesn't come up. type(self) is always going to be Child for an instance of Child, and Child.__dict__['method1'] exists, so it binds Child.method to self, and the result is what self.method1 means.
I have quite complex system with python 2.7. Often in subclasses I need to override methods of parent class with just 'pass' like:
class Parent():
def some_method(self, data):
# do something to data here
....
class Child(Parent):
def some_method(self, data):
# Do not touch data, it should remain unchanged
pass
So my question: is there a way to test that method is overridden with a 'pass' statement? I mean an abstract test, given that it doesn't know anything about 'data': all it has is Child class, method name and that's it.
Of course, I can test that after running some_method data is not changed, but given the complexity of the system I have, there are too many places to check if something was affected, so I'm looking for an abstract solution.
UPD yes, this design is way far from perfect, I know, but can't help it, it's a legacy issue, so let's please leave the system design discussion aside except for one note: don't design your systems like this:)
So the solution I've come so far is (not totally abstract, but abstract enough for my case):
In test case call the subclass method intentionally passing it wrong-typed values, like None in my case:
def test_method_pass_statement(self):
test_class = Child()
try:
# If method isn't overridden, this should raise exception
# but check for your case if None doesn't raise exception
test_class.some_method(None)
except <Exception_type>:
# Customise error and message the way you want
raise
If the method is overridden with pass, it would consume whatever you pass it, given the number of arguments is correct.
I have a one to many class inheritance structure as follows:
class SuperClass:
def func1():
print 'hello'
def func2():
print 'ow'
class SubClass1(SuperClass):
def func1():
print 'hi'
class SubClass2(SuperClass):
def func1():
print 'howdy'
...
I want to add functionality to class A so that I can use it when I create classes B and C (etc), but I cannot edit the code for class A directly. My current solution is:
def func3():
print 'yes!'
SuperClass.func3 = func3
Is there a better and/or more pythonic way to achieve this?
This is called "monkeypatching", and is perfectly reasonable in some cases.
For example if you have to use someone else's code (that you can't modify) that depends on SuperClass, and you need to change that code's behavior, your only real choice is to replace methods on SuperClass.
However, in your case, there doesn't seem to be any good reason to do this. You're defining all of the subclasses of SuperClass, so why not just add another class in between?
class Intermediate(SuperClass):
def func3():
pass
class SubClass1(Intermediate):
def func1():
print 'hi'
This isn't good enough for "functionality that should have been in SuperClass but wasn't" if other code you can't control needs that functionality… but when it's only your code that needs that functionality, it's just as good, and a lot simpler.
If even the subclasses aren't under your control, often you can just derive a new class from each one that is. For example:
class Func3Mixin(object):
def func3():
pass
class F3SubClass1(SubClass1, Func3Mixin):
pass
class F3SubClass2(SubClass2, Func3Mixin):
pass
Now you just construct instances of F3SubClass1 instead of SubClass1. Code that was expecting a SubClass1 instance can use an F3SubClass1 just fine. And Python's duck typing makes this kind of "mixin-oriented programming" especially simple: inside the implementation of Func3Mixin.func3, you can use attributes and methods of SuperClass, despite the fact that Func3Mixin itself isn't statically related to SuperClass in any way, because you know that any runtime object that is a Func3Mixin will also be a SuperClass.
Meanwhile, even when monkeypatching is appropriate, it isn't necessarily the best answer. For example, if you're patching to work around a bug in some third-party code, that code has a nice license and a source repository that makes it easy to maintain your own patches, you can just fork it, create a fixed copy, and use that instead of the original.
Also, it's worth pointing out that none of your classes are actually usable as written—any attempt to call any of the methods will raise a TypeError because they're missing the self argument. But the way you've monkeypatched in func3, it will fail in exactly the same way as func1. (And the same is true for the alternatives I sketched above.)
Finally, all of your classes here are classic classes rather than new-style, because you forgot to make SuperClass inherit from object. If you can't change SuperClass, of course, that's not your fault—but you may want to fix it anyway by making your subclasses (or Intermediate) multiply inherit from object and SuperClass. (If you've been paying attention: yes, this means you can mix-in new-style-classness. Although under the covers you have to understand metaclasses to understand why.)
Ie, if I have a class MyClass, and I do super(MyClass).init, how can I tell which class's init is actually going to be called?
Some code to illustrate:
class MyClass(OtherClass, ThirdClass):
def __init__(self):
mySuper = super(MyClass)
if mySuper == SomeClass:
# doesn't work - mySuper is a super object (not a normal class object)
pass
if mySuper.__init__ == SomeClass.__init__:
# doesn't work - mySuper.__init__ is a super-method-wrapper object
pass
if mySuper.__thisclass__ == SomeClass:
# doesn't work - __thisclass__ is set to be MyClass, not the "parent" class
pass
Any ideas?
EDIT:
If I hadn't already awarded points here, I would probably delete this question, as it's not really very useful as posed, and could potentially encourage bad habits.
As sven-marnach notes, I'm using the one-arg version, super(MyClass), instead of the more useful two-arg version, super(MyClass, self)... and now, I have no idea why I would have wanted to do that. My best guess is that I was still unclear on the proper usage of super at the time.
If you're using the two-arg version, then the second check works - with the caveat that you would need to get .im_func, ie:
if mySuper.__init__.im_func == SomeClass.__init__.im_func:
See Determine whether super().__new__ will be object.__new__ in Python 3? for an example of why this sort of check is useful...
You can extract the wrapped class using
mro = my_super.__self_class__.mro()
wrapped_class = mro[mro.index(my_super.__thisclass__) + 1]
This looks complex, but I also think it is rather pointless to do this.
Edit: I just noticed you don't pass self to super(). For that case, you could use
wrapped_class = my_super.__thisclass__.mro()[1]
The question that remains is: why would you want to do this?