Python: How to only pass needed arguments into function from a dictionary? - python

Assume now I have a well-defined function
def f1(a):
...
and i can not change its definition. Now I want to call it with a argument from a dictionary
D={ 'a':1 , 'b':2}
If I call it like
f1(**D)
there will be a syntax error (because b is not defined in f1). My question is if I can find a smart way to let the function to find the argument it needed only?

You can use inspect.getargspec:
d = {'a': 5, 'b': 6, 'c': 7}
def f(a,b):
return a + b
f(*[d[arg] for arg in inspect.getargspec(f).args])
which gives 11.
Thanks Eugene, getargspec is legacy, instead you should use getfullargspec which has the same usage in this case.

You could get the argument names from the function's code object, then lookup the values for them in the dictionary:
>>> def f(a):
... b = 2
... return a + b
...
>>> D = {'a': 1, 'b': 2, 'c': 3}
>>> nargs = f.__code__.co_argcount
>>> varnames = f.__code__.co_varnames
>>> f(*(D[arg] for arg in varnames[:nargs]))
3

Here is an example of function that got a dictionary and use only the 'b' key :
In [14]: def f1(mydict):
...: return mydict['b']
...:
In [15]: x={'a': 1, 'b':2}
In [16]: f1(x)
Out[16]: 2

Related

Automatically Unpack and Assign, Keys to Values from a Python Dictionary

This question is similar to the one asked here:
However in my case I have a large dictionary filled with many keys and values, and I will not be able to enumerate each key to implement this solution:
from operator import itemgetter
params = {'a': 1, 'b': 2}
a, b = itemgetter('a', 'b')(params)
In my case:
from operator import itemgetter
params = {'a': 1, 'b': 2 ........... 'y': 25, 'z': 26 }
a, b ..... y, z = itemgetter('a', 'b'.... 'y', 'z')(params)
Is there any way I can unpack and assign each key to it's value, and associate values with variables names after its keys on a large scale?
Please Advise.
# Function
a = 1
b = 2
def foo(z):
return a + b + z
foo(3)
# should return 6
Either state the variables as input argument and unpack the dictionary in the call
def foo(z, a, b):
return a + b + z
param = {'a': 1, 'b': 2}
foo(3, **param)
>> 6
then you could also provide default values (for example 0) if any input should be missing.
Another possibility is to provide provide the entire dictionary as input and let the function handle the unpacking.
def bar(z, p):
return p['a'] + p['b'] + z
bar(3, param)
>> 6

Dynamically build key: value lookup for list of variables

