I have one parent class P and several child classes. The parent class contains the method doSomething(x) defined only as:
def doSomething(self, x):
pass
Now, some of P's subclasses may have implemented this method, and some have not. Is there any way I can check if doSomething(x) is going to do nothing but pass, at runtime (e.g. if it is implemented, execute it, if not, skip it)?
There is no need to do anything here other than just calling doMethod() on the instance. Calling a no-op method is not so costly that detecting when a child class has implemented an override is going to save you anything.
So your number 1 option is to just call the method, and don't worry about it being an empty method. That's what pass is for, to give you an easy parent class method that does nothing.
Next, you state
Parent class contains method doSomething(x)
You can use this to detect if you have that method still; the underlying function for the bound method is going to be the same object:
hook = instance.doSomething
if hook.__func__ is ParentClass.doSomething:
# they didn't override the method, so nothing needs to be done.
Again, I'm not sure why anyone would want to do that, because that test is not going to save you anything over just using instance.doSomething().
Next, a function that consists solely of the statement pass will be compiled to the same bytecode, always; it's the same bytecode as return None. Compare the bytecode if you must know if a function is empty:
_RETURN_NONE = (lambda: None).__code__.co_code
def is_pass(f):
return f.__code__.co_code == _RETURN_NONE
This can be applied to any function or method that, in essence, only ever returns None and does nothing else.
Demo:
>>> class P:
... def doSomething(self, x):
... pass
...
>>> class Child1(P):
... def doSomething(self, x):
... print("We are doing something with {!r}!".format(x))
...
>>> class Child2(P):
... pass
...
>>> instance1 = Child1()
>>> instance2 = Child2()
>>> instance1.doSomething(42)
We are doing something with 42!
>>> instance2.doSomething(42)
>>> instance1.doSomething.__func__ is P.doSomething
False
>>> instance2.doSomething.__func__ is P.doSomething
True
>>> is_pass(instance1.doSomething)
False
>>> is_pass(instance2.doSomething)
True
>>> def unrelated_function():
... return 42
...
>>> def another_unrelated_function():
... pass
...
>>> is_pass(unrelated_function)
False
>>> is_pass(another_unrelated_function)
True
Note how is_pass() works on any function that uses pass.
Since your parent method is defined as
def doSomething(x):
pass
It does nothing - it is cheaper to just call it instead of verifying if it has been overriden or not. It will be automatically "skipped" because it does nothing in first place.
That said, if you really want to test for it, you can do something like this
if type(some_instance).doSomething is ParentClass.doSomething:
print('Not overriden')
else:
print('Function has been overriden, call it'):
some_instance.doSomething()
Related
How to determine if an object is a class method? Isn't it best practice to use isinstance(), and how does one make that work?
class Foo:
class_var = 0
#classmethod
def bar(cls):
cls.class_var += 1
print("class variable value:", cls.class_var)
def wrapper(wrapped: classmethod):
"""
Call the wrapped method.
:param wrapped (classmethod, required)
"""
wrapped()
Foo.bar()
wrapper(Foo.bar)
print("the type is:", type(Foo.bar))
print("instance check success:", isinstance(Foo.bar, classmethod))
Output:
class variable value: 1
class variable value: 2
the type is: <class 'method'>
instance check success: False
Process finished with exit code 0
If you just want to tell class methods apart from regular methods and static methods, then you can check this with inspect.ismethod(f).
class A:
def method(self): pass
#classmethod
def class_method(cls): pass
#staticmethod
def static_method(): pass
In the REPL:
>>> from inspect import ismethod
>>> ismethod(A.method)
False
>>> ismethod(A.class_method)
True
>>> ismethod(A.static_method)
False
If you prefer to do this with isinstance, then that's possible using typing.types.MethodType:
>>> from typing import types
>>> isinstance(A.method, types.MethodType)
False
>>> isinstance(A.class_method, types.MethodType)
True
>>> isinstance(A.static_method, types.MethodType)
False
Note that these tests will incorrectly identify e.g. A().method because really we're just testing for a bound method as opposed to an unbound function. So the above solutions only work assuming that you are checking A.something where A is a class and something is either a regular method, a class method or a static method.
As you know Python fills the first parameter of the classmethods with a reference to the class itself and it doesn't matter if you call that method from the class or the instance of the class. A method object is a function which has an object bound to it.
That object can be retrieved by .__self__ attribute. So you can simply check that if the .__self__ attribute is a class or not. If it is a class , it's class is type.
One way of doing it:
class Foo:
#classmethod
def fn1(cls):
pass
def fn2(self):
pass
def is_classmethod(m):
first_parameter = getattr(m, '__self__', None)
if not first_parameter:
return False
type_ = type(first_parameter)
return type_ is type
print(is_classmethod(Foo.fn1))
print(is_classmethod(Foo().fn1))
print("-----------------------------------")
print(is_classmethod(Foo.fn2))
print(is_classmethod(Foo().fn2))
output:
True
True
-----------------------------------
False
False
There is a ismethod function in inspect module that specifically checks that if the object is a bound method. You can use this as well before checking for the type of the first parameter.
NOTE: There is a caveat with the above solution, I'll mention it at the end.
Solution number 2:
Your isinstance solution didn't work because classmethod is a descriptor. If you want to get the actual classmethod instance, you should check the Foo's namespace and get the methods from there.
class Foo:
#classmethod
def fn1(cls):
pass
def fn2(self):
pass
def is_classmethod(cls, m):
return isinstance(cls.__dict__[m.__name__], classmethod)
print(is_classmethod(Foo, Foo.fn1))
print(is_classmethod(Foo, Foo().fn1))
print("-----------------------------------")
print(is_classmethod(Foo, Foo.fn2))
print(is_classmethod(Foo, Foo().fn2))
Solution number 1 caveat: For example if you have a simple MethodType object whose bound object is a different class like int here, this solution isn't going to work. Because remember we just checked that if the first parameter is of type type:
from types import MethodType
class Foo:
def fn2(self):
pass
fn2 = MethodType(fn2, int)
#classmethod
def fn1(cls):
pass
Now only solution number 2 works.
I want to call a function when the value of a subclassed int is requested. As far as I understand any attribute of a class is indirectly requested through __getattribute__, but it seems that immutable values of built-in classes are accessed by some other means, as overloading it does not affect return behavior. An explanation of why this is and how the return value is different from other class attributes (as well as a reference to documentation) would be greatly appreciated.
As an example, what would I put in my subclass of int to have the interactive interpreter return the following?:
>>> class IntSub(int):
... def before(self):
... print "value requested"
... def after(self):
... print "value returned"
...
>>> intsub1 = IntSub(42)
>>> intsub2 = intsub1
value requested
value returned
>>>
EDIT:
I have found a couple of ways of getting halfway to the solution I seek, although not without calling a method that return the object.
1: By adding get() to IntSub and calling it when making an assignment the first of my conditions for a solution are satisfied:
... def get(self):
... self.before()
... print "returning value"
... return self
...
>>> subint1 = SubInt(42)
>>> subint2 = subint1.get()
value requested
returning value
>>>
2: Using a function decorator on get() it is possible to also satisfy the second of my conditions by jumping through a few hoops:
... def decorate(decorating):
... def decorated(self):
... self.before()
... result = decorating(self)
... self.after()
... return result
... return decorated
... #decorate
... def get(self):
... print "returning value"
... return self
...
>>> intsub1 = IntSub(42)
>>> intsub2 = intsub1.get()
value requested
returning value
value obtained
>>>
Still, the issue remains that these approaches requires adding get(), which is not satisfying. I wonder whether the solution I want could be achieved using a class decorator or a different meta-class. Advice and suggestions are most welcome.
I'd like to know whether my method is called by the user directly or by another method. To make it less abstract:
class myclass():
def __init__(self, ...):
....
def method1(self, ...):
...
--- some if statement --
print "Hello"
return something
def callmethod(self, ...):
x = self.method1(...)
return x*2
myinstance = myclass(...)
myinstance.method1(...)
--> 'Hello'
myinstance.callmethod(...)
--> -
Hopefully my class makes clear what I'd like to do: When the user calls 'method1' the print statement shall be executed but if 'method1' is called by another method like 'callmethod' the print statement shall not be executed. Therefore I need 'some if statement' which checks whether 'method1' is called by the user directly or by another method. Thanks for you help!
No, and you don't want to do this.
If you want to change behaviour depending on the way a method is called, then you need to use a parameter. You can use a default value to make this simpler, for example:
def method1(self, do_print=True):
...
if do_print:
print "Hello"
return something
def callmethod(self, ...):
x = self.method1(do_print=False)
return x*2
Now, calling myinstance.method1() will print, whereas myinstance.callmethod() will not.
It's actually achievable using the python inspector, like e.g.:
import inspect
class myclass():
def __init__(self):
pass
def method1(self):
(frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1]
if function_name == '<module>':
print "Hello"
return 2
def callmethod(self):
x = self.method1()
return x*2
myinstance = myclass()
myinstance.method1()
myinstance.callmethod()
but I agree with Daniel it's not an elegant way to achieve the result as it hides some behaviour.
For further details also see: this post
I have two functions in my (first!) Python program that only differ by the class that must be instanciated.
def f(id):
c = ClassA(id)
...
return ...
def g(id):
c = ClassB(id)
...
return ...
To avoid repeated code, I would like to be able to write a single function that would somehow accept the class to instanciate as a parameter.
def f(id):
return f_helper(id, ... ClassA ...)
def g(id):
return f_helper(id, ... ClassB ...)
def f_helper(id, the_class):
c = ... the_class ... (id)
...
return ...
I'm pretty sure this is possible, but did not find how...
That works exactly as you have it (minus the ...s):
>>> class foo:
pass
>>> def make_it(cls):
return cls()
>>> make_it(foo)
<__main__.foo instance at 0x011D9B48>
This can be modified to take in/pass params to the class constructor as well if you like, but the idea is perfectly fine. Classes are first-class objects in Python.
You pretty much got it right, just drop the dots. Classes are first-class values, you can just refer to them, as to any object. f would be return f_helper(id, ClassA) and g would be return f_helper(id, ClassB).
You can pass a callable to a function; a class itself is a callable, the returned object being an instance of said class.
def f_helper(id, the_class):
c = the_class(id)
# ...
return # ...
How can one check if a variable is an instance method or not? I'm using python 2.5.
Something like this:
class Test:
def method(self):
pass
assert is_instance_method(Test().method)
inspect.ismethod is what you want to find out if you definitely have a method, rather than just something you can call.
import inspect
def foo(): pass
class Test(object):
def method(self): pass
print inspect.ismethod(foo) # False
print inspect.ismethod(Test) # False
print inspect.ismethod(Test.method) # True
print inspect.ismethod(Test().method) # True
print callable(foo) # True
print callable(Test) # True
print callable(Test.method) # True
print callable(Test().method) # True
callable is true if the argument if the argument is a method, a function (including lambdas), an instance with __call__ or a class.
Methods have different properties than functions (like im_class and im_self). So you want
assert inspect.ismethod(Test().method)
If you want to know if it is precisely an instance method use the following function. (It considers methods that are defined on a metaclass and accessed on a class class methods, although they could also be considered instance methods)
import types
def is_instance_method(obj):
"""Checks if an object is a bound method on an instance."""
if not isinstance(obj, types.MethodType):
return False # Not a method
if obj.im_self is None:
return False # Method is not bound
if issubclass(obj.im_class, type) or obj.im_class is types.ClassType:
return False # Method is a classmethod
return True
Usually checking for that is a bad idea. It is more flexible to be able to use any callable() interchangeably with methods.