dict of functions with fixed input - python

I have some functions which I would like to call through a dictionary but pass on fixed values.
def doSum(a,b):
print a+b
def doProd(a,b):
print a*b
if I pass on the input via
d = {'sum': doSum,'prod':doProd}
d['prod'](2,4)
It works all fine and prints 8.
But if I try something like
d = {'sum': doSum(2,4),'prod':doProd(2,4)}
d['prod']
It prints 6 and 8. How can I change the code so that it would only run the function I specify with the key with the fixed parameters in the dict?

As an "old school" alternative to Martijn's anwser you can also use lambda functions:
d = {
"sum": lambda: doSum(2, 4),
"prod": lambda: doProd(2, 4),
}
d["sum"]()

Use functools.partial() to store functions with default values to pass in.
You still need to call the function:
from functools import partial
d = {'sum': partial(doSum, 2, 4),'prod': partial(doProd, 2, 4)}
d['sum']()
A partial object, when called, will turn around and call the wrapped function, passing in the arguments you already stored with the partial, plus any others you passed in:
>>> addtwo = partial(doSum, 2)
>>> addtwo(6)
8
>>> addtwo(4)
6
Last but not least, take a look a the operator module; that module already contains a doSum and doProd function for you:
>>> import operator
>>> operator.add(2, 4)
6
>>> operator.mul(2, 4)
8
These functions return the result instead of printing the value. In the above example, it is the python interactive interpreter that does the printing instead.

