I can store functions in dictionaries by saying
MyDict = {}
def func():
print("Hello, world!")
MyDict["func"] = func
I was wondering if there was a cleaner/neater way to write this - something along the lines of
MyDict = {}
def MyDict["func"]():
print("Hello, world!")
However this code throws a syntax error
You can (ab)use a decorator.
MyDict = {}
def store(d, name):
def _(f):
d[name] = f
return f
return _
#store(MyDict, "func")
def func():
print("Hello, world!")
#store(MyDict, "foo")
def some_other_func():
print("Goodbye")
You can simplify this if you just want to use the defined name as the key and hard-code the dictionary to update:
def store(f):
MyDict[f.__name__] = f
return f
#store
def func():
print("Hello, world!")
For your example you can do this:
d = {}
d['func'] = lambda: print('Hello, world!')
d['func']()
>>> 'Hello, world!'
If you want to use a class:
class MyClass:
def func(self):
print('Hello, world!')
c = MyClass()
c.func()
>>> 'Hello, world!'
This is wrong:
def MyDict["func"]():
print("Hello, world!")
because after def you need to use some word that contains only allowed characters. That's why you got Syntax error.
What you can use is:
1) Lambda functions (as suggested by #bphi)
MyDict = {}
MyDict['func'] = lambda: print("123")
MyDict['func']()
2) Python class to dynamically create methods (inside the class) which are stored in MyDict, using setattr built-in function:
def func1():
print(1)
def func2():
print(2)
MyDict = {}
MyDict['func1'] = func1
MyDict['func2'] = func2
class MyClass3:
def __init__(self):
for name, obj in MyDict.items():
setattr(self, name, obj)
obj = MyClass3()
obj.func1()
obj.func2()
or via lambda:
MyDict = {}
MyDict['func1'] = lambda : print(1)
MyDict['func2'] = lambda : print(2)
class MyClass3:
def __init__(self):
for name, obj in MyDict.items():
setattr(self, name, obj)
obj = MyClass3()
obj.func1()
obj.func2()
or
class MyClass3:
MyDict = {}
MyDict['func1'] = lambda: print(1)
MyDict['func2'] = lambda: print(2)
def __init__(self):
for name, obj in self.MyDict.items():
setattr(self, name, obj)
obj = MyClass3()
obj.func1()
obj.func2()
If you can express all your functions as one-liners, use lambdas as suggested in #bphi's answer.
If you don't want to be rescricted by using the lambda calculus, another way is to use a class and its static methods. Static methods are methods of a class, not an instance of a class, so they don't have access to the inner state of an object and can be called on the class, not an instance.
However, by reading through this answer you might see why this is not a very elegant (or recommended) approach, even though the result is exactly what you asked for.
class MyClass:
#staticmethod # this decorator is optional here, but suggested for code clarity
def func():
print("Hello, world!")
def func2():
print("Hey there, I am another function.")
MyClass.func()
>>> 'Hello, world!'
MyClass.func()
>>> 'Hey there, I am another function.'
If you want to use the syntax of dictionaries as proposed in your question, you can use __dict__ on the class:
MyDict = dict(MyClass.__dict__)
MyDict["func"]()
>>> 'Hello, world!'
MyDict["func2"]()
>>> 'Hey there, I am another function.'
And you can also add other functions to that dictionary:
MyDict["func3"] = lambda: print("Hi, I am yet another function.")
def func4:
print("And I am the last function for today.")
MyDict["func4"] = func4
MyDict["func"]()
>>> 'Hi, I am yet another function.'
MyDict["func2"]()
>>> 'And I am the last function for today.'
But as this dictionary is just a representation of the class MyClass, it also contains some items related to that class, like __weakref__. But you can extract your own functions:
MyCleanDict = {}
for key, value in MyDict:
if not key.startswith("_"):
MyCleanDict[key] = value
The result is exactly what you asked for, but I doubt the complexity of the approach is worth the result. I recommend a) using lambda-functions, b) staying at your first approach (define the functions first and then put them in a dict) or c) rethink your actual problem as you may find another solution besides storing functions in a dictionary.
Related
I have a class that has multiple methods and I want to store all of the available methods that would be easily accessible in example would be something like this
class Methods:
def foo(self, a):
return f'hello {a}'
def bar(self, b):
return f'hello {b}'
def methods_dict(self, var, **kwargs):
dic = {
'me' : self.foo(var),
'be': self.bar(var)
}
return dic
But on runtime my methods_dict() method will execute both of the methods inside of it's dictionary.
One one hand I'm planing to store only strings in there and it's really easily accessible, on the other hand i probably would not need to access all of the available methods at once.
Any suggestions ?
I am planning to use those methods as follows
class InheritMethods(Methods):
def __init__(self, method_name):
self.method_name = method_name
def add_to_list(self, input):
arr = []
arr.append(self.method_dicts(input)[self.method_name]
return arr
To clear things up, I am gonna call specific method based on input name, so basically input == method_name
I could do conditional statements like if input == 'foo': do somethings.., but if i end up having a lot of methods, my code is going to be a mess, so i assume(!) that would not be a great idea
I think you can get what you want with the following. Your exact usecase is still not clear. Please respond if I am heading in the wrong direction.
Using self.__getattribute__() you can get a function by name. Of course you would have to catch exceptions etc.
class Methods:
def foo(self, a):
return f'hello {a}'
def bar(self, b):
return f'hello {b}'
class InheritMethods(Methods):
def __init__(self, method_name):
self.method_name = method_name
def add_to_list(self, method_name, input):
method = getattr(self, method_name)
result = method(input)
return [result]
class InheritSingleMethod(Methods):
def __init__(self, method_name):
self.add_to_list = self.getattr(self, method_name)
Output
# Any method version
inherit_methods = InheritMethods('a') # < no use for that argument right?
inherit_methods.add_to_list('foo', 'laurens')
> ['hello laurens']
# Single method version
inherit_single_method = InheritSingleMethod('foo')
inherit_single_method.add_to_list('laurens')
> 'hello laurens'
If all you want to do is access a method of Methods given the name in a str, use getattr:
name = input()
m = Methods()
getattr(m, name)("bob")
[sample.py]
def f(name='Hello Guest'):
print(name)
def A(name=None):
f(name)
A()
Expected Output: 'Hello Guest'
Current Output: None
I'm expecting the answers by without using much more codes like 'name = name if name is not None else some_default_value'
Thanks in advance!
Does this work for you?
def f(name):
print(name or 'Hello Guest')
def A(name=None):
f(name)
A()
Out: "Hello Guest"
A("Hello World")
Out: "Hello World"
If the name variable is being used multiple times in the function, you could just reassign it in the beginning of the function. name = name or "Hello Guest"
The best way to do this will be to use a shared default:
DEFAULT_NAME = "Hello Guest"
def f(name=DEFAULT_NAME):
print(name)
def A(name=DEFAULT_NAME):
f(name)
Using inspect.signature to store default is one way to go:
def f(name='Hello Guest'):
print(name or inspect.signature(f).parameters['name'].default)
def A(name=None):
f(name)
A()
# Hello Guest
With some loss of generality, but simpler (shorter and no other lib):
def f(name='Hello Guest'):
print(name or f.__default__[0])
def A(name=None):
f(name)
A()
# Hello Guest
I have been in a similar situation where I can't change the signature or the body of a function I call internally but I want to use the defaults or pass arguments only when they exists(which can get tricky if you plan to pop those keys manually)
This was the cleanest and the most reusable solution I could write.
Simplest solution:
def f(name='Hello Guest'):
print(name)
def A(**kwargs):
# If kwargs has any keys which are None in value, will be removed.
# Keys which don't exists in kwargs won't propagate, hence using default value.
f(**{k:v for k, v in kwargs.items() if v})
A()
# This returns "Hello Guest"
A(**{"name": None})
# This returns "Hello Guest"
A(**{"name": "Someone!"})
# This returns "Someone!"
Inspect solution:
Inspect is a great module if you plan to do something complex with function signature, parameters, etc.
from inspect import signature
# This function is untouched
def f(name='Hello Guest'):
print(name)
# changed the signature so that params can propagate further
def A(**kwargs):
t = signature(f, follow_wrapped=True)
# If kwargs has any key which is None in value,
# it will be replaced with default values for the function.
# Keys which don't exists in kwargs won't propagate.
f(**{k: (v or t.parameters[k].default) for k, v in kwargs.items()})
A()
# This returns "Hello Guest"
A(**{"name": None})
# This returns "Hello Guest"
A(**{"name": "Someone!"})
# This returns "Someone!"
Or
def f(name):
print(name)
def A(name = 'Hello Guest'):
f(name)
A()
>>> def hehe():
... return "spam"
...
>>> repr(hehe)
'<function hehe at 0x7fe5624e29b0>'
I want to have:
>>> repr(hehe)
'hehe function created by awesome programmer'
How do I do that? Putting __repr__ inside hehe function does not work.
EDIT:
In case you guys are wondering why I want to do this:
>>> defaultdict(hehe)
defaultdict(<function hehe at 0x7f0e0e252280>, {})
I just don't like the way it shows here.
No, you cannot change the representation of a function object; if you wanted to add documentation, you'd add a docstring:
def foo():
"""Frob the bar baz"""
and access that with help(foo) or print foo.__doc__.
You can create a callable object with a custom __repr__, which acts just like a function:
class MyCallable(object):
def __call__(self):
return "spam"
def __repr__(self):
return 'hehe function created by awesome programmer'
Demo:
>>> class MyCallable(object):
... def __call__(self):
... return "spam"
... def __repr__(self):
... return 'hehe function created by awesome programmer'
...
>>> hehe = MyCallable()
>>> hehe
hehe function created by awesome programmer
>>> hehe()
'spam'
Usually, when you want to change something about the function, say function signature, function behavior or function attributes, you should consider using a decorator. So here is how you might implement what you want:
class change_repr(object):
def __init__(self, functor):
self.functor = functor
# lets copy some key attributes from the original function
self.__name__ = functor.__name__
self.__doc__ = functor.__doc__
def __call__(self, *args, **kwargs):
return self.functor(*args, **kwargs)
def __repr__(self):
return '<function %s created by ...>' % self.functor.__name__
#change_repr
def f():
return 'spam'
print f() # spam
print repr(f) # <function hehe created by ...>
Note, that you can only use class based decorator, since you need to override __repr__ method, which you can't do with a function object.
Not directly the answer to your question, but perhaps you really want a docstring?
>>> def hehe():
... '''hehe function created by awesome programmer'''
... return 'spam'
...
>>> help(hehe)
Help on function hehe in module __main__:
hehe()
hehe function created by awesome programmer
Here's a slightly more flexible version of what's in Alexander Zhukov's answer:
def representation(repr_text):
class Decorator(object):
def __init__(self, functor):
self.functor = functor
def __call__(self, *args, **kwargs):
return self.functor(*args, **kwargs)
def __repr__(self):
return (repr_text % self.functor.__name__ if '%' in repr_text
else repr_text)
return Decorator
from collections import defaultdict
#representation('<function %s created by awesome programmer>')
def f():
return list
dd = defaultdict(f)
print repr(dd)
Output:
defaultdict(<function f created by awesome programmer>, {})
Sincerepresentation()returns a decorator, if you wanted the same boilerplate on several functions you could do something like this:
myrepr = representation('<function %s created by awesome programmer>')
#myrepr
def f():
...
#myrepr
def g():
...
etc
I've been stuck on this for a long time (like literally weeks), I've completed everything else in the code but this. I've also researched a lot but can't get anywhere near the solution. The only reason I waited a week to come here is because I wanted to solve this myself, but now, I give up!
Now, suppose I have the following code:
class test:
def meth1(self, obj):
self.hello = {}
return self.hello.obj()
def meth2(self):
test.meth1(self, 'keys')
Now, when I create an instance and try to call the method meth2like this:
x = test()
x.meth2()
It gives me an error for obvious reasons. How can I get it do what I want-- pass an argument to a function and use that argument as an object of another object?
Looks like you want getattr():
def meth1(self, obj):
self.hello = {}
return getattr(self.hello, obj)()
getattr(a, b) is equivalent to a.b (where b in the second case is the string that the b of the first case holds). In this case, a is self.hello and b is obj. From your snippet, it looks like you want to call the obj attribute as opposed to returning it directly, which is why we have a () at the end.
>>> class test:
... def meth1(self, obj):
... self.hello = {}
... return getattr(self.hello, obj)()
... def meth2(self):
... return test.meth1(self, 'keys')
...
>>> x = test()
>>> x.meth2()
[]
I want to get the invoked times of each function or variable from existing codes which is writing in python.
What i thought is override the object's getattribute function, such as below:
acc = {}
class object(object):
def __getattribute__(self, p):
acc.update({str(self) + p: acc.get(str(self) + p, 0) + 1})
return supe(object, self).__getattribute__(p)
class A(object):
def a(self):
pass
class B(A):
def b(self):
pass
def main():
a = A()
a.a()
b = B()
b.b()
b.a = 'a'
b.a
print acc
if __name__ == '__main__':
main()
But, it only can calculate functions and variable in object, how can i calculate the normal functions or variable, such as:
def fun1():
pass
fun1()
fun1()
I want to get the result as 2, is there any tool or method to do it?
I am sorry my pool english, What i really need is the invoked times not the run time.
such as above, we said, fun1() is invoked two times.
Use a decorator.
>>> def timestamp(container, get_timestamp):
... def timestamp_decorator(func):
... def decorated(*args, **kwargs):
... container[func.func_name] = get_timestamp()
... return func(*args, **kwargs)
... return decorated
... return timestamp_decorator
...
And you use it like this:
>>> import datetime
>>> def get_timestamp():
... return datetime.datetime.now()
...
>>> timestamps = {}
>>> #timestamp(timestamps, get_timestamp)
... def foo(a):
... return a * 2
...
>>> x = foo(2)
>>> print x, timestamps
4 {'foo': datetime.datetime(2012, 2, 14, 9, 55, 15, 789893)}
There would be a way to create a counter decorator to a function (nbot a timestamp decorator) -and to automatically wrap all functions in a given module with this decorator -
so, if the module where you want to count the function calls in is named "mymodule" you can write:
class function_counter(object):
def __init__(self, func):
self.counter = 0
self.func = func
def __call__(self, *args, **kw):
self.counter += 1
return self.func(*args, **kw)
And:
>>> #function_counter
... def bla():
... pass
...
>>>
>>> bla()
>>> bla()
>>> bla()
>>> bla.counter
3
To apply this to all the functions in a module, you can write something like:
import mymodule
from types import FunctionType, BuiltinFunctionType
# define the "function_counter" class as above here (or import it)
for key, value in mymodule.__dict__.items():
if isinstance(value, (FunctionType, BuiltinFunctionType)):
mymodule.__dict__[key] = function_counter(value)
That would do for counting function usage.
If you want to count module level variable usage though, it is not that easy - as
you can't just override the mechanism attribute retrieving from a module object as you did for a class in your example.
The way to go there, is to substitute your module for a class - that implements the attribute counting scheme as you do in your example - after you import your module - and have all module attributes to be assigned to instance attributes in this class.
This is not a tested example (unlike the above), but try something along:
import mymodule
from types import FunctionType
class Counter(object):
# counter __getattribute__ just as you did above
c = Counter()
for key, value in mymodule.__dict__.items():
setattr(c, key, staticmethod(value) if isinstance(value, FunctionType) else value)
mymodule = c