8

[sample.py]

def f(name='Hello Guest'):
 print(name)
def A(name=None): 
 f(name)
A()

Expected Output: 'Hello Guest'

Current Output: None

I'm expecting the answers by without using much more codes like 'name = name if name is not None else some_default_value'

Thanks in advance!

asked Jan 18, 2019 at 6:34
1
  • Instead of the default argument you can have a check inside method and assign default value. Commented Jan 18, 2019 at 6:39

5 Answers 5

5

Does this work for you?

def f(name):
 print(name or 'Hello Guest')
def A(name=None): 
 f(name)
A()
Out: "Hello Guest"
A("Hello World")
Out: "Hello World"

If the name variable is being used multiple times in the function, you could just reassign it in the beginning of the function. name = name or "Hello Guest"

answered Jan 18, 2019 at 7:52
Sign up to request clarification or add additional context in comments.

6 Comments

What if I want to print 0?
Well, was that a trick question? :) bool('0') is still True. Hence, print(name or '0') should work.
A(0). Also certain times, empty arrays and other "Falsy" variables will lead to printing Hello Guest instead. Of course in such a straightforward example you wouldn't put an empty list in, but you can easily image that this pattern (antipattern!) will unexpectedly break your application!
I think such a case will require an ìf`block checking if name is not None and name is Falsy.
Exactly why I placed this warning. Shorter is not always better!
|
3

The best way to do this will be to use a shared default:

DEFAULT_NAME = "Hello Guest"
def f(name=DEFAULT_NAME):
 print(name)
def A(name=DEFAULT_NAME):
 f(name)
answered Jan 18, 2019 at 6:46

1 Comment

This pattern works if both routines are under the control of the same party. If f() is maintained by another party, it's not an option.
0

Using inspect.signature to store default is one way to go:

def f(name='Hello Guest'):
 print(name or inspect.signature(f).parameters['name'].default)
def A(name=None): 
 f(name)
A()
# Hello Guest

With some loss of generality, but simpler (shorter and no other lib):

def f(name='Hello Guest'):
 print(name or f.__default__[0])
def A(name=None): 
 f(name)
A()
# Hello Guest
answered Jan 18, 2019 at 6:48

3 Comments

A function inspecting his own signature seems unnecessarily complicated to me.
@wim added simpler way as well
That would be f.__defaults__
0

I have been in a similar situation where I can't change the signature or the body of a function I call internally but I want to use the defaults or pass arguments only when they exists(which can get tricky if you plan to pop those keys manually)

This was the cleanest and the most reusable solution I could write.

Simplest solution:

def f(name='Hello Guest'):
 print(name)
def A(**kwargs):
 # If kwargs has any keys which are None in value, will be removed.
 # Keys which don't exists in kwargs won't propagate, hence using default value. 
 f(**{k:v for k, v in kwargs.items() if v})
A()
# This returns "Hello Guest"
A(**{"name": None})
# This returns "Hello Guest"
A(**{"name": "Someone!"})
# This returns "Someone!"

Inspect solution:

Inspect is a great module if you plan to do something complex with function signature, parameters, etc.

from inspect import signature
# This function is untouched
def f(name='Hello Guest'):
 print(name)
# changed the signature so that params can propagate further
def A(**kwargs): 
 t = signature(f, follow_wrapped=True)
 # If kwargs has any key which is None in value,
 # it will be replaced with default values for the function.
 # Keys which don't exists in kwargs won't propagate.
 f(**{k: (v or t.parameters[k].default) for k, v in kwargs.items()})
A()
# This returns "Hello Guest"
A(**{"name": None})
# This returns "Hello Guest"
A(**{"name": "Someone!"})
# This returns "Someone!"
answered Jan 8, 2022 at 19:49

1 Comment

If you are going to pass kwargs, why not simply trust that the caller won't pass any with val None? You will save yourself the trouble of stripping them out. If the function called with those args fails because someone has called its invoker with kwargs set to None, it will break, and that will be a good thing, because it will let whoever passed those args that they are invalid.
-1

Or

def f(name):
 print(name)
def A(name = 'Hello Guest'):
 f(name)
A()
answered Jan 18, 2019 at 6:39

3 Comments

You should add some comment to your anwer, because it might be useful, but strictly speaking it does not answer the question.
According to OP, the function f should have a default argument. Your answer... contradicts this.
Although this code might (or might not) solve the problem, a good answer should always contain an explanation about what the problem is and how this code helps.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.