Pass method to function using method name from string variable - python

I have a class with a constructor, two other methods, and a member list with the names of the two methods.
class Foo():
def __init__(self):
self.methods = ["self.foo", "self.bar"]
def foo(self):
print("foo")
return 0
def bar(self):
print("bar")
return 0
I have a function that takes a function as an argument, like this.
myFunction(func)
The function has global scope and would be used like this.
myFunction(self.foo)
I want to iterate through the items in the self.methods list and make a call to the function for each method name, but, as expected, a string is passed rather than the method itself. How do I pass the method like the above example, so like self.foo not "self.foo"?

From what I understand you can try this.
class Foo():
def __init__(self):
self.method=['foo','bar']
def foo(self):
print('foo')
def bar(self):
print('bar')
def run_all(self):
for m in self.method:
getattr(self,m)()
a=Foo()
a.run_all() # iterating through self.method and executing them
# foo
# bar

You want somwthing like this?
class Foo():
def __init__(self):
self.methods = [self.foo(), self.bar()]
def foo(self):
print("foo")
return 0
def bar(self):
print("bar")
return 0
foo_obj = Foo()

What about:
class Foo():
def __init__(self):
self.methods = self.foo, self.bar
def run_methods(self):
for method in self.methods:
print('Running method {}'.format(method.__name__))
method()
def foo(self):
print("foo")
return 0
def bar(self):
print("bar")
return 0
So, you can run your methods by calling run_methods. If you want to access their names as well, you can always do that via their respective __name__ methods, as above.
f = Foo()
f.run_methods()
# Output:
#
# Running method foo
# foo
# Running method bar
# bar
EDIT: As another person suggested, you should edit your question to describe in more detail what myFunction(fun) does. But inded, you should probably use a different approach than passing the actual names as strings.

Related

Python #cls.decorator

I want to create a python decorator that adds a certain function to a list of functions of that class that will, sometimes, be processed. Example code:
class A:
# every subclass should define _list
#classmethod
def decorator(cls, f):
# cls = B
cls._flist.append(f)
return f
#classmethod
def processFunctions(cls):
for f in cls._flist:
...
class B(A):
_flist = []
#B.decorator # Obviously not possible because cls is not defined (yet)
def foo(self):
print("Inside foo")
Is it possible to replicate this behaviour? The class (cls) should be passed when decorating the function, so I can't use the usual approach of creating a wrapper function that "unpacks" cls and the other arguments.
Ok, I think I've worked something out.
You need an instance of A, but as a class variable inside B.
Then each method will need an instance:
class A:
def __init__(self):
self._flist = []
def decorator(self, f):
self._flist.append(f)
return f
def processFunctions(self, other):
for f in self._flist:
f(other)
class B:
a=A()
#a.decorator
def foo(self):
print("Inside foo")
def processFunctions(self):
B.a.processFunctions(self)
b = B()
b.processFunctions()
Output
Inside foo
The following way is based on the implementation behavior of locals() in CPython but there is PEP 558 to make it documented standard behavior:
class A:
# every subclass should define _list
#staticmethod
def decorator(loc):
def registrator(f):
loc['_flist'].append(f)
return f
return registrator
#classmethod
def processFunctions(cls):
for f in cls._flist:
...
class B(A):
_flist = []
#decorator(locals())
def foo(self):
print("Inside foo")
Another approach, like the one the package ABC uses is making the decorator add a flag to the function, and then go through the functions of this class that have that flag activated.
class A:
#staticmethod
def decorator(f):
def wraps(f)
f.__processable__ = True
return f
return wraps
def processFunctions(self):
for d in dir(self):
try:
f = getattr(self, d).__func__
if f.__processable__:
f() # Or whatever we want to do with the function
# Instead of try/except we could use a bunch of nested ifs
except AttributeError:
pass

decorating methods causes method to pass in objects [duplicate]

