Call function without optional arguments if they are None

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
18
down vote

favorite
1












There's a function which takes optional arguments.



def alpha(p1="foo", p2="bar"):
print('0,1'.format(p1, p2))


Let me iterate over what happens when we use that function in different ways:



>>> alpha()
foo,bar
>>> alpha("FOO")
FOO,bar
>>> alpha(p2="BAR")
foo,BAR
>>> alpha(p1="FOO", p2=None)
FOO,None


Now consider the case where I want to call it like alpha("FOO", myp2) and myp2 will either contain a value to be passed, or be None. But even though the function handles p2=None, I want it to use its default value "bar" instead.

Maybe that's worded confusingly, so let me reword that:




If myp2 is None, call alpha("FOO"). Else, call alpha("FOO", myp2).




The distinction is relevant because alpha("FOO", None) has a different result than alpha("FOO").



How can I concisely (but readably) make this distinction?



One possibility would usually be to check for None within alpha, which would be encouraged because that would make the code safer. But assume that alpha is used in other places where it is actually supposed to handle None as it does.



I'd like to handle that on the caller-side.



One possibility is to do a case distinction:



if myp2 is None:
alpha("FOO")
else:
alpha("FOO", myp2)


But that can quickly become much code when there are multiple such arguments. (exponentially, 2^n)



Another possibility is to simply do alpha("FOO", myp2 or "bar"), but that requires us to know the default value. Usually, I'd probably go with this approach, but I might later change the default values for alpha and this call would then need to be updated manually in order to still call it with the (new) default value.



I am using python 3.4 but it would be best if your answers can provide a good way that works in any python version.




The question is technically finished here, but I reword some requirement again, since the first answer did gloss over that:

I want the behaviour of alpha with its default values "foo", "bar" preserved in general, so it is (probably) not an option to change alpha itself.

In yet again other words, assume that alpha is being used somewhere else as alpha("FOO", None) where the output FOO,None is expected behaviour.










