Add methods to class dynamically when they are called - python

I want to make a script that does something like:
class Foo():
def magic_method(...):
return called_function
a = Foo()
a.bar()
> bar
a.foo()
> foo
So basically, if the method doesn't exist in Foo(), don't return an error, but accept it and use it as a string to do other stuff.
Is this possible in python?

You can override __getattr__ magic method:
class Foo():
def __getattr__(self, name):
return lambda: name
Now:
>>> a = Foo()
>>> a.something()
'something'
You need to return lambda so calling .something() returns the name of the method (and not just .something).

Related

Python: Check if a method uses #staticmethod [duplicate]

assume following class definition:
class A:
def f(self):
return 'this is f'
#staticmethod
def g():
return 'this is g'
a = A()
So f is a normal method and g is a static method.
Now, how can I check if the funcion objects a.f and a.g are static or not? Is there a "isstatic" funcion in Python?
I have to know this because I have lists containing many different function (method) objects, and to call them I have to know if they are expecting "self" as a parameter or not.
Lets experiment a bit:
>>> import types
>>> class A:
... def f(self):
... return 'this is f'
... #staticmethod
... def g():
... return 'this is g'
...
>>> a = A()
>>> a.f
<bound method A.f of <__main__.A instance at 0x800f21320>>
>>> a.g
<function g at 0x800eb28c0>
>>> isinstance(a.g, types.FunctionType)
True
>>> isinstance(a.f, types.FunctionType)
False
So it looks like you can use types.FunctionType to distinguish static methods.
Your approach seems a bit flawed to me, but you can check class attributes:
(in Python 2.7):
>>> type(A.f)
<type 'instancemethod'>
>>> type(A.g)
<type 'function'>
or instance attributes in Python 3.x
>>> a = A()
>>> type(a.f)
<type 'method'>
>>> type(a.g)
<type 'function'>
To supplement the answers here, in Python 3 the best way is like so:
import inspect
class Test:
#staticmethod
def test(): pass
isstatic = isinstance(inspect.getattr_static(Test, "test"), staticmethod)
We use getattr_static rather than getattr, since getattr will retrieve the bound method or function, not the staticmethod class object. You can do a similar check for classmethod types and property's (e.g. attributes defined using the #property decorator)
Note that even though it is a staticmethod, don't assume it was defined inside the class. The method source may have originated from another class. To get the true source, you can look at the underlying function's qualified name and module. For example:
class A:
#staticmethod:
def test(): pass
class B: pass
B.test = inspect.getattr_static(A, "test")
print("true source: ", B.test.__qualname__)
Technically, any method can be used as "static" methods, so long as they are called on the class itself, so just keep that in mind. For example, this will work perfectly fine:
class Test:
def test():
print("works!")
Test.test()
That example will not work with instances of Test, since the method will be bound to the instance and called as Test.test(self) instead.
Instance and class methods can be used as static methods as well in some cases, so long as the first arg is handled properly.
class Test:
def test(self):
print("works!")
Test.test(None)
Perhaps another rare case is a staticmethod that is also bound to a class or instance. For example:
class Test:
#classmethod
def test(cls): pass
Test.static_test = staticmethod(Test.test)
Though technically it is a staticmethod, it is really behaving like a classmethod. So in your introspection, you may consider checking the __self__ (recursively on __func__) to see if the method is bound to a class or instance.
I happens to have a module to solve this. And it's Python2/3 compatible solution. And it allows to test with method inherit from parent class.
Plus, this module can also test:
regular attribute
property style method
regular method
staticmethod
classmethod
For example:
class Base(object):
attribute = "attribute"
#property
def property_method(self):
return "property_method"
def regular_method(self):
return "regular_method"
#staticmethod
def static_method():
return "static_method"
#classmethod
def class_method(cls):
return "class_method"
class MyClass(Base):
pass
Here's the solution for staticmethod only. But I recommend to use the module posted here.
import inspect
def is_static_method(klass, attr, value=None):
"""Test if a value of a class is static method.
example::
class MyClass(object):
#staticmethod
def method():
...
:param klass: the class
:param attr: attribute name
:param value: attribute value
"""
if value is None:
value = getattr(klass, attr)
assert getattr(klass, attr) == value
for cls in inspect.getmro(klass):
if inspect.isroutine(value):
if attr in cls.__dict__:
bound_value = cls.__dict__[attr]
if isinstance(bound_value, staticmethod):
return True
return False
Why bother? You can just call g like you call f:
a = A()
a.f()
a.g()

