How to disallow keyword arguments? - python-3.x

Recently I noticed that range() does not accept keyword arguments, and I thought this was a little bit strange: Even if we define no defaults we can still do
def f(a, b):
return a + b
f(a=3, b=5)
Is it therefore somehow possible to disable the use of keyword arguments in a function written in Python? Or is this just reserved for built in functions?

Since this came up as the top result for me, figured I'd go ahead and add the answer even though this is 2 years old...
def f(a, b, /):
return a + b
Any arguments before the / must be passed in as positional args.
See: https://peps.python.org/pep-0570/

Related

PyQT QPushButton Connection Problem - Wrong function being called [duplicate]

Im trying to build a calculator with PyQt4 and connecting the 'clicked()' signals from the buttons doesn't work as expected.
Im creating my buttons for the numbers inside a for loop where i try to connect them afterwards.
def __init__(self):
for i in range(0,10):
self._numberButtons += [QPushButton(str(i), self)]
self.connect(self._numberButtons[i], SIGNAL('clicked()'), lambda : self._number(i))
def _number(self, x):
print(x)
When I click on the buttons all of them print out '9'.
Why is that so and how can i fix this?
This is just, how scoping, name lookup and closures are defined in Python.
Python only introduces new bindings in namespace through assignment and through parameter lists of functions. i is therefore not actually defined in the namespace of the lambda, but in the namespace of __init__(). The name lookup for i in the lambda consequently ends up in the namespace of __init__(), where i is eventually bound to 9. This is called "closure".
You can work around these admittedly not really intuitive (but well-defined) semantics by passing i as a keyword argument with default value. As said, names in parameter lists introduce new bindings in the local namespace, so i inside the lambda then becomes independent from i in .__init__():
self._numberButtons[i].clicked.connect(lambda checked, i=i: self._number(i))
UPDATE: clicked has a default checked argument that would override the value of i, so it must be added to the argument list before the keyword value.
A more readable, less magic alternative is functools.partial:
self._numberButtons[i].clicked.connect(partial(self._number, i))
I'm using new-style signal and slot syntax here simply for convenience, old style syntax works just the same.
You are creating closures. Closures really capture a variable, not the value of a variable. At the end of __init__, i is the last element of range(0, 10), i.e. 9. All the lambdas you created in this scope refer to this i and only when they are invoked, they get the value of i at the time they are at invoked (however, seperate invocations of __init__ create lambdas referring to seperate variables!).
There are two popular ways to avoid this:
Using a default parameter: lambda i=i: self._number(i). This work because default parameters bind a value at function definition time.
Defining a helper function helper = lambda i: (lambda: self._number(i)) and use helper(i) in the loop. This works because the "outer" i is evaluated at the time i is bound, and - as mentioned before - the next closure created in the next invokation of helper will refer to a different variable.
Use the Qt way, use QSignalMapper instead.

Best Way to Pass Arguments from One Function to Another in Python