The print of 6 and 8 is actually done at the creation of the dictionary:
>>> d = {'sum': doSum(2,4),'prod':doProd(2,4)}
6
8
because the functions are executed at this moment. Then the call to d['prod'] just does nothing because the value here is None (because the function doProd didn't return anything).
If you print the dictionary, you will have:
>>> print d
{'sum': None, 'prod': None}

Related

Python defaultdict

I found something strange that I couldn't understand.
This is the case:
from collections import defaultdict
a = defaultdict(lambda: len(a))
This is just the part of the code, and the code has never defined 'a' above.
The questions are:
Is it possible to use defaultdict as is, not specifying the variable previously?
If possible, what is the meaning of that code?
Maybe it is best explained in an example:
>>> a = defaultdict(lambda: len(b))
>>> b = 'abcd'
>>> a[0]
4
As you can see, it is possible to use b in the lambda even though the b does not yet exist at that point. What is important is that b exists at the time when the lambda is executed. At that point, Python will look for a variable named b and use it.
Note also that the original code does not necessarily use length of the defaultdict itself. It simply evaluates whatever a is at that point. See this example:
>>> a = defaultdict(lambda: len(a))
>>> a['a']
0
>>> a['b']
1
So far, so good. But then rename some things:
>>> x = a
>>> a = []
>>> x['c']
0
>>> x['d']
0
Now the deaultdict is named x, but it does not use len(x). It still uses len(a). This caveat may become important if you sent the defaultdict to a function where a does not mean anything.
you are saying to default dict, when i try to do something with a key and it doesnt exist, use this lambda as the inital value for the key. since your lambda is using a (i.E the dict its self) and you say the length of it. It means when you perform operations using a key thats not in the dict then the dict will use the lambda instead or in this case the length of the dict as the value
from collections import defaultdict
a = defaultdict(lambda: len(a))
a['one'] += 5 #here dict length is 0 so value is 0 + 5 = 5
a['two'] += 2 #jere dict length is 1 so value is 1 + 2 = 3
a['three'] += 1 #here dict length is 2 so value is 2 + 1 = 3
print(a.items())
print(a['newval']) #here newval doesnt exist so will use default value which is length of dict I.E 3
OUTPUT
dict_items([('one', 5), ('two', 3), ('three', 3)])
3
Here's how defaultdict works. Say you have a dict of lists and you're setting values for keys that might not exist. In that case you'd do something like this:
d = dict()
if some_key not in d:
d[some_key] = list()
d[some_key].append(some_value)
defaultdict does this automatically for you by passing it a callable, e.g., int, list, set, which will call int() (default value 0), list() (default value empty list), and set() (default value empty set) respectively. Your lambda is also a callable, which returns integers, so you'll have a dict with int values. But the value you get from the expression will depend on the size of the dict.
Can you do a = defaultdict(lambda: len(a))?
Yes, you can. The lambda will not be executed until called which is when it'll look up the name a. Compare these two cases.
f = lambda: len(a)
a = defaultdict(f)
a[0] # this is when the lambda is called for the first time
But,
g = lambda: len(b)
g() # this will raise a NameError
b = defauldict(g)

why does D.get(k,v) seem to always execute v if v is returned from a function?

D = {'a':1}
D.get('a', print('hah'))
Although 1 is successfully returned, I also get 'hah'. Why? it seems as if python needs to evaluate what it is that is supposed to return if 'a' doesn't exist, and is somehow tricked because it expected just a variable.
Also, is there a smart way to get the intended behaviour (no execution of the print function), other than this:
D.get('a', print('hah') if not D.get('a') else None)
Mind you, the print() here is a MWE. I really need to use a function that returns a list.
When python calls a function, all arguments are first evaluated, because python doesn't know, whether one parameter is needed or not.
If you don't want the evaluation, you have to work with if or exceptions:
D = {'a': 1}
try:
a = D['a']
except KeyError:
a = print('hah')
With two lookups, so less elegant:
a = D['a'] if 'a' in D else print('hah')
Or if you can guarantee, that the values in your dictionary never evaluate to False (no empty string, empty tuple, 0, 0.0, ..., be cautious!):
a = D.get('a') or print('hah')
Yes, python evaluates the arguments first, and then calls the function.
Print the result of get:
print(D.get('a', 'hah'))
Or, if you want to check for existence:
if "a" in D:
print('there')
Python isn't lazy evaluated. So your
D.get('a', <function call that returns None>)
starts by evaluating the functions that are fed to get and then does the lookup. If 'a' wasn't in the dictionary, you'd still get the printed statement, but the get call would return None.
You can contrive something like lazy evaluation out of python by using functions instead of values, of course:
d = {'a': lambda x: 1}
d.get('a', lambda x: print('hah'))('dummy function argument')
but the awkwardness of this should be pretty self-evident. I think everyone would agree that this is "unpythonic". The arguably nicer way would be:
def return1():
return 1
def print_hah():
print('hah')
d = {'a': return1}
d.get('a', print_hah)()
But again, this isn't very pretty. The main issue is that python wasn't really designed to be a functional language; you can do it, it's just not going to look nice.
Remove the print part:
D = {'a': 1}
print(D.get('a', 'hah'))

What does 'x, y =' mean in python syntax? [duplicate]

This question already has answers here:
How are tuples unpacked in for loops?
(8 answers)
Closed 9 years ago.
I'm new to python and trying to work my way through http://yuji.wordpress.com/2011/06/22/python-imaplib-imap-example-with-gmail/ which has the following line:
result, data = mail.uid('search', None, "ALL") # search and return uids instead
Could someone explain this line?
Thank you.
It means that the function you have called returns an iterable, and the index 0 of the iterable is assigned to x and the index 1 is assigned to y. This is called tuple unpacking.
Eg)
>>> def func(a,b):
... return b,a
...
>>> a = 5
>>> b = 7
>>> a,b = func(a,b)
>>> a
7
>>> b
5
>>> x = func(a,b)
>>> x
(5, 7)
Edit to show that returning multiple values, they are packed as tuple by default and then unpacked at the other end. Since there is only one variable x here, the tuple is assigned to x.
Simple function for swapping two variables(Just for an example) that answers your question
At least, as of python 2.7.x, the function will unpack a tuple of 2 arguments returned from a function. If it returns anything other than 2 arguments in the tuple, I believe it will throw an error if you try to unpack more than this. If it returns 3 arguments and you unpack 2, for example, you will get an exception.
For example:
def func(a):
return (a,a+1,a*2)
a,b,c = func(7)
print a,b
==> 7 8 # NOTE Values
a = func(3)
print a
==> (3, 4, 6) # NOTE: TUPLE
a,b = func(9)
print a,b
==> Exception - ValueError: too many values to unpack
This may be different in 3.0+.
The other answer, that "the function you have called returns an iterable" is a good one. That is what is happening in your specific example. This is what is called "unpacking" in python. The following are examples of unpacking and assignment related to your question:
>>> a,b = 1,2
>>> a
1
>>> b
2
>>> a,b,c = ['do', 're', 'mi']
>>> a
'do'
>>> b
're'
>>> c
'mi'
>>>
This is one of the pretty features of Python syntax. If I am not mistaken, it is also optimized - i.e. the fastest way to achieve the result.

