Let's say we have the function f and I need the argument b to default to an empty list, but can't set b=[] because of the issue around mutable default args.
Which of these is the most Pythonic, or is there a better way?
def f(a, b=None):
if not b:
b = []
pass
def f(a, b=None):
b = b or []
pass
The first form as it reads easier. Without any specific context, you should explicitly test for the default value, to avoid potential truthiness issues with the passed in value.
def f(a, b=None):
if b is None:
b = []
pass
From PEP 8, Programming Recommendations:
Also, beware of writing if x when you really mean if x is not None --
e.g. when testing whether a variable or argument that defaults to None
was set to some other value. The other value might have a type (such
as a container) that could be false in a boolean context!
You can see examples of this approach throughout the cpython repository:
Lib/bdb.py
Lib/argparse.py
Lib/base64.py
def f(a, b=''):
if not b:
b = []
print(a)
You can cdo something simple such as "if not b". If you are going to make the default argument an empty string or set it equal to None, you can simply use an if statement to define what B should be if you are never actually going to enter an argument for b. In this example we simply set it to an empty list.
Related
I'm trying to use
def my_function(a,b)
If I try to print function like this
print(my_function()), when values start from none, I get
"missing 2 required positional arguments"
I want to use default value so when I use, print(my_function()),
a=10 and b=a.
So I tried
def my_function(a=10,b=a)
and I got a not defined.
I don't want to define a before with global.
Is it possible? or something like this
def my_function(a,b)
if a == None:
a = 10
if b == None:
b = a
This didn't work either when I used print(my_function()).
You can set the default to None:
def my_function(a=10, b=None):
if b is None:
b = a
Here the default for a is 10, and b is set to a if left to the default value.
If you need to accept None as well, pick a different, unique default to act as a sentinel. An instance of object() is an oft-used convention:
_sentinel = object()
def my_function(a=10, b=_sentinel):
if b is _sentinel:
b = a
Now you can call my_function(11, None) and b will be set to None, call it without specifying b (e.g. my_function() or my_function(42), and b will be set to whatever a was set to.
Unless a parameter has a default (e.g. is a keyword parameter), they are required.
This function my_function(a,b) expected two positional arguments without default value so It can't be called without them passed
So the main question how can we pass two argument so that second is set to first if not passed
There are two way for this:
kwargs unpacking
def my_function(a=10, **kwargs):
b = kwargs.get('b', a)
sentinel as default Value
_sentinel = object()
def my_function(a=10, b=_sentinel):
if b is _sentinel:
b = a
Hum! I thing you can't define my_function like this. But you can use a decorator to hide the default values computation.
For example:
import functools
def my_decorator(f):
#functools.wraps(f)
def wrapper(a=10, b=None):
if b is None:
b = a
return f(a, b)
return wrapper
You can then define your function like this:
#my_decorator
def my_function(a, b):
return (a, b)
You can use your function with zero, one or two parameters:
>>> print(my_function())
(10, 10)
>>> print(my_function(5))
(5, 5)
>>> print(my_function(5, 12))
(5, 12)
I have a recursive function like this:
b=4
def someFunction(x,y,z):
global b
b += x
if...#something
else:
someFunction(x,y,z)
...
Theres a lot to it, but thats the general idea. My issue is that when running my program on cmd, I cant keep calling 'someFunction' with different parameters as there is no reset for b, however if I reset b within the function It won't work as I intend it to. So I could write this in two functions with the recursion in a sub function, but is there some other way to have b reset when I call the function without this being a problem when it starts recursion?
What I usually do is use an optional keyword argument, like this.
def someFunction(x,y,z, b=None):
if b is None:
b = 4
b += x
if...#something
else:
someFunction(x,y,z,b=b)
This way you can initialize the b on the first call to any value (and avoid usage of global variables).
This also has the positive that now someFunction is a pure function (no side effects and same input always gives same output) and much easier to work with. (Testing, refactoring, ..)
You can add an optional parameter of the function with the reset value:
def someFunction(x,y,z, reset = None):
if reset is not None:
b=reset
...
b += x
if...#something
else:
someFunction(x,y,z)
then the first time just call f(x,y,z, reset=4)
Following is an example of what I would like to do.
def f(a, b, c):
if a == 'method1':
c = 0
return b + c
In this function, parameter c is unneeded if the condition a='method1' is satisfied.
Still, I can call the function with f(a='method1', b=1, c=2), which will have the same effect as f(a='method1', b=1, c=0).
A solution to this is to set the parameter c default to 0
def f(a, b, c=0):
if a == 'method1':
c = 0
return b + c
Now I can call f(a='method1',b=1), which is exactly what I want. The problem is, I can still change the parameter c in the call f(a='method1',b=1,c=1), which I do not want the user to be able to.
Can I enforce this condition in the function signature, and not in the body (i.e. I would not like to use if in the body). Or if there is another better solution, please tell.
Something like
def f(a, b, c = 0 if a == 'method1', else c is required):
return b + c
Thanks in advance.
a, b and c are all assigned dynamically at runtime. There is no way you can make up for this in the signature. It needs to be detected at runtime and you might as well do that in an if as anywhere else. You can specialize at the function name level, though, and python will take care of detecting the number of parameters.
def f(b,c):
return b + c
def f_method1(b):
return f(b, 0)
def f_method2(half_a_c):
return f(0, half_a_c*2)
Hmm... this almost seems like something that you should be able to do with functools.singledispatch and typing.Literal, but I can't quite get them to work together at least in python 3.7 (with Literal coming from the typing_extensions module). I think that in general singledispatch is probably the only tool that will really get what you've asked for as the different registered functions can have entirely different signatures. However, to do this our methods need to be different classes.
from functools import singledispatch
class Method1():
pass
class OtherMethods():
pass
#singledispatch
def f(method, b, c):
return b + c
#f.register(Method1)
def _(method, b):
return b
f(Method1(), 12) # returns 12
f(Method1(), 12, 7) # raises an error
f(OtherMethods(), 12) # raises an error
f(OtherMethods(), 12, 7) # returns 19
Now this is not exactly what you asked for but the arguments are enforced in the signature.
If someone who knows more about the implementation of singledispatch and Literal comes by maybe they can explain the interaction between the two.
One easier thing to do would be to simply define c to default to some invalid value.
def f(a, b, c=None):
if a == 'method1':
c = 0
return b + c
This solves the problem that if the user forgets to set c for a method besides method1 they'll receive a (possibly cryptic) error message. However it doesn't fix the fact that if they set c when using method1 that value will be silently ignored and possibly cause confusion.
I want to define a function with some optional arguments, let's say A (mandatory) and B (optional). When B is not given, I want it to take the same value as A. How could I do that?
I have tried this, but it doesn't work (name 'B' is not defined):
def foo(A, B=A):
do_something()
I understand that the values of the arguments are not assigned before the body of the function.
You shall do this inside of your function.
Taking your original function:
def foo(A, B=A):
do_something()
try something like:
def foo(A, B=None):
if B is None:
B = A
do_something()
Important thing is, that function default values for function arguments are given at the time, the function is defined.
When you call the function with some value for A, it is too late as the B default value was already assigned and lives in function definition.
You could do it like this. If B has a value of None then assign it from A
def foo(A, B=None):
if B is None:
B = A
print 'A = %r' % A
print 'B = %r' % B
I have some variables and I want to select the first one that evaluates to True, or else return a default value.
For instance I have a, b, and c. My existing code:
result = a if a else (b if b else (c if c else default))
Another approach I was considering:
result = ([v for v in (a, b, c) if v] + [default])[0]
But they both feel messy, so is there a more Pythonic way?
Did you mean returning first value for what bool(value)==True? Then you can just rely on the fact that boolean operators return last evaluated argument:
result = a or b or c or default
If one variable is not "defined", you can't access its name. So any reference to 'a' raises a NameError Exception.
In the other hand, if you have something like:
a = None
b = None
c = 3
you can do
default = 1
r = a or b or c or default
# r value is 3
So long as default evaluates to True:
result = next((x for x in (a, b, c, d , e, default) if x))
You could do something like this (in contrast to the other answers this is a solution where you don't have to define the 'missing' values as being either None or False):
b = 6
c = 8
def first_defined(items):
for x in items:
try:
return globals()[x]
break
except KeyError:
continue
print first_defined(["a", "b", "c"])
In order to avoid NameErrors when a, b or c isn't defined: give the function a list of strings instead of variable references (you can't pass non-existing references). If you are using variables outside the 'globals()' scope, you could use getattr with its default argument.
--
If a, b and c are defined, I'd go for something like this (considering the fact that an empty string, None or False evaluate to a boolean False):
a = None
b = 6
c = 8
def firstitem(items):
for x in items:
if x:
return x
break
else:
continue
print firstitem([a, b, c])
Don't know if this works in every case, but this works for this case.
a = False
b = "b"
c = False
default = "default"
print a or b or c or default # b
How about this ?
a=None
b=None
c=None
val= reduce(lambda x,y:x or y,(a,b,c,"default"))
print val
The above prints "default". If any of the inputs is defined, val would contain the first defined input.
If by defined you mean ever assigned any value whatsoever to in any scope accessible from here, then trying to access an "undefined" variable will raise a NameError exception (or some subclass thereof, but catching NameError will catch the subclass too). So, the simplest way to perform, literally, the absolutely weird task you ask about, is:
for varname in ('a', 'b', 'c'):
try: return eval(varname)
except NameError: pass
return default
Any alleged solution lacking a try/except won't work under the above meaning for "defined". Approaches based on exploring specific scopes will either miss other scopes, or be quite complex by trying to replicate the scope-ordering logic that eval does for you so simply.
If by "defined" you actually mean "assigned a value that evaluates to true (as opposed to false)", i.e., all values are actually defined (but might happen to be false, and you want the first true value instead), then the already-proposed a or b or c or default becomes the simplest approach. But that's a totally different (and even weirder!) meaning for the word "defined"!-)