Python : Assert that variable is instance method? - python

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.

Related

Make class method able to check if it has been called

Here is a nice way to make a function object self-aware and able to check if it has been called (per this answer):
def example():
example.has_been_called = True
pass
example.has_been_called = False
example()
#Actual Code!:
if example.has_been_called:
print("foo bar")
How can I translate this solution to a class instance method?
I have tried this:
class Example:
def method_one(self):
self.method_one.has_been_called = True
pass
def method_two(self):
self.method_two.has_been_called = True
pass
example = Example()
example.method_one()
#Actual Code!:
if example.method_one.has_been_called:
print("foo bar")
but I keep getting:
> Traceback (most recent call last): File "c:\python
> projects\dog\tests.py", line 8, in <module>
> example.run() File "c:\python projects\dog\tests.py", line 4, in run
> self.run.has_been_called = True AttributeError: 'method' object has no attribute 'has_been_called'
Instance methods are in fact members of the class. If you want to know whether an method has been called on a specific object, you should make the indicator a boolean member of the instance:
class Example:
has_been_called = False
def run(self):
self.has_been_called = True
After example = Example(), example.has_been_called will be true if and only if example.run() has been called
If you want to know whether the method has been called on any object, you should make the indicator a member of the class:
class Example:
has_been_called = False
def run(self):
Example.has_been_called = True # global
# self.__class__.has_been_called = True # per sub_class
Here Example.has_been_called (also accessible for any instance from Example) would be true if and only if it has been called on one instance. The difference between the global and per sub-class way only matters if you have subclasses.
For a class method, the method already receives a class object and not an instance, so it would be:
class Example:
has_been_called = False
#classmethod
def run(cls):
Example.has_been_called = True # global
# cls.has_been_called = True # per sub_class
Beware in the per sub-class way, the attribute is set on the subclass, so you should examine it only from an instance.
Even if it is possible, you would have no reason to set an attribute on the method itself. The code should be:
class Example:
has_been_called = False
def run(self):
Example.run.has_been_called = True
but it would be non Pythonic.
Create a dict to store the functions that have been run.
class Example:
def __init__(self):
self.has_been_called = {}
def run(self):
self.has_been_called["run"] = True
example = Example()
example.run()
#Actual Code!:
try:
if example.has_been_called["run"]:
print("foo bar")
except KeyError:
pass
If you comment example.run(), no error is raised.
Using a dictionary also allows you to apply the same process to other methods without creating a ton of variables.
Every use of self.run produces a new instance of method, not the actual function bound to Example.run. You need a reference to the actual function, which you can get through the special name __class__, which here will refer to the static class Example. You also need to ensure the attribute is initialized (though you don't need any special magic here; the name run is bound to an ordinary function at this point and doesn't need to be used as an attribute).
class Example:
def run(self):
__class__.run.has_been_called = True
run.has_been_called = False
If instead you want to update an override in a subclass, use type(self) instead of __class__.
As you want each instance to have its own has_been_called flag, then you shouldn't attempt to define has_been_called on the method, as the method exists on the class object, not on the instance (self).
Instead, define it as an attribute on the instance object (self). So just skip the .run part:
class Example:
def run(self):
self.has_been_called = True
example = Example()
example.run()
#Actual Code!:
if example.has_been_called:
print("foo bar")
If you want to have a separate flag for each method, then use a dictionary:
from collections import defaultdict
class Example:
def __init__(self):
self.has_been_called = defaultdict(bool)
def run(self):
self.has_been_called["run"] = True
example = Example()
example.run()
if example.has_been_called["run"]:
print("foo bar")
Don't use .'s in variable names:
class Example:
def method_one(self):
self.method_one_has_been_called = True
def method_two(self):
self.method_two_has_been_called = True
example = Example()
example.method_one()
#Actual Code!:
if example.method_one_has_been_called:
print("foo bar")
Output:
foo bar