Assigning to a dict

Forgive me if this has been asked before. I did not know how to search for it.
I'm quite familiar with the following idiom:
def foo():
return [1,2,3]
[a,b,c] = foo()
(d,e,f) = foo()
wherein the values contained within the left hand side will be assigned based upon the values returned from the function on the right.
I also know you can do
def bar():
return {'a':1,'b':2,'c':3}
(one, two, three) = bar()
[four, five, six] = bar()
wherein the keys returned from the right hand side will be assigned to the containers on the left hand side.
However, I'm curious, is there a way to do the following in Python 2.6 or earlier:
{letterA:one, letterB:two, letterC:three} = bar()
and have it work in the same manner that it works for sequences to sequences? If not, why? Naively attempting to do this as I've written it will fail.
Dictionary items do not have an order, so while this works:
>>> def bar():
... return dict(a=1,b=2,c=3)
>>> bar()
{'a': 1, 'c': 3, 'b': 2}
>>> (lettera,one),(letterb,two),(letterc,three) = bar().items()
>>> lettera,one,letterb,two,letterc,three
('a', 1, 'c', 3, 'b', 2)
You can see that you can't necessarily predict how the variables will be assigned. You could use collections.OrderedDict in Python 3 to control this.
If you modify bar() to return a dict (as suggested by #mikerobi), you might want to still preserve keyed items that are in your existing dict. In this case, use update:
mydict = {}
mydict['existing_key'] = 100
def bar_that_says_dict():
return { 'new_key': 101 }
mydict.update(bar_that_says_dict())
print mydict
This should output a dict with both existing_key and new_key. If mydict had a key of new_key, then the update would overwrite it with the value returned from bar_that_says_dict.
No, if you can not change bar function, you could create a dict from the output pretty easily.
This is the most compact solution. But I would prefer to modify the bar function to return a dict.
dict(zip(['one', 'two', 'three'], bar()))

Can I Pass Dictionary Values/Entry and Keys to function

I am writing a function and intended to use a dictionary key and its value as parameters. For example:
testDict={'x':2,'xS':4}
def newFunct(key,testDict['key']):
newvalue=key+str(testDict['key'])
return newValue
for key in testDict:
newValue=newFunct(key,testDict[key])
print newValue
I get a SyntaxError: invalid syntax when I hit the return button after typing the semicolon. I am guessing this is telling me I can't pass a dictionary value in that form. Presumably I can define a new variable
for key in testDict:
xdixt=testDict[key]
newValue=newFunct(key,xdixt)
and def the function using xdixt
but I am hoping there is some trick that I am missing. I Googled and found some reference to unpacking a dictionary but that didn't seem to work.
This Python stuff is really cool. My question was came about because I am trying to use some values I stored in a dictionary to create a new directory. Based on the material I read from Stephan's answer I wondered about how to generalize the information I learned. My directory name has five different pieces to it, each piece is the result of processing the values from myDict. The expression to create the directory name was getting too complicated and in my opinion too complicated to easily read. so I wondered if I could use the same approach to put the pieces into a list and then unpack them when it came time to create the directory name and it worked!
def createDirectory(myKey,**myDict):
pathList=[]
pathList.append(myDict['subKey1'])
pathList.append(myDict['subKey2'].lstrip('0'))
pathList.append(myDict['subKey3'])
etc
myPath=os.path.join(*myList)
os.makedirs(myPath)
return(myPath)
Is this what you want?
def func(**kwargs):
for key, value in kwargs.items():
pass # Do something
func(**myDict) # Call func with the given dict as key/value parameters
(See the documentation for more about keyword arguments. The keys in myDict must be strings.)
Edit: you edited your question to include the following:
I think the ** notation in front of myDict instructs the function to expect a dictionary and to unpack the key (the first *) and the value, the second *
This is not correct. To understand what is happening, you must consider the following:
A function can have multiple formal parameters (a and b in this case):
def f1(a, b): pass
We can pass positional arguments to such function (like in most other languages):
f1(2, 3)
We can also pass keyword arguments:
f1(a=2, b=3)
We can also mix these, but the positional arguments must come first:
f1(2, b=3)
f1(a=2, 3) # SyntaxError: non-keyword arg after keyword arg
There is a way to let a function accept an arbitrary number of positional arguments, which it can access as a tuple (args in this case):
def f2(*args): assert isinstance(args, tuple)
Now we can call f2 using separately specified arguments, or using a list whose contents first need to be unpacked, using a syntax similar to the notation used for *args:
f2(2, 3)
f2(*[2, 3])
Likewise, an arbitrary number of keyword arguments may be accepted:
def f3(**kwargs): pass
Note that f3 does not ask for a single argument of type dict. This is the kind of invocations it expects:
f3(a=2, b=3)
f3(**{'a': 2, 'b': 3})
All arguments to f3 must be named:
f3(2, 3) # TypeError: f3() takes exactly 0 arguments (2 given)
Putting all of this together, and remembering that positional arguments must come first, we may have:
>>> def f4(a, b, *args, **kwargs):
... print('%r, %r' % (args, kwargs))
...
>>> f4(2, 3)
(), {}
>>> f4(2, 3, 4, 5)
(4, 5), {}
>>> f4(2, 3, x=4, y=5)
(), {'y': 5, 'x': 4}
>>> f4(2, 3, 4, 5, x=6, y=7)
(4, 5), {'y': 7, 'x': 6}
>>> f4(2, *[3, 4, 5], **{'x': 6, 'y': 7})
(4, 5), {'y': 7, 'x': 6}
Pay special attention to the following two errors:
>>> f4(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f4() takes at least 2 arguments (1 given)
>>> f4(2, 3, a=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f4() got multiple values for keyword argument 'a'
The second error should help you explain this behavior:
>>> f4(**{'foo': 0, 'a': 2, 'b': 3, 'c': 4})
(), {'c': 4, 'foo': 0}
Not sure why we are bringing in kwargs, this is much simpler than that. You said you're new to Python, I think you just need some Python fundamentals here.
def newFunct(key,testDict['key']):
Should be:
def newFunct(key, val):
There's no reason to use any special syntax on your second parameter to indicate that it's coming from a dictionary. It's just a parameter, you just happen to be passing the value from a dictionary item into it.
Further, once it's in the function, there's no reason to treat it in a special way either. At this point it's just a value. Which means that:
newvalue=key+str(testDict[key])
Can now just be:
newvalue=key+str(val)
So when you call it like this (as you did):
newValue=newFunct(key,testDict[key])
testDict[key] resolves to the value at 'key', which just becomes "val" in the function.
An alternate way, if you see it fit for whatever reason (and this is just something that's good to know), you could define the function thusly:
def newFunct(key, testDict):
Again, the second parameter is just a parameter, so we use the same syntax, but now we're expecting it to be a dict, so we should use it like one:
newvalue=key+str(testDict[key])
(Note: don't put quotes around 'key' in this case. We're referring to the variable called 'key', not a key called 'key'). When you call the function, it looks like this:
newValue=newFunct(key,testDict)
So unlike the first case where you're just passing one variable from the dictionary, you're passing a reference to the whole dictionary into the function this time.
Hope that helps.
why don't you just do:
[k + str(v) for k, v in test_dict.iteritems()]
or for py3k:
[k + str(v) for k, v in test_dict.items()]
edit
def f(k, v):
print(k, v) # or do something much more complicated
for k, v in testDict.items():
f(k, v)
From your description is seems like testDict is some sort of global variable with respect to the function. If this is the case - why do you even need to pass it to the function?
Instead of your code:
testDict={'x':2,'xS':4}
def newFunct(key,testDict[key]):
newvalue=key+str(testDict[key])
return newValue
for key in testDict:
newValue=newFunct(key,testDict[key])
print newValue
You can simply use:
testDict={'x':2,'xS':4}
def newFunct(key):
newvalue=key+str(testDict[key])
return newValue
for key in testDict:
newValue=newFunct(key)
print newValue
If testDict is not meant to be in the global scope (which makes sense...), I would recommend simply passing a name for the dictionary and not "messing around" with variable length argument lists in this case:
testDict={'x':2,'xS':4}
def newFunct(key,dictionary):
newvalue=key+str(dictionary[key])
return newValue
for key in testDict:
newValue=newFunct(key,testDict)
print newValue

Categories

Resources