Get all the class types referenced within a function or class

I'm working on a code analyzer and I'm trying to identify all the class types referenced within a function or class in Python.
For example say I have this class:
import collections
Bar = collections.namedtuple('Bar', ['bar'])
Baz = collections.namedtuple('Baz', ['baz'])
class Foo(object):
def get_bar(self):
return Bar(1)
def get_baz(self):
return Baz(2)
I'm looking for a way I can get types of the functions and classes. Something like this:
print(get_types(Foo.get_bar)) # ['Bar']
print(get_types(Foo.get_baz)) # ['Baz']
print(get_types(Foo)) # ['Bar','Baz']
One solution could involve using type annotations. Setting the return value of get_bar() to Bar and the return value of get_baz() to Baz, you could write get_types() as below...
import inspect
import collections
Bar = collections.namedtuple('Bar', ['bar'])
Baz = collections.namedtuple('Baz', ['baz'])
class Foo(object):
def get_bar(self) -> Bar:
return Bar(1)
def get_baz(self) -> Baz:
return Baz(2)
def get_types(obj):
if inspect.isclass(obj):
methods = [method for method in dir(obj)
if callable(getattr(obj, method)) and not method.startswith('_')]
return [get_types(getattr(obj, method)) for method in methods]
if callable(obj):
return [obj.__annotations__['return'].__name__]
def main():
print(get_types(Foo.get_bar)) # ['Bar']
print(get_types(Foo.get_baz)) # ['Baz']
print(get_types(Foo)) # ['Bar','Baz']
if __name__ == '__main__':
main()
In get_types(obj), if obj contains an instance of a class, you can select out the non private methods of that class and return get_types() on each of these. If obj contains a function, then we just return the return attribute of that function.

python standalone function return object instance that called it

I have a very strange problem.
I need to return a class object to call a function that is supposed to return the class object that called it. I know, I know. Just think of it as a contrived exercise, though for me it is a very real need.
def baz():
# return the object instance that calls me.
class Foo():
def bar(self, func):
return func() # should return the Foo object but how???
new_foo = Foo()
new_foo_instance = new_foo.bar(baz)
is it possible to write anything in baz() that will return the object that called it?
EDIT:
to answer the comments:
I have tried to use inspect, but with no success, I even looked at the entire stack but I cannot find an entry that matches the new_foo object:
new_foo looks like this when I printed it out: <__main__.Foo object at 0x0000029AAFC4C780>
when I printed out the entire stack that entry was not found within it:
def baz():
print(inspect.stack())
return inspect.stack() #[1][3]
>>> [FrameInfo(frame=<frame object at 0x0000029AADB49648>, filename='return_caller.py', lineno=5, function='baz', code_context=[' print(inspect.stack())\n'], index=0), FrameInfo(frame=<frame object at 0x0000029AAD8F0DE8>, filename='return_caller.py', lineno=11, function='bar', code_context=[' return func() # should return the Foo object but how???\n'], index=0), FrameInfo(frame=<frame object at 0x0000029AAD8AC588>, filename='return_caller.py', lineno=19, function='<module>', code_context=['new_foo_instance = new_foo.bar(baz)\n'], index=0)]
So I am not trying to get it to return a new instance of Foo, but actually the exact same instance as new_foo.
Use inspect:
import inspect
def baz():
frame_infos = inspect.stack() # A list of FrameInfo.
frame = frame_infos[1].frame # The frame of the caller.
locs = frame.f_locals # The caller's locals dict.
return locs['self']
class Foo():
def bar(self, func):
return func()
f1 = Foo()
f2 = f1.bar(baz)
print(f1)
print(f2)
print(f2 is f1) # True
Or cheat:
def baz():
return getattr(baz, 'self', None)
class Foo():
def bar(self, func):
func.self = self # Functions can be a place to store global information.
return func()
The above answer is perfect and this is another way to fulfill your need.
import sys
import inspect
def baz():
"""
Return the object instance whose method calls me
"""
for item in dir(sys.modules[__name__]):
elem = eval(item)
if inspect.isclass(elem):
foo_instance = elem()
break
return foo_instance
class Foo():
"""
Foo class
"""
def bar(self, func):
return func() # should return the Foo object but how???
# Instantiation and calling
new_foo = Foo()
new_foo_instance = new_foo.bar(baz)
print(new_foo_instance) # <__main__.Foo object at 0x0000015C5A2F59E8>
print(type(new_foo_instance)) # <class '__main__.Fo
# E:\Users\Rishikesh\Projects\Python3\try>python Get_caller_object_final.py
# <__main__.Foo object at 0x0000015C5A2F59E8>
# <class '__main__.Foo'>
References ยป
How can I get a list of all classes within current module in Python?
Python: get only classes defined in imported module with dir()?