This question already has answers here:
Python: Bind an Unbound Method?
(5 answers)
Closed 2 years ago.
Problem Description
I want to use a decorator to define a class method, but this requires me to manually give the 'self' object when I shouldn't have to provide that.
def func_wrapper(func):
def call_func(self):
print(self.a)
func()
return call_func
def func():
print('hello')
class test:
def __init__(self, func):
self.a = 0
self.call_func = func_wrapper(func)
mytest = test(func)
#mytest.call_func() #why does this not work?
mytest.call_func(mytest) #this works
I want to be able to mytest.call_func() but this doesn't work, presumably because call_func is bound to the func_wrapper and not mytest. If I manually pass in the object, e.g. mytest.call_func(mytest) this will work, but I don't want to have to manually pass in the object - this creates inconsistent call signatures if one inherited the test class and wrote their own call_func method, because then the method would be properly bound to the class.
Solution Attempts
def func_wrapper2(func, obj):
def call_func():
print(obj.a)
func()
return call_func
class test:
def __init__(self, func):
self.a = 0
self.call_func = func_wrapper2(func, self)
Here is a solution which lets me test.call_func() as desired, but here func_wrapper is not a true decorator as it requires to be passed in the object as well.
Looking on the web I found this blog https://medium.com/#vadimpushtaev/decorator-inside-python-class-1e74d23107f6 which talks about this issue and recommends to define the decorator either in a nested class, or a helper class. However their solution doesn't seem to work and I am getting type errors from passing the wrong number of inputs.
class test2:
class test2helper:
#classmethod
def func_wrapper(func):
print(self.a)
func()
def __init__(self):
self.a = 0
#test2helper.func_wrapper
def call_func(self):
print('hello')
So what is the proper way to use decorators with class methods? Every way to do it seems to cause different issues with how the self is being handled. I am going to use the func_wrapper2 design unless there is a better way to do this.
You are missing one level:
class test2:
class test2helper:
#classmethod
def decorator(cls, func): # this must return a function!
def func_wrapper(self): # ... namely this one, the "wrapper"
print(self.a) # ... where you have access to the instance
func(self) # ... upon which the method is called
return func_wrapper
def __init__(self):
self.a = 0
#test2helper.decorator
def call_func(self):
print('hello')
>>> t = test2()
>>> t.call_func()
0
hello
Or, if you want to go with the earlier attempt without nested class:
def decorator(func): # you are decorating an unbound function!
def func_wrapper(obj):
print(obj.a)
func(obj) # which has to be passed all the arguments
return func_wrapper
class test:
def __init__(self):
self.a = 0
#decorator
def call_func(self):
print('hello')
You can define a class decorator to do what you want:
def class_decorator(cls):
def call_func(self):
print(self.a)
return func()
setattr(cls, 'call_func', call_func)
return cls
def func():
print('hello')
#class_decorator
class Test:
def __init__(self, func):
self.a = 0
mytest = Test(func)
mytest.call_func() # This now works.
Output:
0
hello

Python : Set method attribute from within method

I am trying to make a python decorator that adds attributes to methods of a class so that I can access and modify those attributes from within the method itself. The decorator code is
from types import MethodType
class attribute(object):
def __init__(self, **attributes):
self.attributes = attributes
def __call__(self, function):
class override(object):
def __init__(self, function, attributes):
self.__function = function
for att in attributes:
setattr(self, att, attributes[att])
def __call__(self, *args, **kwargs):
return self.__function(*args, **kwargs)
def __get__(self, instance, owner):
return MethodType(self, instance, owner)
retval = override(function, self.attributes)
return retval
I tried this decorator on the toy example that follows.
class bar(object):
#attribute(a=2)
def foo(self):
print self.foo.a
self.foo.a = 1
Though I am able to access the value of attribute 'a' from within foo(), I can't set it to another value. Indeed, when I call bar().foo(), I get the following AttributeError.
AttributeError: 'instancemethod' object has no attribute 'a'
Why is this? More importantly how can I achieve my goal?
Edit
Just to be more specific, I am trying to find a simple way to implement static variable that are located within class methods. Continuing from the example above, I would like instantiate b = bar(), call both foo() and doo() methods and then access b.foo.a and b.doo.a later on.
class bar(object):
#attribute(a=2)
def foo(self):
self.foo.a = 1
#attribute(a=4)
def doo(self):
self.foo.a = 3
The best way to do this is to not do it at all.
First of all, there is no need for an attribute decorator; you can just assign it yourself:
class bar(object):
def foo(self):
print self.foo.a
self.foo.a = 1
foo.a = 2
However, this still encounters the same errors. You need to do:
self.foo.__dict__['a'] = 1
You can instead use a metaclass...but that gets messy quickly.
On the other hand, there are cleaner alternatives.
You can use defaults:
def foo(self, a):
print a[0]
a[0] = 2
foo.func_defaults = foo.func_defaults[:-1] + ([2],)
Of course, my preferred way is to avoid this altogether and use a callable class ("functor" in C++ words):
class bar(object):
def __init__(self):
self.foo = self.foo_method(self)
class foo_method(object):
def __init__(self, bar):
self.bar = bar
self.a = 2
def __call__(self):
print self.a
self.a = 1
Or just use classic class attributes:
class bar(object):
def __init__(self):
self.a = 1
def foo(self):
print self.a
self.a = 2
If it's that you want to hide a from derived classes, use whatever private attributes are called in Python terminology:
class bar(object):
def __init__(self):
self.__a = 1 # this will be implicitly mangled as __bar__a or similar
def foo(self):
print self.__a
self.__a = 2
EDIT: You want static attributes?
class bar(object):
a = 1
def foo(self):
print self.a
self.a = 2
EDIT 2: If you want static attributes visible to only the current function, you can use PyExt's modify_function:
import pyext
def wrap_mod(*args, **kw):
def inner(f):
return pyext.modify_function(f, *args, **kw)
return inner
class bar(object):
#wrap_mod(globals={'a': [1]})
def foo(self):
print a[0]
a[0] = 2
It's slightly ugly and hackish. But it works.
My recommendation would be just to use double underscores:
class bar(object):
__a = 1
def foo(self):
print self.__a
self.__a = 2
Although this is visible to the other functions, it's invisible to anything else (actually, it's there, but it's mangled).
FINAL EDIT: Use this:
import pyext
def wrap_mod(*args, **kw):
def inner(f):
return pyext.modify_function(f, *args, **kw)
return inner
class bar(object):
#wrap_mod(globals={'a': [1]})
def foo(self):
print a[0]
a[0] = 2
foo.a = foo.func_globals['a']
b = bar()
b.foo() # prints 1
b.foo() # prints 2
# external access
b.foo.a[0] = 77
b.foo() # prints 77
While You can accomplish Your goal by replacing self.foo.a = 1 with self.foo.__dict__['a'] = 1 it is generally not recommended.
If you are using Python2 - (and not Python3) - whenever you retrieve a method from an instance, a new instance method object is created which is a wrapper to the original function defined in the class body.
The instance method is a rather transparent proxy to the function - you can retrieve the function's attributes through it, but not set them - that is why setting an item in self.foo.__dict__ works.
Alternatively you can reach the function object itself using: self.foo.im_func - the im_func attribute of instance methods point the underlying function.
Based on other contributors's answers, I came up with the following workaround. First, wrap a dictionnary in a class resolving non-existant attributes to the wrapped dictionnary such as the following code.
class DictWrapper(object):
def __init__(self, d):
self.d = d
def __getattr__(self, key):
return self.d[key]
Credits to Lucas Jones for this code.
Then implement a addstatic decorator with a statics attribute that will store the static attributes.
class addstatic(object):
def __init__(self, **statics):
self.statics = statics
def __call__(self, function):
class override(object):
def __init__(self, function, statics):
self.__function = function
self.statics = DictWrapper(statics)
def __call__(self, *args, **kwargs):
return self.__function(*args, **kwargs)
def __get__(self, instance, objtype):
from types import MethodType
return MethodType(self, instance)
retval = override(function, self.statics)
return retval
The following code is an example of how the addstatic decorator can be used on methods.
class bar(object):
#attribute(a=2, b=3)
def foo(self):
self.foo.statics.a = 1
self.foo.statics.b = 2
Then, playing with an instance of the bar class yields :
>>> b = bar()
>>> b.foo.statics.a
2
>>> b.foo.statics.b
3
>>> b.foo()
>>> b.foo.statics.a
3
>>> b.foo.statics.b
5
The reason for using this statics dictionnary follows jsbueno's answer which suggest that what I want would require overloading the dot operator of and instance method wrapping the foo function, which I am not sure is possible. Of course, the method's attribute could be set in self.foo.__dict__, but since it not recommended (as suggested by brainovergrow), I came up with this workaround. I am not certain this would be recommended either and I guess it is up for comments.