Suppose I have some variables:
a, b, c, d, e = range(5)
I want to save the values of these variables in a file for later inspection. One way I thought to do this was:
lookup = {
'a': a,
'b': b,
'c': c,
'd': d,
'e': e
}
As you might imagine, with a large number of variables, this could get tedious. And, yes, I know many editors have functionality to make this kind of copy-paste action easy. But I'm looking for the standard, "Pythonic" way of dynamically building a key: value lookup where the key is the variable's name and the value is the variable's, well, value!
I thought about this:
>>> {var.__name__: var for var in [a, b, c, d, e]}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <dictcomp>
AttributeError: 'int' object has no attribute '__name__'
I'm not surprised this didn't work, because integer variables are constants (I'm not sure of the exact way to describe things):
>>> a = 1
>>> b = 1
>>> a is b
True
>>> b is a
True
>>> a == b
True
How might I accomplish this?
import itertools
data = range(5)
result = {f"a{count}": value for count, value in zip(itertools.count(1), data)}
print(result)
Output:
{'a1': 0, 'a2': 1, 'a3': 2, 'a4': 3, 'a5': 4}
You might want to look into locals() and inspect. The result could be i.e.:
>>> from inspect import ismodule
>>> a = 1
>>> b = 1
>>> dict((k, v) for k, v in locals().items() if not k.startswith("__") and not callable(v) and not ismodule(v))
{'a': 1, 'b': 1}
But to get it right you might need to add some additional conditions, and also you will have to watch out for mutable objects or values, as in this case those would mutate and you would not preserve the earlier value for later inspection. Serialization or copying them could help.
You could tackle it from the other direction and save all the local variables, using locals() For example
import json
def foo(a=None, bb=None):
ccc='lots of c'; de=42
print( json.dumps( locals() ))
foo() generates {"a": null, "bb": null, "ccc": "lots of c", "de": 42}
( json.dumps is one way to serialize a dict, and will work only for simple variables that can be converted to JSON)
Another way to just get some variables would be
print( json.dumps( dict( a=a, b=b, c=c) ))
Here is another way using ascii_lowercase from string module:
import string
alphabets = iter(string.ascii_lowercase)
lookup = {next(alphabets): x for x in range(5)}
print(lookup)
# {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4}

Python: Forward a dictionary to another function [duplicate]

I'd like to call a function in python using a dictionary with matching key-value pairs for the parameters.
Here is some code:
d = dict(param='test')
def f(param):
print(param)
f(d)
This prints {'param': 'test'} but I'd like it to just print test.
I'd like it to work similarly for more parameters:
d = dict(p1=1, p2=2)
def f2(p1, p2):
print(p1, p2)
f2(d)
Is this possible?
Figured it out for myself in the end. It is simple, I was just missing the ** operator to unpack the dictionary
So my example becomes:
d = dict(p1=1, p2=2)
def f2(p1,p2):
print p1, p2
f2(**d)
In[1]: def myfunc(a=1, b=2):
In[2]: print(a, b)
In[3]: mydict = {'a': 100, 'b': 200}
In[4]: myfunc(**mydict)
100 200
A few extra details that might be helpful to know (questions I had after reading this and went and tested):
The function can have parameters that are not included in the dictionary
You can not override a function parameter that is already in the dictionary
The dictionary can not have values that aren't in the function.
Examples:
Number 1: The function can have parameters that are not included in the dictionary
In[5]: mydict = {'a': 100}
In[6]: myfunc(**mydict)
100 2
Number 2: You can not override a function parameter that is already in the dictionary
In[7]: mydict = {'a': 100, 'b': 200}
In[8]: myfunc(a=3, **mydict)
TypeError: myfunc() got multiple values for keyword argument 'a'
Number 3: The dictionary can not have values that aren't in the function.
In[9]: mydict = {'a': 100, 'b': 200, 'c': 300}
In[10]: myfunc(**mydict)
TypeError: myfunc() got an unexpected keyword argument 'c'
How to use a dictionary with more keys than function arguments:
A solution to #3, above, is to accept (and ignore) additional kwargs in your function (note, by convention _ is a variable name used for something being discarded, though technically it's just a valid variable name to Python):
In[11]: def myfunc2(a=None, **_):
In[12]: print(a)
In[13]: mydict = {'a': 100, 'b': 200, 'c': 300}
In[14]: myfunc2(**mydict)
100
Another option is to filter the dictionary based on the keyword arguments available in the function:
In[15]: import inspect
In[16]: mydict = {'a': 100, 'b': 200, 'c': 300}
In[17]: filtered_mydict = {k: v for k, v in mydict.items() if k in [p.name for p in inspect.signature(myfunc).parameters.values()]}
In[18]: myfunc(**filtered_mydict)
100 200
Example with both positional and keyword arguments:
Notice further than you can use positional arguments and lists or tuples in effectively the same way as kwargs, here's a more advanced example incorporating both positional and keyword args:
In[19]: def myfunc3(a, *posargs, b=2, **kwargs):
In[20]: print(a, b)
In[21]: print(posargs)
In[22]: print(kwargs)
In[23]: mylist = [10, 20, 30]
In[24]: mydict = {'b': 200, 'c': 300}
In[25]: myfunc3(*mylist, **mydict)
10 200
(20, 30)
{'c': 300}
In python, this is called "unpacking", and you can find a bit about it in the tutorial. The documentation of it sucks, I agree, especially because of how fantasically useful it is.
Here ya go - works just any other iterable:
d = {'param' : 'test'}
def f(dictionary):
for key in dictionary:
print key
f(d)

getting a dictionary of class variables and values

I am working on a method to return all the class variables as keys and values as values of a dictionary , for instance i have:
first.py
class A:
a = 3
b = 5
c = 6
Then in the second.py i should be able to call maybe a method or something that will return a dictionary like this
import first
dict = first.return_class_variables()
dict
then dict will be something like this:
{'a' : 3, 'b' : 5, 'c' : 6}
This is just a scenario to explain the idea, of course i don't expect it to be that easy, but i will love if there are ideas on how to handle this problem just like dict can be used to set a class variables values by passing to it a dictionary with the variable, value combination as key, value.
You need to filter out functions and built-in class attributes.
>>> class A:
... a = 3
... b = 5
... c = 6
...
>>> {key:value for key, value in A.__dict__.items() if not key.startswith('__') and not callable(key)}
{'a': 3, 'c': 6, 'b': 5}
Something like this?
class A(object):
def __init__(self):
self.a = 3
self.b = 5
self.c = 6
def return_class_variables(A):
return(A.__dict__)
if __name__ == "__main__":
a = A()
print(return_class_variables(a))
which gives
{'a': 3, 'c': 6, 'b': 5}
Use a dict comprehension on A.__dict__ and filter out keys that start and end with __:
>>> class A:
a = 3
b = 5
c = 6
...
>>> {k:v for k, v in A.__dict__.items() if not (k.startswith('__')
and k.endswith('__'))}
{'a': 3, 'c': 6, 'b': 5}
Best solution and most pythonic is to use var(class_object) or var(self) (if trying to use inside class).
This although do avoids dictionary pairs where the key is another object and not a default python type.
>>> class TheClass():
>>> def __init__(self):
>>> self.a = 2
>>> self.b = 1
>>> print(vars(self))
>>> class_object= TheClass()
{'a'=2, 'b'=1}
Or outside class
>>> vars(class_object)
{'a': 2, 'b': 1}
You can use __dict__ to get the list of a class variables. For example, if you have a class like this:
class SomeClass:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def to_dict(self) -> dict:
return {key: value for key, value in self.__dict__.items()}
You can get the list of variables this way:
some_class = SomeClass(1,2,3)
some_class.to_dict()
And the output will be:
{'a':1, 'b':2, 'c':3}

calling Python kwargs functions with special keys

I want to use kwargs in Python like this:
def myfunc(**kwargs):
... do something ...
x = myfunc(a=1, b=2, #value=4)
But I can't, because #value is not a valid Python keyword
Alternatively, I can do this:
x = myfunc(**{'a':1, 'b':2, '#value': 4})
which is kind of awkward.
Is there any way I can use some kind of hybrid approach here?
# this doesn't work
x = myfunc(a=1,b=2, {'#value': 4})
Sure you can:
x = myfunc(a=1, b=2, **{'#value': 4})
Using explicit keyword parameters does not prevent you from passing in a dictionary as well.
Demo:
>>> def myfunc(**kwargs):
... print kwargs
...
>>> myfunc(a=1, b=2, **{'#value': 4})
{'a': 1, 'b': 2, '#value': 4}

Categories