Python: How to fix, if a static class variable gets a different function reference pointer?

I wonder why my class calls the referenced function (assigned to a static class variable) with with an argument. If I assign the function reference to a normal class variable it works like expected.
Here my example code:
# This function is not editable, because it's imported from an API
def getStuff():
print "I do my stuff!!!"
class foo(object):
GET_STUFF = getStuff
def __init__(self):
print "static var: ",self.GET_STUFF
self.GET_STUFF()
print "outer func: ",getStuff
foo()
This comes up with the following error:
outer func: <function getStuff at 0x0000000003219908>
static var: <bound method foo.getStuff of <__main__.foo object at 0x00000000030AB358>>
Traceback (most recent call last):
File "C:/example.py", line 13, in <module>
foo()
File "C:/example.py", line 10, in __init__
self.GET_STUFF()
TypeError: getStuff() takes no arguments (1 given)
To fix this issue I point the function reference inside the constructor to the class variable:
class foo(object):
def __init__(self):
self.GET_STUFF = getStuff
print "static var: ",self.GET_STUFF
self.GET_STUFF()
The result is like expected and works fine:
outer func: <function getStuff at 0x000000000331F908>
static var: <function getStuff at 0x000000000331F908>
I do my stuff!!!
But:
I wanted to use a static class variable, because it makes it easy to read and simple to setup for different API's. So in the end I would come up with some wrapper classes like in the following:
from API01 import getStuff01
from API02 import getStuff02
# bar calculates stuff object from the API (it calls GET_STUFF)
# and stores the object into self.stuff
import bar
class foo01(bar):
GET_STUFF = getStuff01
def DoSomething(self, volume):
self.stuff.volume = volume
class foo02(bar):
GET_STUFF = getStuff02
def DoSomething(self, volume):
self.stuff.volume = volume
# [...] and so on..
Is there a way to bring it to work in the way I want to setup my wrapper classes, or do I really have to define a constructor for each wrapper class?
Thanks
The reason for the error is that
self.GET_STUFF()
actually means
tmp = getattr(self, 'GET_STUFF')
tmp(self)
That means these two classes are equivalent:
def foo(self): pass
class Foo(object):
a = foo
class Bar(object):
def a(self): pass
In both cases, a function object is added to the class as a member and that means for Python that the function wants self as the first parameter.
To achieve what you want:
from API01 import getStuff01
def wrapper01(self):
getStuff01()
class foo01(object):
GET_STUFF = wrapper01
Just for extend Aaron answer, if you want to have static methods you can use the #staticmethod decorator:
class Calc:
#staticmethod
def sum(x, y):
return x + y
print (Calc.sum(3,4))
>>> 7
I thought already that my object is calling the referenced function with itself as argument. After a bit of research I finally found a solution. When I use a class variable to point to a function it will not referencing a direct pointer. It references the function as a bounced method of it's class. To get rid of the default call of calling a method with getattr, the call function of getattr for the class itself has to be overwritten (in this case the class bar, because foo (the wrapper classes) inherits the functionalities of bar:
import inspect
class bar(object):
GET_STUFF = None
def __getattribute__(self, name):
attr = object.__getattribute__(self,name)
if name == "GET_STUFF":
# Check: is method and is bounced?
if inspect.ismethod(attr) and attr.im_self is not None:
return attr.__func__
return attr
getattr of bar is now pointing to the original function reference, but only for the class variable GET_STUFF, because I want to leave the default functionality for the rest of my variables.
So, when I now execute the following:
class foo(bar):
GET_STUFF = getStuff
def __init__(self):
print "inner func: ",self.GET_STUFF
self.GET_STUFF()
foo()
I get the expected result and can write my wrappers without producing additional code for each module with those wrapper classes:
outer func: <function getStuff at 0x00000000034259E8>
inner func: <function getStuff at 0x00000000034259E8>
I do my stuff!!!