I have a function that performs a specific task, and this function takes many options, both named and unnamed options. For example:
def eat_fruit(x,a_number=None , a_fruit=None):
return(f'{x} ate {str(a_number)} {a_fruit}')
#call the function
eat_fruit("John",a_number=5,a_fruit='apples') #outputs 'John ate 5 apples'
Now, I have another function that takes many options, for example:
def do_lots_of_stuff(a,b,activity_1=None,activity_2=None):
return(f'''{a} and {b} {activity_1} and {activity_2}''')
do_lots_of_stuff("Bob","Mary",activity_1='run',activity_2='jump') #returns "Bob and Mary run and jump"
I want to have the function do_lots_of_stuff call the function eat_fruit, sometimes with options. However, it is not clear to me how to pass options from one to the other in a straightforward manner.
Ideally, I am looking for something like:
#This code does not work; it demos the type of functionality I am looking for.
do_lots_of_stuff("Bob","Mary",activity_1='run',activity_2='jump', eat_fruit_options={*put_options_here*}):
eat_fruit(eat_fruit_options)
return(f'''{a} and {b} {activity_1} and {activity_2}''')
Note that this can't be accomplished via do_lots_of_stuff(*do_lots_of_stuff_options*, *eat_fruit_options*) since options for eat_fruit are not valid do_lots_of_stuff options. Furthermore, keyword arguments must come after positional arguments. In addition this solution does not seem to be sufficient here, because I only want to pass some arguments, not all of them.
Other relevant links (although I don't believe they successfully address my question):
can I pass all positional arguments from one function to another in python?
Passing variables between functions in Python
Passing value from one function to another in Python
do_lots_of_stuff("Bob","Mary",activity_1='run',activity_2='jump', eat_fruit_args=["John"], eat_fruit_kwargs={"a_number": 5, "a_fruit": "apples"}):
eat_fruit(*eat_fruit_args, **eat_fruit_kwargs)
return(f'''{a} and {b} {activity_1} and {activity_2}''')
You can pass and forward arguments and keyword arguments. Arguments are in the form of a list. Keyword arguments (kwargs) are in the form of a dictionary, with the key as a string, and the value as the correlating keyword value.

PYTHON3: non-default argument follows default argument [duplicate]

This question already has answers here:
Why can't non-default arguments follow default arguments?
(4 answers)
Closed 2 years ago.
Actually i am a newbie to the programming world and i have defined a very simple function that will just add three numbers.
Here's the code:
def sum(a=2,b,c):
print(a+b+c)
sum(b=1,c=3)
But it just returns me an error: SyntaxError: non-default argument follows default argument
It would be great help if someone could explain this error. Thanks.
You cannot have default arguments (a=2) before positional arguments (b, c). Fix this by putting a at the back of the signature (or change c to be the default argument).
def sum(a, b, c=2):
This is because it can make calls very confusing. For instance, let's say you have this signature:
def sum(a, b=2, c, d=4):
What happens when the user calls
sum(1, 2, 3)
Do they mean sum(a=1, b=2, c=3), or sum(a=1, c=2, d=3)?

String formatting in python 3 without print function

Trying to understand how "%s%s" %(a,a) is working in below code I have only seen it inside print function thus far.Could anyone please explain how it is working inside int()?
a=input()
b=int("%s%s" %(a,a))
this "%s" format has been borrowed from C printf format, but is much more interesting because it doesn't belong to print statement. Note that it involves just one argument passed to print (or to any function BTW):
print("%s%s" % (a,a))
and not (like C) a variable number of arguments passed to some functions that accept & understand them:
printf("%s%s,a,a);
It's a standalone way of creating a string from a string template & its arguments (which for instance solves the tedious issue of: "I want a logger with formatting capabilities" which can be achieved with great effort in C or C++, using variable arguments + vsprintf or C++11 variadic recursive templates).
Note that this format style is now considered legacy. Now you'd better use format, where the placeholders are wrapped in {}.
One of the direct advantages here is that since the argument is repeated you just have to do:
int("{0}{0}".format(a))
(it references twice the sole argument in position 0)
Both legacy and format syntaxes are detailed with examples on https://pyformat.info/
or since python 3.6 you can use fstrings:
>>> a = 12
>>> int(f"{a}{a}")
1212
% is in a way just syntactic sugar for a function that accepts a string and a *args (a format and the parameters for formatting) and returns a string which is the format string with the embedded parameters. So, you can use it any place that a string is acceptable.
BTW, % is a bit obsolete, and "{}{}".format(a,a) is the more 'modern' approach here, and is more obviously a string method that returns another string.

Can Python use a functions default parameter when an inline if fails when calling it?

If I have a variable that has a value I don't want passed to a function, is it possible to do it without several ifs, especially if there are several variables that may or may not need to be passed in?
Take the following:
def test(param=""):
...do stuff
x = None
test(x if x else ?)
^
What can i put here so it
defaults to the default in
the function definition?
If this isn't possible, is there a quick way of doing this when there are multiple variables that may or may not need to be passed in rather than a lot of ifs?
Basic answer:
if(x): test(x)
else: test()
With *args you can pass in as many variables as you want but I don't think that will help you. The best I can think of is multiple ifs (Python doesn't allow overloading unfortunately).
That would look like:
if x:
if y:
if z: test(x,y,z)
else: test(x,y)
else: test(x)
else: test()
The reason you can't call test(x,z) or test(y) for example is because your method assumes a certain order in the signature so you wouldn't be able to specify which arg you are passing in at function call. In Java you could do it with overloading and different argument types, but not here afaik.

Resources