share|improve this question























  • "But assume that alpha is used in other places where it is actually supposed to handle None as it does." -- What do you mean? You still want to be able to pass None as a parameter?
    – cheersmate
    Sep 25 at 8:56










  • @cheersmate Does my edit at the end of the question help? (I think deceze's answer is what I was looking for. I have to try it yet though)
    – lucidbrot
    Sep 25 at 9:03














up vote
18
down vote

favorite
1












There's a function which takes optional arguments.



def alpha(p1="foo", p2="bar"):
print('0,1'.format(p1, p2))


Let me iterate over what happens when we use that function in different ways:



>>> alpha()
foo,bar
>>> alpha("FOO")
FOO,bar
>>> alpha(p2="BAR")
foo,BAR
>>> alpha(p1="FOO", p2=None)
FOO,None


Now consider the case where I want to call it like alpha("FOO", myp2) and myp2 will either contain a value to be passed, or be None. But even though the function handles p2=None, I want it to use its default value "bar" instead.

Maybe that's worded confusingly, so let me reword that:




If myp2 is None, call alpha("FOO"). Else, call alpha("FOO", myp2).




The distinction is relevant because alpha("FOO", None) has a different result than alpha("FOO").



How can I concisely (but readably) make this distinction?



One possibility would usually be to check for None within alpha, which would be encouraged because that would make the code safer. But assume that alpha is used in other places where it is actually supposed to handle None as it does.



I'd like to handle that on the caller-side.



One possibility is to do a case distinction:



if myp2 is None:
alpha("FOO")
else:
alpha("FOO", myp2)


But that can quickly become much code when there are multiple such arguments. (exponentially, 2^n)



Another possibility is to simply do alpha("FOO", myp2 or "bar"), but that requires us to know the default value. Usually, I'd probably go with this approach, but I might later change the default values for alpha and this call would then need to be updated manually in order to still call it with the (new) default value.



I am using python 3.4 but it would be best if your answers can provide a good way that works in any python version.




The question is technically finished here, but I reword some requirement again, since the first answer did gloss over that:

I want the behaviour of alpha with its default values "foo", "bar" preserved in general, so it is (probably) not an option to change alpha itself.

In yet again other words, assume that alpha is being used somewhere else as alpha("FOO", None) where the output FOO,None is expected behaviour.










share|improve this question























  • "But assume that alpha is used in other places where it is actually supposed to handle None as it does." -- What do you mean? You still want to be able to pass None as a parameter?
    – cheersmate
    Sep 25 at 8:56










  • @cheersmate Does my edit at the end of the question help? (I think deceze's answer is what I was looking for. I have to try it yet though)
    – lucidbrot
    Sep 25 at 9:03












up vote
18
down vote

favorite
1









up vote
18
down vote

favorite
1






1





There's a function which takes optional arguments.



def alpha(p1="foo", p2="bar"):
print('0,1'.format(p1, p2))


Let me iterate over what happens when we use that function in different ways:



>>> alpha()
foo,bar
>>> alpha("FOO")
FOO,bar
>>> alpha(p2="BAR")
foo,BAR
>>> alpha(p1="FOO", p2=None)
FOO,None


Now consider the case where I want to call it like alpha("FOO", myp2) and myp2 will either contain a value to be passed, or be None. But even though the function handles p2=None, I want it to use its default value "bar" instead.

Maybe that's worded confusingly, so let me reword that:




If myp2 is None, call alpha("FOO"). Else, call alpha("FOO", myp2).




The distinction is relevant because alpha("FOO", None) has a different result than alpha("FOO").



How can I concisely (but readably) make this distinction?



One possibility would usually be to check for None within alpha, which would be encouraged because that would make the code safer. But assume that alpha is used in other places where it is actually supposed to handle None as it does.



I'd like to handle that on the caller-side.



One possibility is to do a case distinction:



if myp2 is None:
alpha("FOO")
else:
alpha("FOO", myp2)


But that can quickly become much code when there are multiple such arguments. (exponentially, 2^n)



Another possibility is to simply do alpha("FOO", myp2 or "bar"), but that requires us to know the default value. Usually, I'd probably go with this approach, but I might later change the default values for alpha and this call would then need to be updated manually in order to still call it with the (new) default value.



I am using python 3.4 but it would be best if your answers can provide a good way that works in any python version.




The question is technically finished here, but I reword some requirement again, since the first answer did gloss over that:

I want the behaviour of alpha with its default values "foo", "bar" preserved in general, so it is (probably) not an option to change alpha itself.

In yet again other words, assume that alpha is being used somewhere else as alpha("FOO", None) where the output FOO,None is expected behaviour.










share|improve this question















There's a function which takes optional arguments.



def alpha(p1="foo", p2="bar"):
print('0,1'.format(p1, p2))


Let me iterate over what happens when we use that function in different ways:



>>> alpha()
foo,bar
>>> alpha("FOO")
FOO,bar
>>> alpha(p2="BAR")
foo,BAR
>>> alpha(p1="FOO", p2=None)
FOO,None


Now consider the case where I want to call it like alpha("FOO", myp2) and myp2 will either contain a value to be passed, or be None. But even though the function handles p2=None, I want it to use its default value "bar" instead.

Maybe that's worded confusingly, so let me reword that:




If myp2 is None, call alpha("FOO"). Else, call alpha("FOO", myp2).




The distinction is relevant because alpha("FOO", None) has a different result than alpha("FOO").



How can I concisely (but readably) make this distinction?



One possibility would usually be to check for None within alpha, which would be encouraged because that would make the code safer. But assume that alpha is used in other places where it is actually supposed to handle None as it does.



I'd like to handle that on the caller-side.



One possibility is to do a case distinction:



if myp2 is None:
alpha("FOO")
else:
alpha("FOO", myp2)


But that can quickly become much code when there are multiple such arguments. (exponentially, 2^n)



Another possibility is to simply do alpha("FOO", myp2 or "bar"), but that requires us to know the default value. Usually, I'd probably go with this approach, but I might later change the default values for alpha and this call would then need to be updated manually in order to still call it with the (new) default value.



I am using python 3.4 but it would be best if your answers can provide a good way that works in any python version.




The question is technically finished here, but I reword some requirement again, since the first answer did gloss over that:

I want the behaviour of alpha with its default values "foo", "bar" preserved in general, so it is (probably) not an option to change alpha itself.

In yet again other words, assume that alpha is being used somewhere else as alpha("FOO", None) where the output FOO,None is expected behaviour.







python python-3.x






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Sep 25 at 19:40

























asked Sep 25 at 8:50









lucidbrot

92611031




92611031











  • "But assume that alpha is used in other places where it is actually supposed to handle None as it does." -- What do you mean? You still want to be able to pass None as a parameter?
    – cheersmate
    Sep 25 at 8:56










  • @cheersmate Does my edit at the end of the question help? (I think deceze's answer is what I was looking for. I have to try it yet though)
    – lucidbrot
    Sep 25 at 9:03
















  • "But assume that alpha is used in other places where it is actually supposed to handle None as it does." -- What do you mean? You still want to be able to pass None as a parameter?
    – cheersmate
    Sep 25 at 8:56










  • @cheersmate Does my edit at the end of the question help? (I think deceze's answer is what I was looking for. I have to try it yet though)
    – lucidbrot
    Sep 25 at 9:03















"But assume that alpha is used in other places where it is actually supposed to handle None as it does." -- What do you mean? You still want to be able to pass None as a parameter?
– cheersmate
Sep 25 at 8:56




"But assume that alpha is used in other places where it is actually supposed to handle None as it does." -- What do you mean? You still want to be able to pass None as a parameter?
– cheersmate
Sep 25 at 8:56












@cheersmate Does my edit at the end of the question help? (I think deceze's answer is what I was looking for. I have to try it yet though)
– lucidbrot
Sep 25 at 9:03




@cheersmate Does my edit at the end of the question help? (I think deceze's answer is what I was looking for. I have to try it yet though)
– lucidbrot
Sep 25 at 9:03












6 Answers
6






active

oldest

votes

















up vote
25
down vote



accepted










Pass the arguments as kwargs from a dictionary, from which you filter out the None values:



kwargs = dict(p1='FOO', p2=None)

alpha(**k: v for k, v in kwargs.items() if v is not None)





share|improve this answer




















  • This treats p1 = None the same of course, possibly what is wanted (or irrelevant) but worth noting perhaps
    – Chris_Rands
    Sep 25 at 8:59










  • This works perfectly! Thanks! Would you mind adding a short explanation or a good link? I think I understand what it does and could google the rest by myself, but it would also be useful for future visitors
    – lucidbrot
    Sep 25 at 9:19










  • It simply uses argument unpacking and dictionary comprehensions.
    – deceze♦
    Sep 25 at 9:28

















up vote
8
down vote














although ** is definitely a language feature, it's surely not created for solving this particular problem. Your suggestion works, so does mine. Which one works better depends on the rest of the OP's code. However, there is still no way to write f(x or dont_pass_it_at_all)
- blue_note




Thanks to your great answers, I thought I'd try to do just that:



# gen.py
def callWithNonNoneArgs(f, *args, **kwargs):
kwargsNotNone = k: v for k, v in kwargs.items() if v is not None
return f(*args, **kwargsNotNone)


 



# python interpreter
>>> import gen
>>> def alpha(p1="foo", p2="bar"):
... print('0,1'.format(p1,p2))
...
>>> gen.callWithNonNoneArgs(alpha, p1="FOO", p2=None)
FOO,bar
>>> def beta(ree, p1="foo", p2="bar"):
... print('0,1,2'.format(ree,p1,p2))
...
>>> beta('hello', p2="world")
hello,foo,world
>>> beta('hello', p2=None)
hello,foo,None
>>> gen.callWithNonNoneArgs(beta, 'hello', p2=None)
hello,foo,bar


This is probably not perfect, but it seems to work: It's a function that you can call with another function and it's arguments, and it applies deceze's answer to filter out the arguments that are None.






share|improve this answer




















  • I like this answer better than the highest one because the hairy code is moved into a function rather than being inline.
    – Quelklef
    Sep 25 at 12:01

















up vote
8
down vote














But assume that alpha is used in other places where it is actually supposed to handle None as it does.




To respond to this concern, I have been known to have a None-like value which isn't actually None for this exact purpose.



_novalue = object()

def alpha(p1=_novalue, p2=_novalue):
if p1 is _novalue:
p1 = "foo"
if p2 is _novalue:
p2 = "bar"
print('0,1'.format(p1, p2))


Now the arguments are still optional, so you can neglect to pass either of them. And the function handles None correctly. If you ever want to explicitly not pass an argument, you can pass _novalue.



>>> alpha(p1="FOO", p2=None)
FOO,None
>>> alpha(p1="FOO")
FOO,bar
>>> alpha(p1="FOO", p2=_novalue)
FOO,bar


and since _novalue is a special made-up value created for this express purpose, anyone who passes _novalue is certainly intending the "default argument" behavior, as opposed to someone who passes None who might intend that the value be interpreted as literal None.






share|improve this answer
















  • 1




    +1 , this satisfies all the conditions of OP ! I think some alternate examples of _novalue can be : passing -1 for a positive numeric argument , or passing 0.5 for a boolean argument , or passing "" where "" is an invalid argument.
    – Prem
    Sep 25 at 16:51










  • I’ve also done to differentiate None from not-set-yet on properties. It works well, but you have to be careful to always use the same _novalue. it’s easy to sprinkle around different ‘_novalue = object()’ and end up w extremely subtle bugs.
    – JL Peyret
    Sep 25 at 18:55


















up vote
2
down vote













Unfortunately, there's no way to do what you want. Even widely adopted python libraries/frameworks use your first approach. It's an extra line of code, but it is quite readable.



Do not use the alpha("FOO", myp2 or "bar") approach, because, as you mention yourself, it creates a terrible kind of coupling, since it requires the caller to know details about the function.



Regarding work-arounds: you could make a decorator for you function (using the inspect module), which checks the arguments passed to it. If one of them is None, it replaces the value with its own default value.






share|improve this answer
















  • 1




    "No way"…? Hmm… 🤔
    – deceze♦
    Sep 25 at 9:02










  • @deceze: really? is there any language feature that allows you to do this? Obviously there can be various work-arounds, but this is 3 times longer and harder to read than what the OP wants to avoid.
    – blue_note
    Sep 25 at 9:07






  • 1




    If you just have a single if..else, sure, that is actually shorter. But for functions with more than two or three arguments this longer workaround quickly pays off. And yes, I'd regard ** as a language feature to solve this issue.
    – deceze♦
    Sep 25 at 9:09






  • 1




    @deceze: although ** is definitely a language feature, it's surely not created for solving this particular problem. Your suggestion works, so does mine. Which one works better depends on the rest of the OP's code. However, there is still no way to write f(x or dont_pass_it_at_all)
    – blue_note
    Sep 25 at 9:15






  • 1




    @blue_note I'm fairly certain that the ** feature was created for exactly this use case: dynamically building up an argument set. What in the world else can you use dict unpacking for? Nothing else accepts a set of unpacked key-value pairs like methods (including initializers) do.
    – jpmc26
    Sep 26 at 3:37


















up vote
2
down vote













You could inspect the default values via alpha.__defaults__ and then use them instead of None. That way you circumvent the hard-coding of default values:



>>> args = [None]
>>> alpha('FOO', *[x if x is not None else y for x, y in zip(args, alpha.__defaults__[1:])])





share|improve this answer


















  • 1




    @jpp Good point, changed the answer.
    – a_guest
    Sep 25 at 9:06










  • Feels ugly and elegant at the same time, but I don't see why not to use this answer. Why do you not recomment this way?
    – lucidbrot
    Sep 25 at 9:22






  • 1




    @lucidbrot Well okay, technically there's nothing wrong with it and when you have many arguments it saves you from explicitly writing down the arguments' names. It's just when you want to use a default value normally you just don't pass the argument. But yes, there might be actually uses cases for that, I think it depends on the judgement of the reader. I'll remove rephrase that statement.
    – a_guest
    Sep 25 at 9:26


















up vote
1
down vote













I'm surprised nobody brought this up



def f(p1="foo", p2=None):
p2 = "bar" if p2 is None else p2
print(p1+p2)


You assign None to p2 as standart (or don't, but this way you have the true standart at one point in your code) and use an inline if. Imo the most pythonic answer. Another thing that comes to mind is using a wrapper, but that would be way less readable.



EDIT:
What I'd probably do is use a dummy as standart value and check for that. So something like this:



class dummy():
pass

def alpha(p1="foo", p2=dummy()):
if isinstance(p2, dummy):
p2 = "bar"
print("0,1".format(p1, p2))

alpha()
alpha("a","b")
alpha(p2=None)


produces:



foo,bar
a,b
foo,None





share|improve this answer






















  • This does not preserve the original behavior for other calls. (I.e. None should usually print None, just not in this specific call). I am aware that my requirements imply bad code, but I wanted to know how it would be possible. I think your answer is valuable for many future visitors, but is not the answer to my question. I wouldn't delete it though (as the first answerer did, who suggested the same thing and got downvoted to the ninth layer of Baator
    – lucidbrot
    Sep 26 at 6:19










  • Oops sorry, should've read properly. See edit in original comment.
    – SV-97
    Sep 26 at 15:12











Your Answer





StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52494128%2fcall-function-without-optional-arguments-if-they-are-none%23new-answer', 'question_page');

);

Post as a guest






























6 Answers
6






active

oldest

votes








6 Answers
6






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
25
down vote



accepted










Pass the arguments as kwargs from a dictionary, from which you filter out the None values:



kwargs = dict(p1='FOO', p2=None)

alpha(**k: v for k, v in kwargs.items() if v is not None)





share|improve this answer




















  • This treats p1 = None the same of course, possibly what is wanted (or irrelevant) but worth noting perhaps
    – Chris_Rands
    Sep 25 at 8:59










  • This works perfectly! Thanks! Would you mind adding a short explanation or a good link? I think I understand what it does and could google the rest by myself, but it would also be useful for future visitors
    – lucidbrot
    Sep 25 at 9:19










  • It simply uses argument unpacking and dictionary comprehensions.
    – deceze♦
    Sep 25 at 9:28














up vote
25
down vote



accepted










Pass the arguments as kwargs from a dictionary, from which you filter out the None values:



kwargs = dict(p1='FOO', p2=None)

alpha(**k: v for k, v in kwargs.items() if v is not None)





share|improve this answer




















  • This treats p1 = None the same of course, possibly what is wanted (or irrelevant) but worth noting perhaps
    – Chris_Rands
    Sep 25 at 8:59










  • This works perfectly! Thanks! Would you mind adding a short explanation or a good link? I think I understand what it does and could google the rest by myself, but it would also be useful for future visitors
    – lucidbrot
    Sep 25 at 9:19










  • It simply uses argument unpacking and dictionary comprehensions.
    – deceze♦
    Sep 25 at 9:28












up vote
25
down vote



accepted







up vote
25
down vote



accepted






Pass the arguments as kwargs from a dictionary, from which you filter out the None values:



kwargs = dict(p1='FOO', p2=None)

alpha(**k: v for k, v in kwargs.items() if v is not None)





share|improve this answer












Pass the arguments as kwargs from a dictionary, from which you filter out the None values:



kwargs = dict(p1='FOO', p2=None)

alpha(**k: v for k, v in kwargs.items() if v is not None)






share|improve this answer












share|improve this answer



share|improve this answer










answered Sep 25 at 8:54









deceze♦

383k59519671




383k59519671











  • This treats p1 = None the same of course, possibly what is wanted (or irrelevant) but worth noting perhaps
    – Chris_Rands
    Sep 25 at 8:59










  • This works perfectly! Thanks! Would you mind adding a short explanation or a good link? I think I understand what it does and could google the rest by myself, but it would also be useful for future visitors
    – lucidbrot
    Sep 25 at 9:19










  • It simply uses argument unpacking and dictionary comprehensions.
    – deceze♦
    Sep 25 at 9:28
















  • This treats p1 = None the same of course, possibly what is wanted (or irrelevant) but worth noting perhaps
    – Chris_Rands
    Sep 25 at 8:59










  • This works perfectly! Thanks! Would you mind adding a short explanation or a good link? I think I understand what it does and could google the rest by myself, but it would also be useful for future visitors
    – lucidbrot
    Sep 25 at 9:19










  • It simply uses argument unpacking and dictionary comprehensions.
    – deceze♦
    Sep 25 at 9:28















This treats p1 = None the same of course, possibly what is wanted (or irrelevant) but worth noting perhaps
– Chris_Rands
Sep 25 at 8:59




This treats p1 = None the same of course, possibly what is wanted (or irrelevant) but worth noting perhaps
– Chris_Rands
Sep 25 at 8:59












This works perfectly! Thanks! Would you mind adding a short explanation or a good link? I think I understand what it does and could google the rest by myself, but it would also be useful for future visitors
– lucidbrot
Sep 25 at 9:19




This works perfectly! Thanks! Would you mind adding a short explanation or a good link? I think I understand what it does and could google the rest by myself, but it would also be useful for future visitors
– lucidbrot
Sep 25 at 9:19












It simply uses argument unpacking and dictionary comprehensions.
– deceze♦
Sep 25 at 9:28




It simply uses argument unpacking and dictionary comprehensions.
– deceze♦
Sep 25 at 9:28












up vote
8
down vote














although ** is definitely a language feature, it's surely not created for solving this particular problem. Your suggestion works, so does mine. Which one works better depends on the rest of the OP's code. However, there is still no way to write f(x or dont_pass_it_at_all)
- blue_note




Thanks to your great answers, I thought I'd try to do just that:



# gen.py
def callWithNonNoneArgs(f, *args, **kwargs):
kwargsNotNone = k: v for k, v in kwargs.items() if v is not None
return f(*args, **kwargsNotNone)


 



# python interpreter
>>> import gen
>>> def alpha(p1="foo", p2="bar"):
... print('0,1'.format(p1,p2))
...
>>> gen.callWithNonNoneArgs(alpha, p1="FOO", p2=None)
FOO,bar
>>> def beta(ree, p1="foo", p2="bar"):
... print('0,1,2'.format(ree,p1,p2))
...
>>> beta('hello', p2="world")
hello,foo,world
>>> beta('hello', p2=None)
hello,foo,None
>>> gen.callWithNonNoneArgs(beta, 'hello', p2=None)
hello,foo,bar


This is probably not perfect, but it seems to work: It's a function that you can call with another function and it's arguments, and it applies deceze's answer to filter out the arguments that are None.






share|improve this answer




















  • I like this answer better than the highest one because the hairy code is moved into a function rather than being inline.
    – Quelklef
    Sep 25 at 12:01














up vote
8
down vote














although ** is definitely a language feature, it's surely not created for solving this particular problem. Your suggestion works, so does mine. Which one works better depends on the rest of the OP's code. However, there is still no way to write f(x or dont_pass_it_at_all)
- blue_note




Thanks to your great answers, I thought I'd try to do just that:



# gen.py
def callWithNonNoneArgs(f, *args, **kwargs):
kwargsNotNone = k: v for k, v in kwargs.items() if v is not None
return f(*args, **kwargsNotNone)


 



# python interpreter
>>> import gen
>>> def alpha(p1="foo", p2="bar"):
... print('0,1'.format(p1,p2))
...
>>> gen.callWithNonNoneArgs(alpha, p1="FOO", p2=None)
FOO,bar
>>> def beta(ree, p1="foo", p2="bar"):
... print('0,1,2'.format(ree,p1,p2))
...
>>> beta('hello', p2="world")
hello,foo,world
>>> beta('hello', p2=None)
hello,foo,None
>>> gen.callWithNonNoneArgs(beta, 'hello', p2=None)
hello,foo,bar


This is probably not perfect, but it seems to work: It's a function that you can call with another function and it's arguments, and it applies deceze's answer to filter out the arguments that are None.






share|improve this answer




















  • I like this answer better than the highest one because the hairy code is moved into a function rather than being inline.
    – Quelklef
    Sep 25 at 12:01












up vote
8
down vote










up vote
8
down vote










although ** is definitely a language feature, it's surely not created for solving this particular problem. Your suggestion works, so does mine. Which one works better depends on the rest of the OP's code. However, there is still no way to write f(x or dont_pass_it_at_all)
- blue_note




Thanks to your great answers, I thought I'd try to do just that:



# gen.py
def callWithNonNoneArgs(f, *args, **kwargs):
kwargsNotNone = k: v for k, v in kwargs.items() if v is not None
return f(*args, **kwargsNotNone)


 



# python interpreter
>>> import gen
>>> def alpha(p1="foo", p2="bar"):
... print('0,1'.format(p1,p2))
...
>>> gen.callWithNonNoneArgs(alpha, p1="FOO", p2=None)
FOO,bar
>>> def beta(ree, p1="foo", p2="bar"):
... print('0,1,2'.format(ree,p1,p2))
...
>>> beta('hello', p2="world")
hello,foo,world
>>> beta('hello', p2=None)
hello,foo,None
>>> gen.callWithNonNoneArgs(beta, 'hello', p2=None)
hello,foo,bar


This is probably not perfect, but it seems to work: It's a function that you can call with another function and it's arguments, and it applies deceze's answer to filter out the arguments that are None.






share|improve this answer













although ** is definitely a language feature, it's surely not created for solving this particular problem. Your suggestion works, so does mine. Which one works better depends on the rest of the OP's code. However, there is still no way to write f(x or dont_pass_it_at_all)
- blue_note




Thanks to your great answers, I thought I'd try to do just that:



# gen.py
def callWithNonNoneArgs(f, *args, **kwargs):
kwargsNotNone = k: v for k, v in kwargs.items() if v is not None
return f(*args, **kwargsNotNone)


 



# python interpreter
>>> import gen
>>> def alpha(p1="foo", p2="bar"):
... print('0,1'.format(p1,p2))
...
>>> gen.callWithNonNoneArgs(alpha, p1="FOO", p2=None)
FOO,bar
>>> def beta(ree, p1="foo", p2="bar"):
... print('0,1,2'.format(ree,p1,p2))
...
>>> beta('hello', p2="world")
hello,foo,world
>>> beta('hello', p2=None)
hello,foo,None
>>> gen.callWithNonNoneArgs(beta, 'hello', p2=None)
hello,foo,bar


This is probably not perfect, but it seems to work: It's a function that you can call with another function and it's arguments, and it applies deceze's answer to filter out the arguments that are None.







share|improve this answer












share|improve this answer



share|improve this answer










answered Sep 25 at 9:43









lucidbrot

92611031




92611031











  • I like this answer better than the highest one because the hairy code is moved into a function rather than being inline.
    – Quelklef
    Sep 25 at 12:01
















  • I like this answer better than the highest one because the hairy code is moved into a function rather than being inline.
    – Quelklef
    Sep 25 at 12:01















I like this answer better than the highest one because the hairy code is moved into a function rather than being inline.
– Quelklef
Sep 25 at 12:01




I like this answer better than the highest one because the hairy code is moved into a function rather than being inline.
– Quelklef
Sep 25 at 12:01










up vote
8
down vote














But assume that alpha is used in other places where it is actually supposed to handle None as it does.




To respond to this concern, I have been known to have a None-like value which isn't actually None for this exact purpose.



_novalue = object()

def alpha(p1=_novalue, p2=_novalue):
if p1 is _novalue:
p1 = "foo"
if p2 is _novalue:
p2 = "bar"
print('0,1'.format(p1, p2))


Now the arguments are still optional, so you can neglect to pass either of them. And the function handles None correctly. If you ever want to explicitly not pass an argument, you can pass _novalue.



>>> alpha(p1="FOO", p2=None)
FOO,None
>>> alpha(p1="FOO")
FOO,bar
>>> alpha(p1="FOO", p2=_novalue)
FOO,bar


and since _novalue is a special made-up value created for this express purpose, anyone who passes _novalue is certainly intending the "default argument" behavior, as opposed to someone who passes None who might intend that the value be interpreted as literal None.






share|improve this answer
















  • 1




    +1 , this satisfies all the conditions of OP ! I think some alternate examples of _novalue can be : passing -1 for a positive numeric argument , or passing 0.5 for a boolean argument , or passing "" where "" is an invalid argument.
    – Prem
    Sep 25 at 16:51










  • I’ve also done to differentiate None from not-set-yet on properties. It works well, but you have to be careful to always use the same _novalue. it’s easy to sprinkle around different ‘_novalue = object()’ and end up w extremely subtle bugs.
    – JL Peyret
    Sep 25 at 18:55















up vote
8
down vote














But assume that alpha is used in other places where it is actually supposed to handle None as it does.




To respond to this concern, I have been known to have a None-like value which isn't actually None for this exact purpose.



_novalue = object()

def alpha(p1=_novalue, p2=_novalue):
if p1 is _novalue:
p1 = "foo"
if p2 is _novalue:
p2 = "bar"
print('0,1'.format(p1, p2))


Now the arguments are still optional, so you can neglect to pass either of them. And the function handles None correctly. If you ever want to explicitly not pass an argument, you can pass _novalue.



>>> alpha(p1="FOO", p2=None)
FOO,None
>>> alpha(p1="FOO")
FOO,bar
>>> alpha(p1="FOO", p2=_novalue)
FOO,bar


and since _novalue is a special made-up value created for this express purpose, anyone who passes _novalue is certainly intending the "default argument" behavior, as opposed to someone who passes None who might intend that the value be interpreted as literal None.






share|improve this answer
















  • 1




    +1 , this satisfies all the conditions of OP ! I think some alternate examples of _novalue can be : passing -1 for a positive numeric argument , or passing 0.5 for a boolean argument , or passing "" where "" is an invalid argument.
    – Prem
    Sep 25 at 16:51










  • I’ve also done to differentiate None from not-set-yet on properties. It works well, but you have to be careful to always use the same _novalue. it’s easy to sprinkle around different ‘_novalue = object()’ and end up w extremely subtle bugs.
    – JL Peyret
    Sep 25 at 18:55













up vote
8
down vote










up vote
8
down vote










But assume that alpha is used in other places where it is actually supposed to handle None as it does.




To respond to this concern, I have been known to have a None-like value which isn't actually None for this exact purpose.



_novalue = object()

def alpha(p1=_novalue, p2=_novalue):
if p1 is _novalue:
p1 = "foo"
if p2 is _novalue:
p2 = "bar"
print('0,1'.format(p1, p2))


Now the arguments are still optional, so you can neglect to pass either of them. And the function handles None correctly. If you ever want to explicitly not pass an argument, you can pass _novalue.



>>> alpha(p1="FOO", p2=None)
FOO,None
>>> alpha(p1="FOO")
FOO,bar
>>> alpha(p1="FOO", p2=_novalue)
FOO,bar


and since _novalue is a special made-up value created for this express purpose, anyone who passes _novalue is certainly intending the "default argument" behavior, as opposed to someone who passes None who might intend that the value be interpreted as literal None.






share|improve this answer













But assume that alpha is used in other places where it is actually supposed to handle None as it does.




To respond to this concern, I have been known to have a None-like value which isn't actually None for this exact purpose.



_novalue = object()

def alpha(p1=_novalue, p2=_novalue):
if p1 is _novalue:
p1 = "foo"
if p2 is _novalue:
p2 = "bar"
print('0,1'.format(p1, p2))


Now the arguments are still optional, so you can neglect to pass either of them. And the function handles None correctly. If you ever want to explicitly not pass an argument, you can pass _novalue.



>>> alpha(p1="FOO", p2=None)
FOO,None
>>> alpha(p1="FOO")
FOO,bar
>>> alpha(p1="FOO", p2=_novalue)
FOO,bar


and since _novalue is a special made-up value created for this express purpose, anyone who passes _novalue is certainly intending the "default argument" behavior, as opposed to someone who passes None who might intend that the value be interpreted as literal None.







share|improve this answer












share|improve this answer



share|improve this answer










answered Sep 25 at 14:20









Silvio Mayolo

12.6k22251




12.6k22251







  • 1




    +1 , this satisfies all the conditions of OP ! I think some alternate examples of _novalue can be : passing -1 for a positive numeric argument , or passing 0.5 for a boolean argument , or passing "" where "" is an invalid argument.
    – Prem
    Sep 25 at 16:51










  • I’ve also done to differentiate None from not-set-yet on properties. It works well, but you have to be careful to always use the same _novalue. it’s easy to sprinkle around different ‘_novalue = object()’ and end up w extremely subtle bugs.
    – JL Peyret
    Sep 25 at 18:55













  • 1




    +1 , this satisfies all the conditions of OP ! I think some alternate examples of _novalue can be : passing -1 for a positive numeric argument , or passing 0.5 for a boolean argument , or passing "" where "" is an invalid argument.
    – Prem
    Sep 25 at 16:51










  • I’ve also done to differentiate None from not-set-yet on properties. It works well, but you have to be careful to always use the same _novalue. it’s easy to sprinkle around different ‘_novalue = object()’ and end up w extremely subtle bugs.
    – JL Peyret
    Sep 25 at 18:55








1




1




+1 , this satisfies all the conditions of OP ! I think some alternate examples of _novalue can be : passing -1 for a positive numeric argument , or passing 0.5 for a boolean argument , or passing "" where "" is an invalid argument.
– Prem
Sep 25 at 16:51




+1 , this satisfies all the conditions of OP ! I think some alternate examples of _novalue can be : passing -1 for a positive numeric argument , or passing 0.5 for a boolean argument , or passing "" where "" is an invalid argument.
– Prem
Sep 25 at 16:51












I’ve also done to differentiate None from not-set-yet on properties. It works well, but you have to be careful to always use the same _novalue. it’s easy to sprinkle around different ‘_novalue = object()’ and end up w extremely subtle bugs.
– JL Peyret
Sep 25 at 18:55





I’ve also done to differentiate None from not-set-yet on properties. It works well, but you have to be careful to always use the same _novalue. it’s easy to sprinkle around different ‘_novalue = object()’ and end up w extremely subtle bugs.
– JL Peyret
Sep 25 at 18:55











up vote
2
down vote













Unfortunately, there's no way to do what you want. Even widely adopted python libraries/frameworks use your first approach. It's an extra line of code, but it is quite readable.



Do not use the alpha("FOO", myp2 or "bar") approach, because, as you mention yourself, it creates a terrible kind of coupling, since it requires the caller to know details about the function.



Regarding work-arounds: you could make a decorator for you function (using the inspect module), which checks the arguments passed to it. If one of them is None, it replaces the value with its own default value.






share|improve this answer
















  • 1




    "No way"…? Hmm… 🤔
    – deceze♦
    Sep 25 at 9:02










  • @deceze: really? is there any language feature that allows you to do this? Obviously there can be various work-arounds, but this is 3 times longer and harder to read than what the OP wants to avoid.
    – blue_note
    Sep 25 at 9:07






  • 1




    If you just have a single if..else, sure, that is actually shorter. But for functions with more than two or three arguments this longer workaround quickly pays off. And yes, I'd regard ** as a language feature to solve this issue.
    – deceze♦
    Sep 25 at 9:09






  • 1




    @deceze: although ** is definitely a language feature, it's surely not created for solving this particular problem. Your suggestion works, so does mine. Which one works better depends on the rest of the OP's code. However, there is still no way to write f(x or dont_pass_it_at_all)
    – blue_note
    Sep 25 at 9:15






  • 1




    @blue_note I'm fairly certain that the ** feature was created for exactly this use case: dynamically building up an argument set. What in the world else can you use dict unpacking for? Nothing else accepts a set of unpacked key-value pairs like methods (including initializers) do.
    – jpmc26
    Sep 26 at 3:37















up vote
2
down vote













Unfortunately, there's no way to do what you want. Even widely adopted python libraries/frameworks use your first approach. It's an extra line of code, but it is quite readable.



Do not use the alpha("FOO", myp2 or "bar") approach, because, as you mention yourself, it creates a terrible kind of coupling, since it requires the caller to know details about the function.



Regarding work-arounds: you could make a decorator for you function (using the inspect module), which checks the arguments passed to it. If one of them is None, it replaces the value with its own default value.






share|improve this answer
















  • 1




    "No way"…? Hmm… 🤔
    – deceze♦
    Sep 25 at 9:02










  • @deceze: really? is there any language feature that allows you to do this? Obviously there can be various work-arounds, but this is 3 times longer and harder to read than what the OP wants to avoid.
    – blue_note
    Sep 25 at 9:07






  • 1




    If you just have a single if..else, sure, that is actually shorter. But for functions with more than two or three arguments this longer workaround quickly pays off. And yes, I'd regard ** as a language feature to solve this issue.
    – deceze♦
    Sep 25 at 9:09






  • 1




    @deceze: although ** is definitely a language feature, it's surely not created for solving this particular problem. Your suggestion works, so does mine. Which one works better depends on the rest of the OP's code. However, there is still no way to write f(x or dont_pass_it_at_all)
    – blue_note
    Sep 25 at 9:15






  • 1




    @blue_note I'm fairly certain that the ** feature was created for exactly this use case: dynamically building up an argument set. What in the world else can you use dict unpacking for? Nothing else accepts a set of unpacked key-value pairs like methods (including initializers) do.
    – jpmc26
    Sep 26 at 3:37













up vote
2
down vote










up vote
2
down vote









Unfortunately, there's no way to do what you want. Even widely adopted python libraries/frameworks use your first approach. It's an extra line of code, but it is quite readable.



Do not use the alpha("FOO", myp2 or "bar") approach, because, as you mention yourself, it creates a terrible kind of coupling, since it requires the caller to know details about the function.



Regarding work-arounds: you could make a decorator for you function (using the inspect module), which checks the arguments passed to it. If one of them is None, it replaces the value with its own default value.






share|improve this answer












Unfortunately, there's no way to do what you want. Even widely adopted python libraries/frameworks use your first approach. It's an extra line of code, but it is quite readable.



Do not use the alpha("FOO", myp2 or "bar") approach, because, as you mention yourself, it creates a terrible kind of coupling, since it requires the caller to know details about the function.



Regarding work-arounds: you could make a decorator for you function (using the inspect module), which checks the arguments passed to it. If one of them is None, it replaces the value with its own default value.







share|improve this answer












share|improve this answer



share|improve this answer










answered Sep 25 at 9:00









blue_note

9,83521730




9,83521730







  • 1




    "No way"…? Hmm… 🤔
    – deceze♦
    Sep 25 at 9:02










  • @deceze: really? is there any language feature that allows you to do this? Obviously there can be various work-arounds, but this is 3 times longer and harder to read than what the OP wants to avoid.
    – blue_note
    Sep 25 at 9:07






  • 1




    If you just have a single if..else, sure, that is actually shorter. But for functions with more than two or three arguments this longer workaround quickly pays off. And yes, I'd regard ** as a language feature to solve this issue.
    – deceze♦
    Sep 25 at 9:09






  • 1




    @deceze: although ** is definitely a language feature, it's surely not created for solving this particular problem. Your suggestion works, so does mine. Which one works better depends on the rest of the OP's code. However, there is still no way to write f(x or dont_pass_it_at_all)
    – blue_note
    Sep 25 at 9:15






  • 1




    @blue_note I'm fairly certain that the ** feature was created for exactly this use case: dynamically building up an argument set. What in the world else can you use dict unpacking for? Nothing else accepts a set of unpacked key-value pairs like methods (including initializers) do.
    – jpmc26
    Sep 26 at 3:37













  • 1




    "No way"…? Hmm… 🤔
    – deceze♦
    Sep 25 at 9:02










  • @deceze: really? is there any language feature that allows you to do this? Obviously there can be various work-arounds, but this is 3 times longer and harder to read than what the OP wants to avoid.
    – blue_note
    Sep 25 at 9:07






  • 1




    If you just have a single if..else, sure, that is actually shorter. But for functions with more than two or three arguments this longer workaround quickly pays off. And yes, I'd regard ** as a language feature to solve this issue.
    – deceze♦
    Sep 25 at 9:09






  • 1




    @deceze: although ** is definitely a language feature, it's surely not created for solving this particular problem. Your suggestion works, so does mine. Which one works better depends on the rest of the OP's code. However, there is still no way to write f(x or dont_pass_it_at_all)
    – blue_note
    Sep 25 at 9:15






  • 1




    @blue_note I'm fairly certain that the ** feature was created for exactly this use case: dynamically building up an argument set. What in the world else can you use dict unpacking for? Nothing else accepts a set of unpacked key-value pairs like methods (including initializers) do.
    – jpmc26
    Sep 26 at 3:37








1




1




"No way"…? Hmm… 🤔
– deceze♦
Sep 25 at 9:02




"No way"…? Hmm… 🤔
– deceze♦
Sep 25 at 9:02












@deceze: really? is there any language feature that allows you to do this? Obviously there can be various work-arounds, but this is 3 times longer and harder to read than what the OP wants to avoid.
– blue_note
Sep 25 at 9:07




@deceze: really? is there any language feature that allows you to do this? Obviously there can be various work-arounds, but this is 3 times longer and harder to read than what the OP wants to avoid.
– blue_note
Sep 25 at 9:07




1




1




If you just have a single if..else, sure, that is actually shorter. But for functions with more than two or three arguments this longer workaround quickly pays off. And yes, I'd regard ** as a language feature to solve this issue.
– deceze♦
Sep 25 at 9:09




If you just have a single if..else, sure, that is actually shorter. But for functions with more than two or three arguments this longer workaround quickly pays off. And yes, I'd regard ** as a language feature to solve this issue.
– deceze♦
Sep 25 at 9:09




1




1




@deceze: although ** is definitely a language feature, it's surely not created for solving this particular problem. Your suggestion works, so does mine. Which one works better depends on the rest of the OP's code. However, there is still no way to write f(x or dont_pass_it_at_all)
– blue_note
Sep 25 at 9:15




@deceze: although ** is definitely a language feature, it's surely not created for solving this particular problem. Your suggestion works, so does mine. Which one works better depends on the rest of the OP's code. However, there is still no way to write f(x or dont_pass_it_at_all)
– blue_note
Sep 25 at 9:15




1




1




@blue_note I'm fairly certain that the ** feature was created for exactly this use case: dynamically building up an argument set. What in the world else can you use dict unpacking for? Nothing else accepts a set of unpacked key-value pairs like methods (including initializers) do.
– jpmc26
Sep 26 at 3:37





@blue_note I'm fairly certain that the ** feature was created for exactly this use case: dynamically building up an argument set. What in the world else can you use dict unpacking for? Nothing else accepts a set of unpacked key-value pairs like methods (including initializers) do.
– jpmc26
Sep 26 at 3:37











up vote
2
down vote













You could inspect the default values via alpha.__defaults__ and then use them instead of None. That way you circumvent the hard-coding of default values:



>>> args = [None]
>>> alpha('FOO', *[x if x is not None else y for x, y in zip(args, alpha.__defaults__[1:])])





share|improve this answer


















  • 1




    @jpp Good point, changed the answer.
    – a_guest
    Sep 25 at 9:06










  • Feels ugly and elegant at the same time, but I don't see why not to use this answer. Why do you not recomment this way?
    – lucidbrot
    Sep 25 at 9:22






  • 1




    @lucidbrot Well okay, technically there's nothing wrong with it and when you have many arguments it saves you from explicitly writing down the arguments' names. It's just when you want to use a default value normally you just don't pass the argument. But yes, there might be actually uses cases for that, I think it depends on the judgement of the reader. I'll remove rephrase that statement.
    – a_guest
    Sep 25 at 9:26















up vote
2
down vote













You could inspect the default values via alpha.__defaults__ and then use them instead of None. That way you circumvent the hard-coding of default values:



>>> args = [None]
>>> alpha('FOO', *[x if x is not None else y for x, y in zip(args, alpha.__defaults__[1:])])





share|improve this answer


















  • 1




    @jpp Good point, changed the answer.
    – a_guest
    Sep 25 at 9:06










  • Feels ugly and elegant at the same time, but I don't see why not to use this answer. Why do you not recomment this way?
    – lucidbrot
    Sep 25 at 9:22






  • 1




    @lucidbrot Well okay, technically there's nothing wrong with it and when you have many arguments it saves you from explicitly writing down the arguments' names. It's just when you want to use a default value normally you just don't pass the argument. But yes, there might be actually uses cases for that, I think it depends on the judgement of the reader. I'll remove rephrase that statement.
    – a_guest
    Sep 25 at 9:26













up vote
2
down vote










up vote
2
down vote









You could inspect the default values via alpha.__defaults__ and then use them instead of None. That way you circumvent the hard-coding of default values:



>>> args = [None]
>>> alpha('FOO', *[x if x is not None else y for x, y in zip(args, alpha.__defaults__[1:])])





share|improve this answer














You could inspect the default values via alpha.__defaults__ and then use them instead of None. That way you circumvent the hard-coding of default values:



>>> args = [None]
>>> alpha('FOO', *[x if x is not None else y for x, y in zip(args, alpha.__defaults__[1:])])






share|improve this answer














share|improve this answer



share|improve this answer








edited Sep 25 at 10:47

























answered Sep 25 at 9:03









a_guest

4,25311038




4,25311038







  • 1




    @jpp Good point, changed the answer.
    – a_guest
    Sep 25 at 9:06










  • Feels ugly and elegant at the same time, but I don't see why not to use this answer. Why do you not recomment this way?
    – lucidbrot
    Sep 25 at 9:22






  • 1




    @lucidbrot Well okay, technically there's nothing wrong with it and when you have many arguments it saves you from explicitly writing down the arguments' names. It's just when you want to use a default value normally you just don't pass the argument. But yes, there might be actually uses cases for that, I think it depends on the judgement of the reader. I'll remove rephrase that statement.
    – a_guest
    Sep 25 at 9:26













  • 1




    @jpp Good point, changed the answer.
    – a_guest
    Sep 25 at 9:06










  • Feels ugly and elegant at the same time, but I don't see why not to use this answer. Why do you not recomment this way?
    – lucidbrot
    Sep 25 at 9:22






  • 1




    @lucidbrot Well okay, technically there's nothing wrong with it and when you have many arguments it saves you from explicitly writing down the arguments' names. It's just when you want to use a default value normally you just don't pass the argument. But yes, there might be actually uses cases for that, I think it depends on the judgement of the reader. I'll remove rephrase that statement.
    – a_guest
    Sep 25 at 9:26








1




1




@jpp Good point, changed the answer.
– a_guest
Sep 25 at 9:06




@jpp Good point, changed the answer.
– a_guest
Sep 25 at 9:06












Feels ugly and elegant at the same time, but I don't see why not to use this answer. Why do you not recomment this way?
– lucidbrot
Sep 25 at 9:22




Feels ugly and elegant at the same time, but I don't see why not to use this answer. Why do you not recomment this way?
– lucidbrot
Sep 25 at 9:22




1




1




@lucidbrot Well okay, technically there's nothing wrong with it and when you have many arguments it saves you from explicitly writing down the arguments' names. It's just when you want to use a default value normally you just don't pass the argument. But yes, there might be actually uses cases for that, I think it depends on the judgement of the reader. I'll remove rephrase that statement.
– a_guest
Sep 25 at 9:26





@lucidbrot Well okay, technically there's nothing wrong with it and when you have many arguments it saves you from explicitly writing down the arguments' names. It's just when you want to use a default value normally you just don't pass the argument. But yes, there might be actually uses cases for that, I think it depends on the judgement of the reader. I'll remove rephrase that statement.
– a_guest
Sep 25 at 9:26











up vote
1
down vote













I'm surprised nobody brought this up



def f(p1="foo", p2=None):
p2 = "bar" if p2 is None else p2
print(p1+p2)


You assign None to p2 as standart (or don't, but this way you have the true standart at one point in your code) and use an inline if. Imo the most pythonic answer. Another thing that comes to mind is using a wrapper, but that would be way less readable.



EDIT:
What I'd probably do is use a dummy as standart value and check for that. So something like this:



class dummy():
pass

def alpha(p1="foo", p2=dummy()):
if isinstance(p2, dummy):
p2 = "bar"
print("0,1".format(p1, p2))

alpha()
alpha("a","b")
alpha(p2=None)


produces:



foo,bar
a,b
foo,None





share|improve this answer






















  • This does not preserve the original behavior for other calls. (I.e. None should usually print None, just not in this specific call). I am aware that my requirements imply bad code, but I wanted to know how it would be possible. I think your answer is valuable for many future visitors, but is not the answer to my question. I wouldn't delete it though (as the first answerer did, who suggested the same thing and got downvoted to the ninth layer of Baator
    – lucidbrot
    Sep 26 at 6:19










  • Oops sorry, should've read properly. See edit in original comment.
    – SV-97
    Sep 26 at 15:12















up vote
1
down vote













I'm surprised nobody brought this up



def f(p1="foo", p2=None):
p2 = "bar" if p2 is None else p2
print(p1+p2)


You assign None to p2 as standart (or don't, but this way you have the true standart at one point in your code) and use an inline if. Imo the most pythonic answer. Another thing that comes to mind is using a wrapper, but that would be way less readable.



EDIT:
What I'd probably do is use a dummy as standart value and check for that. So something like this:



class dummy():
pass

def alpha(p1="foo", p2=dummy()):
if isinstance(p2, dummy):
p2 = "bar"
print("0,1".format(p1, p2))

alpha()
alpha("a","b")
alpha(p2=None)


produces:



foo,bar
a,b
foo,None





share|improve this answer






















  • This does not preserve the original behavior for other calls. (I.e. None should usually print None, just not in this specific call). I am aware that my requirements imply bad code, but I wanted to know how it would be possible. I think your answer is valuable for many future visitors, but is not the answer to my question. I wouldn't delete it though (as the first answerer did, who suggested the same thing and got downvoted to the ninth layer of Baator
    – lucidbrot
    Sep 26 at 6:19










  • Oops sorry, should've read properly. See edit in original comment.
    – SV-97
    Sep 26 at 15:12













up vote
1
down vote










up vote
1
down vote









I'm surprised nobody brought this up



def f(p1="foo", p2=None):
p2 = "bar" if p2 is None else p2
print(p1+p2)


You assign None to p2 as standart (or don't, but this way you have the true standart at one point in your code) and use an inline if. Imo the most pythonic answer. Another thing that comes to mind is using a wrapper, but that would be way less readable.



EDIT:
What I'd probably do is use a dummy as standart value and check for that. So something like this:



class dummy():
pass

def alpha(p1="foo", p2=dummy()):
if isinstance(p2, dummy):
p2 = "bar"
print("0,1".format(p1, p2))

alpha()
alpha("a","b")
alpha(p2=None)


produces:



foo,bar
a,b
foo,None





share|improve this answer














I'm surprised nobody brought this up



def f(p1="foo", p2=None):
p2 = "bar" if p2 is None else p2
print(p1+p2)


You assign None to p2 as standart (or don't, but this way you have the true standart at one point in your code) and use an inline if. Imo the most pythonic answer. Another thing that comes to mind is using a wrapper, but that would be way less readable.



EDIT:
What I'd probably do is use a dummy as standart value and check for that. So something like this:



class dummy():
pass

def alpha(p1="foo", p2=dummy()):
if isinstance(p2, dummy):
p2 = "bar"
print("0,1".format(p1, p2))

alpha()
alpha("a","b")
alpha(p2=None)


produces:



foo,bar
a,b
foo,None






share|improve this answer














share|improve this answer



share|improve this answer








edited Sep 26 at 15:16

























answered Sep 26 at 5:17









SV-97

317




317











  • This does not preserve the original behavior for other calls. (I.e. None should usually print None, just not in this specific call). I am aware that my requirements imply bad code, but I wanted to know how it would be possible. I think your answer is valuable for many future visitors, but is not the answer to my question. I wouldn't delete it though (as the first answerer did, who suggested the same thing and got downvoted to the ninth layer of Baator
    – lucidbrot
    Sep 26 at 6:19










  • Oops sorry, should've read properly. See edit in original comment.
    – SV-97
    Sep 26 at 15:12

















  • This does not preserve the original behavior for other calls. (I.e. None should usually print None, just not in this specific call). I am aware that my requirements imply bad code, but I wanted to know how it would be possible. I think your answer is valuable for many future visitors, but is not the answer to my question. I wouldn't delete it though (as the first answerer did, who suggested the same thing and got downvoted to the ninth layer of Baator
    – lucidbrot
    Sep 26 at 6:19










  • Oops sorry, should've read properly. See edit in original comment.
    – SV-97
    Sep 26 at 15:12
















This does not preserve the original behavior for other calls. (I.e. None should usually print None, just not in this specific call). I am aware that my requirements imply bad code, but I wanted to know how it would be possible. I think your answer is valuable for many future visitors, but is not the answer to my question. I wouldn't delete it though (as the first answerer did, who suggested the same thing and got downvoted to the ninth layer of Baator
– lucidbrot
Sep 26 at 6:19




This does not preserve the original behavior for other calls. (I.e. None should usually print None, just not in this specific call). I am aware that my requirements imply bad code, but I wanted to know how it would be possible. I think your answer is valuable for many future visitors, but is not the answer to my question. I wouldn't delete it though (as the first answerer did, who suggested the same thing and got downvoted to the ninth layer of Baator
– lucidbrot
Sep 26 at 6:19












Oops sorry, should've read properly. See edit in original comment.
– SV-97
Sep 26 at 15:12





Oops sorry, should've read properly. See edit in original comment.
– SV-97
Sep 26 at 15:12


















 

draft saved


draft discarded















































 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52494128%2fcall-function-without-optional-arguments-if-they-are-none%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

How to check contact read email or not when send email to Individual?

Bahrain

Postfix configuration issue with fips on centos 7; mailgun relay