Ways to set per instance __call__?

What I want to do is something like:
class Foo(object):
def __init__(self):
pass
def f(self):
print "f"
def g(self):
print "g"
# programatically set the "default" operation
fer=Foo()
fer.__call__=fer.f
# a different instance does something else as its
# default operation
ger=Foo()
ger.__call__=ger.g
fer() # invoke different functions on different
ger() # objects depending on how they were set up.
But as of 2.7 (which I'm currently using) I can't do this, the attempts at fer()
raise an exception.
Is there a way to, in effect, set a per instance __call__ method?
The normal stuff with types.MethodType unfortunately doesn't work here since __call__ is a special method.
From the data model:
Class instances are callable only when the class has a __call__() method; x(arguments) is a shorthand for x.__call__(arguments).
This is slightly ambiguous as to what is actually called, but it's clear that your class needs to have a __call__ method.
You'll need to create some sort of hack:
class Foo(object):
def __init__(self):
pass
def f(self):
print "f"
def g(self):
print "g"
def __call__(self):
return self.__call__()
f = Foo()
f.__call__ = f.f
f()
g = Foo()
g.__call__ = g.g
g()
Careful with this though, it'll result in an infinite recursion if you don't set a __call__ on an instance before you try to call it.
Note that I don't actually recommend calling the magic attribute that you rebind __call__. The point here is to demonstrate that python translates: f() into f.__class__.__call__(f) and so there's nothing you can do to change it on a per-instance basis. the class's __call__ will be called no matter what you do -- You just need to do something to change the behavior of the class's __call__ per-instance which is easily achieved.
You could use a setter type thing to actually create methods on your class (rather than simple functions) -- and of course that could be turned into a property:
import types
class Foo(object):
def __init__(self):
pass
def f(self):
print "f"
def g(self):
print "g"
def set_func(self,f):
self.func = types.MethodType(f,self)
def __call__(self,*args,**kwargs):
self.func(*args,**kwargs)
f = Foo()
f.set_func(Foo.f)
f()
def another_func(self,*args):
print args
f.set_func(another_func)
f(1,2,3,"bar")
You might be trying to solve the wrong problem.
Since python allows procedural creation of classes you could write code like that:
>>> def create_class(cb):
... class Foo(object):
... __call__ = cb
... return Foo
...
>>> Foo1 = create_class(lambda self: 42)
>>> foo1 = Foo1()
>>> foo1()
>>> Foo2 = create_class(lambda self: self.__class__.__name__)
>>> foo2 = Foo2()
>>> foo2()
Please note thought that Foo1 and Foo2 do not have a common base class in this case. So isinstance and issubclass will not work. If you need them to have a common base class I would go for the following code:
>>> class Foo(object):
... #classmethod
... def create_subclass(cls, cb):
... class SubFoo(cls):
... __call__ = cb
... return SubFoo
...
>>> Foo1 = Foo.create_subclass(lambda self: 42)
>>> foo1 = Foo1()
>>> foo1()
>>> Foo2 = Foo.create_subclass(lambda self: self.__class__.__name__)
>>> foo1 = Foo2()
>>> foo2()
'Foo'
>>> issubclass(Foo1, Foo)
True
>>> issubclass(Foo2, Foo)
True
I really like the second way as it provides a clean class hierarchy and looks quite clean to me.
Possible solution:
class Foo(object):
def __init__(self):
self._callable = lambda s: None
def f(self):
print "f"
def set_callable(self, func):
self._callable = func
def g(self):
print "g"
def __call__(self):
return self._callable()
d = Foo()
d.set_callable(d.g)

Categories