Automatically remove named parameters from a Python function call - python

I've written a Python library that uses a lot of named parameters in its function calls, and I'm wondering if there's any way to automatically remove all of these named parameters, instead of removing them manually (which is a very tedious task).
For example, would it be possible to translate this function call:
getClass(lang="Java", body=[
mainMethod(lang="Java", body=[
println(lang="Java", toPrint="Hello World")
])
])
into the function call below (which omits the named arguments, and is much more concise?):
getClass("Java", [
mainMethod("Java", [
println("Java", "Hello World!")
])
])
In order to do this, one possible approach would be to write a function that would print its own function call as a string - however, I don't think it's possible to write a function that would do this. Are there any other approaches to this problem that might work as well?

There is no need. Keyword arguments can still be passed positionally. There is the added benefit, here, of being able to specify one or none of them, if you would so please. However, you don't need to specify any at all.
>>> def foo(bar=1, baz=[2,3]):
... print bar, baz
...
>>> foo()
1 [2, 3]
>>> foo(baz=4)
1 4
>>> foo(10, 20)
10 20
If I'm misunderstanding the code you're providing, let me know. Steve's answer seems to indicate that you are actually working with strings, but I didn't see anything in your post to indicate that.
You did mention a function which prints its own function call; by this, I assume you mean that the function must print a string which looks exactly like the thing you'd type to call the function with the same arguments which you passed. This is relatively easy to do, because you can either type the function's name as-is, or you can use its __name__ attribute.
>>> def goo(a,b):
... print "{}({}, {})".format(goo.__name__, a, b)
...
>>> goo(1,2)
goo(1, 2)
>>> def hoo(*args):
... print "{}({})".format(hoo.__name__, ', '.join((str(arg) for arg in args)))
...
>>>
>>> hoo(2,3,4,5)
hoo(2, 3, 4, 5)
Thinking about it, your example seems wanting of a general function which would grant this behavior to any function - recursively. Here's a way to achieve that, using partials (I'll redefine foo() so that the example makes some more sense):
>>> from functools import partial
>>> def foo(a, b):
... return (a if not isinstance(a, partial) else a()) + (b if not isinstance(b, partial) else b())
...
>>> fun = partial(foo, 1, partial(foo, partial(foo, 2, 4), partial(foo, 3, 5)))
>>> fun()
15
>>> fun = partial(foo, 1, partial(foo, partial(foo, 2, 4), partial(foo, 3, 5)))
>>> def print_pfunc(pfunc):
... return "{}({}{}{})".format(pfunc.func.__name__, ', '.join(str(arg) if not isinstance(arg, partial) else print_pfunc(arg) for arg in pfunc.args) if pfunc.args else '', ', ' if pfunc.args and pfunc.keywords else '', ', '.join('{}={}'.format(k, v if not isinstance(v, partial) else print_pfunc(v)) for k, v in pfunc.keywords) if pfunc.keywords else '')
...
>>> print print_pfunc(fun)
foo(1, foo(foo(2, 4), foo(3, 5)))
If you're not a fan of that very long format() call, here's a different way to write it (just so that you don't have to spend time decoding my garbage):
def print_pfunc(pfunc):
args = ""
if pfunc.args is not None:
args = ', '.join(str(arg) if not isinstance(arg, partial) else print_pfunc(arg) for arg in pfunc.args)
kwargs = ""
if pfunc.keywords is not None:
kwargs = ', '.join('{}={}'.format(k, v if not isinstance(v, partial) else print_pfunc(v)) for k, v in pfunc.keywords)
return "{}({}{}{})".format(pfunc.func.__name__, args, ', ' if args and kwargs else '', kwargs)
Adapting this to your code, now, will require you to write code which will turn your function calls into partials before evaluating them. It's up to you what you want to do from this point - I can't think of a clever way to get around the fact that function calls passed as arguments get evaluated before they are passed, as this will interfere with what you are trying to do.

Related

*_ and *args assigns which value at runtime | python |

Not getting internally what is happening. *_ amd *args doing
what is assigned to default() at runtime
Using *_ in default
def default(*_):
return "Not Happy"
a,b=10,20
default(a,b)
Using *args in default
def default(*args):
return "Not Happy"
a,b=10,20
default(a,b)
I am trying to understand what is assigned to default at runtime.
if not a and b
I have used website to see visually what happens at runtime during execution but not getting : https://pythontutor.com/visualize.html
In Python, you can define variadic functions (i.e. functions that can take any number of arguments), cf the tutorial or a RealPython article about it.
The gist of it is that you can declare a *whatever parameter, and Python will collect the variadic parameters and put them in there for you. For example :
>>> def foo(*args):
>>> print(type(args), args)
>>>
>>> foo()
<class 'tuple'> ()
>>> foo(1)
<class 'tuple'> (1,)
>>> foo(1, 'a')
<class 'tuple'> (1, 'a')
>>> foo(1, 'a', 'b', 'c')
<class 'tuple'> (1, 'a', 'b', 'c')
The convention is to call it args, but you can give it another name :
>>> def foo(*elephant):
>>> print(elephant)
>>>
>>> foo(1, 'a')
(1, 'a')
So when you call default(a,b), then *args (or *_ if you want) is filled, and you can use it in your function :
>>> def default(*args):
>>> return "Not Happy" + str(args)
>>>
>>> a,b=10,20
>>> default(a,b)
'Not Happy(10, 20)'
default is a function, when you do default(...) you call that function, meaning you execute the code you wrote in it. You are passing a and b, none of them is listed as a regular parameter, so both ends up in the *args parameter.

dict of functions with fixed input

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}