Use decorator to collect instance methods?

I have this class:
class Foo(object):
handlers = []
def __init__(self):
pass
def run(self):
pass
def foo(self):
pass
def bar(self):
pass
How could I implement decorator #collect_handler
class Foo(object):
handlers = []
def __init__(self):
pass
def run(self):
pass
#collect_handler
def foo(self):
pass
#collect_handler
def bar(self):
pass
so that:
foo = Foo()
foo.handlers # [foo, bar]
?
is this possible?
class Foo(object):
handlers = []
def collect_handler(handlers):
def wrapper(func):
handlers.append(func)
return func
return wrapper
collect_handler = collect_handler(handlers)
def __init__(self):
pass
def run(self):
pass
#collect_handler
def foo(self):
pass
#collect_handler
def bar(self):
pass
foo = Foo()
print(foo.handlers)
yields
[<function foo at 0xb770d994>, <function bar at 0xb770d9cc>]
These are not unbound methods; they are just plain functions. (There is no checking that the the first argument is an instance of Foo.) However, they should suffice. (Note in Python3 there are no more unbound methods; the distinction between unbound methods and plain functions was removed.)
Just an alternate way without using decorators.
f = Foo()
[m for m in dir(f) if getattr(f,m).__doc__ == "COLLECT"]
The above statement uses List comprehension in Python.
dir is a built-in function which would return all attributes of an object.
getattr is a built-in function to retrieve an attribute of an object.
__doc__ is a python variable which holds the docstring for any python artifacts.
This should be your class definition:
class Foo(object):
def __init__(self):
pass
def run(self):
pass
def foo(self):
"COLLECT"
pass
def bar(self):
"COLLECT"
pass

Python subclasses calling parent function

class A():
class B():
def Foo(self):
print "Hello"
class C():
def Bar(self):
print "Goodbye"
def name(self):
print "FooBar"
What I want to do is, within the Bar function is call the Foo function. How would I do that?
In Python, inner classes don't have an implicit instance of the outer class associated with them. Without such an instance, you can't call A's non-static methods from B or C.
If you do have such an instance, then simply use the dot notation:
class C():
def Bar(self):
self.a.name()
...
(where self.a is an instance of A.)
Alternatively, if A.name() can be made static, the following will also work:
class A(object):
class C():
def Bar(self):
print "Goodbye"
A.name()
#staticmethod
def name():
print "FooBar"
A.C().Bar()
You need an instance of class A to call a method.

Categories

Resources