Hello, There is a very common pattern for creating optional arguments when you can't use None: _optional = object() def foo(*, arg1='spam', arg3=None, arg4=_optional): if arg4 is _optional: # caller didn't pass *anything* for arg4 else: # caller did pass some (maybe None) value for arg4 It's a bit annoying to create this marker objects, and also, if you try to render a signature of such function, you'll get something like: "(*, arg1='spam', arg3=None, arg4=
TBH I think it's usually an anti-pattern when you have an API where the
absence of a parameter is not equivalent to some default value. It makes
wrapping such APIs awkward, e.g.
def logging_foo(*, arg1='something_other_than_spam', arg3=None,
arg4=
Hello,
There is a very common pattern for creating optional arguments when you can't use None:
_optional = object() def foo(*, arg1='spam', arg3=None, arg4=_optional): if arg4 is _optional: # caller didn't pass *anything* for arg4 else: # caller did pass some (maybe None) value for arg4
It's a bit annoying to create this marker objects, and also, if you try to render a signature of such function, you'll get something like:
"(*, arg1='spam', arg3=None, arg4=
What if we add a standard marker for this use-case: functools.optional or inspect.Parameter.optional?
Yury _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido)
On Wed, Apr 16, 2014 at 10:29 AM, Guido van Rossum
TBH I think it's usually an anti-pattern when you have an API where the absence of a parameter is not equivalent to some default value. It makes wrapping such APIs awkward, e.g.
def logging_foo(*, arg1='something_other_than_spam', arg3=None, arg4=
): loging.info('calling foo(arg1=%r, arg3=%r, arg4=%r)', arg1, arg3, arg4) return foo(arg1=arg1, arg3=arg3, arg4=arg4)
Wrapping the APIs in such a tightly coupled way is already awkward, since if the argspec (e.g. the default) changes, so must your wrapper. *args/**kwargs are better when possible. -- Devin
On Wed, Apr 16, 2014 at 10:09 AM, Yury Selivanov
wrote: Hello,
There is a very common pattern for creating optional arguments when you can't use None:
_optional = object() def foo(*, arg1='spam', arg3=None, arg4=_optional): if arg4 is _optional: # caller didn't pass *anything* for arg4 else: # caller did pass some (maybe None) value for arg4
It's a bit annoying to create this marker objects, and also, if you try to render a signature of such function, you'll get something like:
"(*, arg1='spam', arg3=None, arg4=
What if we add a standard marker for this use-case: functools.optional or inspect.Parameter.optional?
Yury _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido)
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On Wed, Apr 16, 2014 at 12:29 PM, Guido van Rossum
TBH I think it's usually an anti-pattern when you have an API where the absence of a parameter is not equivalent to some default value. It makes wrapping such APIs awkward, e.g.
def logging_foo(*, arg1='something_other_than_spam', arg3=None, arg4=
): loging.info('calling foo(arg1=%r, arg3=%r, arg4=%r)', arg1, arg3, arg4) return foo(arg1=arg1, arg3=arg3, arg4=arg4)
I've had to do that before when writing decorators that take parameters, e.g: def mydecorator(arg1,arg2=None): def _f(f): if arg2 is None: arg2 = f.something ... return f return _f Which sucks when None is a valid value.
On Wed, Apr 16, 2014 at 10:09 AM, Yury Selivanov
wrote: Hello,
There is a very common pattern for creating optional arguments when you can't use None:
_optional = object() def foo(*, arg1='spam', arg3=None, arg4=_optional): if arg4 is _optional: # caller didn't pass *anything* for arg4 else: # caller did pass some (maybe None) value for arg4
It's a bit annoying to create this marker objects, and also, if you try to render a signature of such function, you'll get something like:
"(*, arg1='spam', arg3=None, arg4=
What if we add a standard marker for this use-case: functools.optional or inspect.Parameter.optional?
Yury _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido)
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Ryan If anybody ever asks me why I prefer C++ to C, my answer will be simple: "It's becauseslejfp23(@#Q*(E*EIdc-SEGFAULT. Wait, I don't think that was nul-terminated."
On 2014-04-16, 1:29 PM, Guido van Rossum wrote:
TBH I think it's usually an anti-pattern when you have an API where the absence of a parameter is not equivalent to some default value. It makes wrapping such APIs awkward, e.g.
def logging_foo(*, arg1='something_other_than_spam', arg3=None, arg4=
): loging.info('calling foo(arg1=%r, arg3=%r, arg4=%r)', arg1, arg3, arg4) return foo(arg1=arg1, arg3=arg3, arg4=arg4)
Agree, wrapping is hard, but you can always use **kwargs. The pattern is sometimes useful for decorators (as Ryan Gonzalez shows in this thread). But basically, you need this when 'None' is a legitimate value for some optional argument, and you want users to pass explicitly. For instance, see inspect.Signature.replace method: http://hg.python.org/cpython/file/e4ee0b15cc4f/Lib/inspect.py#l2193 I'm not saying it's a very common thing to do, but sometimes you need this, and having the need of doing some ad hoc hacks is slightly annoying. Yury
On Wed, Apr 16, 2014 at 9:45 PM, Yury Selivanov
On 2014-04-16, 1:29 PM, Guido van Rossum wrote:
TBH I think it's usually an anti-pattern when you have an API where the absence of a parameter is not equivalent to some default value. It makes wrapping such APIs awkward, e.g.
def logging_foo(*, arg1='something_other_than_spam', arg3=None, arg4=
): loging.info('calling foo(arg1=%r, arg3=%r, arg4=%r)', arg1, arg3, arg4) return foo(arg1=arg1, arg3=arg3, arg4=arg4) Agree, wrapping is hard, but you can always use **kwargs.
The pattern is sometimes useful for decorators (as Ryan Gonzalez shows in this thread). But basically, you need this when 'None' is a legitimate value for some optional argument, and you want users to pass explicitly.
For instance, see inspect.Signature.replace method: http://hg.python.org/cpython/file/e4ee0b15cc4f/Lib/inspect.py#l2193
I'm not saying it's a very common thing to do, but sometimes you need this, and having the need of doing some ad hoc hacks is slightly annoying.
...but it would be yet another thing to learn. Plus, being it uncommon you would easily forget what's the "right way to do it" and likely come up with the usual object() hack anyway. -- Giampaolo - http://grodola.blogspot.com
On Wed, Apr 16, 2014 at 12:09 PM, Yury Selivanov
Hello,
There is a very common pattern for creating optional arguments when you can't use None:
_optional = object() def foo(*, arg1='spam', arg3=None, arg4=_optional): if arg4 is _optional: # caller didn't pass *anything* for arg4 else: # caller did pass some (maybe None) value for arg4
It's a bit annoying to create this marker objects, and also, if you try to render a signature of such function, you'll get something like:
"(*, arg1='spam', arg3=None, arg4=
What if we add a standard marker for this use-case: functools.optional or inspect.Parameter.optional?
Has Ellipsis (...) been suggested and rejected for this use before? It's not an absolutely perfect fit, but it looks better to me: def foo(*, arg1='spam', arg3=None, arg4=...): if arg4 is Ellipsis: # caller didn't pass anything for arg4 ... else: # caller passed something, possibly None, for arg4 ... The signature would look like "(*, arg1='spam', arg3=None, arg4=Ellipsis)", unless inspect.Signature.__str__ special-cased Ellipsis to be "..." (or "<optional>" if we officially blessed Ellipsis for the purpose). -- Zach
This thread is derailing quickly. :-) Does anyone remember why the marker pattern was invented? (That's a rhetorical question, in case you wondered. :-) On Wed, Apr 16, 2014 at 11:22 AM, Zachary Ware < zachary.ware+pyideas@gmail.com> wrote:
On Wed, Apr 16, 2014 at 12:09 PM, Yury Selivanov
wrote: Hello,
There is a very common pattern for creating optional arguments when you can't use None:
_optional = object() def foo(*, arg1='spam', arg3=None, arg4=_optional): if arg4 is _optional: # caller didn't pass *anything* for arg4 else: # caller did pass some (maybe None) value for arg4
It's a bit annoying to create this marker objects, and also, if you try to render a signature of such function, you'll get something like:
"(*, arg1='spam', arg3=None, arg4=
What if we add a standard marker for this use-case: functools.optional or inspect.Parameter.optional?
Has Ellipsis (...) been suggested and rejected for this use before? It's not an absolutely perfect fit, but it looks better to me:
def foo(*, arg1='spam', arg3=None, arg4=...): if arg4 is Ellipsis: # caller didn't pass anything for arg4 ... else: # caller passed something, possibly None, for arg4 ...
The signature would look like "(*, arg1='spam', arg3=None, arg4=Ellipsis)", unless inspect.Signature.__str__ special-cased Ellipsis to be "..." (or "<optional>" if we officially blessed Ellipsis for the purpose).
-- Zach _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido)
participants (6)
-
Devin Jeanpierre
-
Giampaolo Rodola'
-
Guido van Rossum
-
Ryan Gonzalez
-
Yury Selivanov
-
Zachary Ware