Dynamical output in Python Functions

When we use def, we can use **kwargs and *args to define dynamic inputs to the function
Is there anything similar for the return tuples, I've been looking for something that behaves like this:
def foo(data):
return 2,1
a,b=foo(5)
a=2
b=1
a=foo(5)
a=2
However if I only declare one value to unpack, it sends the whole tuple over there:
a=foo(5)
a=(2,1)
I could use 'if' statements, but I was wondering if there was something less cumbersome. I could also use some hold variable to store that value, but my return value might be kind of large to have just some place holder for that.
Thanks
If you need to fully generalize the return value, you could do something like this:
def function_that_could_return_anything(data):
# do stuff
return_args = ['list', 'of', 'return', 'values']
return_kwargs = {'dict': 0, 'of': 1, 'return': 2, 'values': 3}
return return_args, return_kwargs
a, b = function_that_could_return_anything(...)
for thing in a:
# do stuff
for item in b.items():
# do stuff
In my opinion it would be simpler to just return a dictionary, then access parameters with get():
dict_return_value = foo()
a = dict_return_value.get('key containing a', None)
if a:
# do stuff with a
I couldn't quite understand exactly what you're asking, so I'll take a couple guesses.
If you want to use a single value sometimes, consider a namedtuple:
from collections import namedtuple
AAndB = namedtuple('AAndB', 'a b')
def foo(data):
return AAndB(2,1)
# Unpacking all items.
a,b=foo(5)
# Using a single value.
foo(5).a
Or, if you're using Python 3.x, there's extended iterable unpacking to easily unpack only some of the values:
def foo(data):
return 3,2,1
a, *remainder = foo(5) # a==3, remainder==[2,1]
a, *remainder, c = foo(5) # a==3, remainder==[2], c==1
a, b, c, *remainder = foo(5) # a==3, b==2, c==1, remainder==[]
Sometimes the name _ is used to indicate that you are discarding the value:
a, *_ = foo(5)

what is the asterisk in "replace(*something)" for? (python) [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What does *args and **kwargs mean?
I' just reading Mining the social web and encountered a python syntax that I can't figure out:
transforms = [(', Inc.', ''), (', Inc', ''), (', LLC', ''), (', LLP', '')]
"google, Inc.".replace(*transforms[0])
But if I type
*transforms[0]
in the interpreter, it says it is invalid syntax. I googled it, but the python docu really is not up for the job.
So what does the asterisk means here please? Thank you all.
The *argument format in python means: use all elements in the sequence argument and pass them as arguments to the function.
In this specific case, that translates to:
"google, Inc.".replace(', Inc.', '')
This is easiest demonstrated:
>>> def foo(arg1, arg2):
... print arg1, arg2
...
>>> arguments = ('spam', 'eggs')
>>> foo(*arguments)
spam, eggs
You can also use the **kw double star format to pass in keyword arguments:
>>> def foo(arg1='ham', arg2='spam'):
... print arg1, arg2
...
>>> arguments = dict(arg2='foo', arg1='bar')
>>> foo(**arguments)
bar, foo
and you can use the same spelling in a function definition to capture arbitrary positional and keyword arguments:
>>> def foo(*args, **kw):
... print args, kw
...
>>> foo('arg1', 'arg2', foo='bar', spam='eggs')
('arg1', 'arg2'), {'foo': 'bar', 'spam': 'eggs'}
The asterisk unpacks an iterable. I think it is best explained with an example:
>>> def exampleFunction (paramA, paramB, paramC):
print('A:', paramA)
print('B:', paramB)
print('C:', paramC)
>>> myTuple = ('foo', 'bar', 'baz')
>>> myTuple
('foo', 'bar', 'baz')
>>> exampleFunction(myTuple)
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
exampleFunction(myTuple)
TypeError: exampleFunction() takes exactly 3 arguments (1 given)
>>> exampleFunction(myTuple[0], myTuple[1], myTuple[2])
A: foo
B: bar
C: baz
>>> exampleFunction(*myTuple)
A: foo
B: bar
C: baz
As you can see, we defined a function that takes three arguments and a tuple with three elements. Now if we want to use the values from the tuple directly, we cannot just pass the tuple and have it working. We could pass each element separately but that is just very verbose. What we do instead is use the asterisk to unpack the tuple and essentially use the elements from the tuple as arguments.
There is a second usage for the unpacking functionality when working with a unknown number of parameters:
>>> def example2 (*params):
for param in params:
print(param)
>>> example2('foo')
foo
>>> example2('foo', 'bar')
foo
bar
>>> example2(*myTuple)
foo
bar
baz
The asterisk allows us here to define a parameter that takes all the remaining values that were passed and packs it into an iterable, so we can iterate it.
It turns the tuple passed into a list of arguments. So
"google, Inc.".replace(*transforms[0])
becomes
"google, Inc.".replace(', Inc.', '')
This way you can programatically construct the list of arguments that are being passed (with variable length being a key advantage).
Check section 4.7.4 of the Python tutorial: http://docs.python.org/tutorial/controlflow.html#more-on-defining-functions
But if I type
*transforms[0]
in the interpreter, it says it is invalid syntax.
The * in front of transforms[0] only has meaning in a function call.
An alternative way of making this call with the data in the first tuple in the list is:
"Google, Inc.".replace(transforms[0][0],transforms[0][1])

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