In Python can isinstance() be used to detect a class method?

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.

Checking whether function contains pass

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()

Self Attributes Live in Function Pointer?

Suppose I have a simple python3 class like so:
class Test():
def __init__(self):
self.a = 'a'
def checkIsA(self, checkA):
return self.a == checkA
And some further code such as:
def tester(func, item):
return func(item)
testObject = Test()
print(tester(testObject.checkIsA, 'a')) # prints True
How is the function pointer(?) checkIsA still aware of its class member variables (defined by self) when used independently by another function?
I want to use this functionality in a program I'm writing but I'm worried I'm not understanding these semantics correctly.
testObject.checkIsA is what's called a bound method - it remembers the instance it was taken from so that its self attribute gets automatically populated by that instance.
You can easily check a difference between a class function (unbound method) and an instance method (bound method), Python will quite happily tell you all the details:
testObject = Test()
print(Test.checkIsA) # <function Test.checkIsA at 0x00000000041236A8>
print(testObject.checkIsA) # <bound method Test.checkIsA of
# <__main__.Test object at 0x0000000004109390>>
You can simulate a call to testObject.checkIsA() directly through the unbound Test.checkIsA function by passing your instance, too, e.g.:
def tester(func, instance, item):
return func(instance, item)
testObject = Test()
print(tester(Test.checkIsA, testObject, 'a')) # prints True
Or, with functools.partial:
import functools
def tester(func, item):
return func(item)
testObject = Test()
print(tester(functools.partial(Test.checkIsA, testObject), 'a')) # prints True
And that's exactly what a bound instance method does for you in the back by supplementing the first self attribute with its stored __self__ value. You can check that, too:
testObject = Test()
print(testObject.checkIsA.__self__ is testObject) # True

Python - If a function is a first class object, can a function have a method?

I have a class which maintains a list of functions. These functions are just objects sitting in a queue and every so often the class pops one off and executes it. However, there are times when I would like to print out this list, and I'm imagining code as follows:
for function in self.control_queue:
print function.summarize()
if function.ready():
function()
In other words, I would like to call methods called summarize() and ready(), that I want to define somewhere, on these function objects. Also, I would like to be able to toss anonymous functions on this queue - i.e., generate everything dynamically.
you can make it a class and define __call__
class MyClass():
def summarize(self):
#summarize stuff
pass
def ready(self):
#ready stuff
pass
def _call__(self):
#put the code here, for when you call myClass()
pass
How you run it:
function = MyClass()
print function.summarize()
if function.ready():
function()
You have a couple possible approaches.
You could add the definitions to functions.
def foo():
pass
# later..
foo.summarize = lambda: "To pair with bar"
foo.ready = lambda: True
You could create class objects to wrap the function operation.
class Func():
def summarize(self):
return "Function!"
def ready(self):
return self.ready
def __call__(self):
# Act as a function
Or you can have a function which checks the function label for these capabilities.
def summarize_func(func):
return func.__name__ # Or branch here on specific names/attributes
def ready_func(func):
return True # Or branch on names/attributes
Finally to accommodate anonymous functions you can check for prescience of these attributes and return optimistically if the attributes are absent. Then you can combine above approaches with something that will work on any function.
def summarize_func(func):
if hasattr(func, summarize):
return func.summarize()
else:
# Note this will just be '<lambda>' for anonymous funcs
return func.__name__
def ready_func(func):
if hasattr(func, ready):
return func.ready()
else:
return True
One option is to implement function as a class instance:
class Function(object):
def summarize(self): pass # some relevant code here
def __call__(self): pass # and there
and use it later with
function = Function()
With __call__ magic method implemented, this function becomes a callable object.
For sure, you can assign attributes to functions, but it is rather obscure and conterintuitive:
>>> def summ(a): return sum(a)
...
>>> def function(a): return a
...
>>> function.sum=summ
>>> function.sum([1,2,3])
6

Categories