Mailing List Archive

Any possible type alias that can also set a default value for a function arg?
We have the `Optional[T]` type as a short-hand for Union[T | None] and telling us that said argument may not be present.

However, I find that a majority of the time, we also want to set a default value of None on the argument so that it can be evaluated without doing a getattr() check first.

iow, a lot of `foo: Optional[str] = None` in method signatures.

I'd love to see a companion to the Optional type, I'll call it Default, so that it can take a default value as a second arg, with a default of that being None.

For example:

foo: Default[str] would be equivalent to foo: Optional[str] = None
foo: Default[str, "bar"] would be equivalent to foo: Optional[str] = "bar"

or something like that. Basically, any way to avoid writing `= None` over and over again.
--
https://mail.python.org/mailman/listinfo/python-list
Re: Any possible type alias that can also set a default value for a function arg? [ In reply to ]
On Thu, 19 Oct 2023 at 10:11, Matthew Carruth via Python-list
<python-list@python.org> wrote:
>
> We have the `Optional[T]` type as a short-hand for Union[T | None] and telling us that said argument may not be present.
>
> However, I find that a majority of the time, we also want to set a default value of None on the argument so that it can be evaluated without doing a getattr() check first.
>
> iow, a lot of `foo: Optional[str] = None` in method signatures.
>
> I'd love to see a companion to the Optional type, I'll call it Default, so that it can take a default value as a second arg, with a default of that being None.
>
> For example:
>
> foo: Default[str] would be equivalent to foo: Optional[str] = None
> foo: Default[str, "bar"] would be equivalent to foo: Optional[str] = "bar"
>
> or something like that. Basically, any way to avoid writing `= None` over and over again.

Fundamentally no, at least not without some shenanigans. Type hints do
not affect the regular running of the code, so they can't add
defaults. You could do it the other way around and have the default
imply that it is optional, and I believe that used to be the way that
MyPy calculated things, but it was ultimately rejected. (I may have
the details wrong on that though, don't quote me.)

Ahh, but shenanigans? What kind of shenanigans is that? Glad you
asked! So, uhh, you could decorate a function and mess with its
defaults.

>>> from typing import Optional
>>> def spam(n: Optional[int]):
... if n is None: print("Default spamminess")
... else: print("Spam " * n)
...
>>> spam(5)
Spam Spam Spam Spam Spam
>>> spam(None)
Default spamminess
>>> spam()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: spam() missing 1 required positional argument: 'n'
>>> spam.__defaults__ = (None,)
>>> spam()
Default spamminess

So you could design a decorator that goes through all the arguments,
finds the ones that say "Optional", and adds a default of None if one
wasn't specified. Good luck with it though. First, you'll have to deal
with the difficulties of aligning arguments (not insurmountable but a
lot of work; don't forget that there are posonly and kwonly args to
consider). Then, you'll have to deal with the much bigger difficulties
of convincing people that this is a good thing.

BTW, rather than a decorator, you could do this by iterating over
every function in a module or class. That might work out easier. Not
sure.

Just be aware that, while Python provides you with all the tools
necessary to shoot yourself in the foot, that isn't a guarantee that
holes in feet are worthwhile.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Aw: Re: Any possible type alias that can also set a default value for a function arg? [ In reply to ]
> > or something like that. Basically, any way to avoid writing `= None` over and over again.
>
> Fundamentally no, at least not without some shenanigans. Type hints do
> not affect the regular running of the code,

Except when they do ;-)

... depending on what counts as (valid) code ...

In Python a distinction can be made between "runnable" and "valid" :-D

Karsten

--
https://mail.python.org/mailman/listinfo/python-list
Re: Re: Any possible type alias that can also set a default value for a function arg? [ In reply to ]
On Thu, 19 Oct 2023 at 18:04, Karsten Hilbert <Karsten.Hilbert@gmx.net> wrote:
>
> > > or something like that. Basically, any way to avoid writing `= None` over and over again.
> >
> > Fundamentally no, at least not without some shenanigans. Type hints do
> > not affect the regular running of the code,
>
> Except when they do ;-)
>
> ... depending on what counts as (valid) code ...
>
> In Python a distinction can be made between "runnable" and "valid" :-D
>

Can you give a counter-example? I mean, yes, any code can be written
that inspects the annotations at runtime and makes whatever changes it
likes, but that's part of what I described as "shenanigans".

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Aw: Re: Re: Any possible type alias that can also set a default value for a function arg? [ In reply to ]
> > > Fundamentally no, at least not without some shenanigans. Type hints do
> > > not affect the regular running of the code,
> >
> > Except when they do ;-)
> >
> > ... depending on what counts as (valid) code ...
> >
> > In Python a distinction can be made between "runnable" and "valid" :-D
> >
>
> Can you give a counter-example?

As per my recent foray into abusing existence-checking for Singleton assurance
along such lines as

>>> try: self.initialized
>>> except AttributeError: print('first instantiation'); self.initialized = True

and then changing that to

>>> try: self.initialized:bool

Karsten
--
https://mail.python.org/mailman/listinfo/python-list
Re: Re: Re: Any possible type alias that can also set a default value for a function arg? [ In reply to ]
On Thu, 19 Oct 2023 at 18:25, Karsten Hilbert <Karsten.Hilbert@gmx.net> wrote:
>
> > > > Fundamentally no, at least not without some shenanigans. Type hints do
> > > > not affect the regular running of the code,
> > >
> > > Except when they do ;-)
> > >
> > > ... depending on what counts as (valid) code ...
> > >
> > > In Python a distinction can be made between "runnable" and "valid" :-D
> > >
> >
> > Can you give a counter-example?
>
> As per my recent foray into abusing existence-checking for Singleton assurance
> along such lines as
>
> >>> try: self.initialized
> >>> except AttributeError: print('first instantiation'); self.initialized = True
>
> and then changing that to
>
> >>> try: self.initialized:bool

But that's not equivalent code. You might just as well say that the
ellipsis here suddenly changes the code:

self.initialized
self.initialized = ...

These are completely different, and they behave differently. Both are
valid, but they mean different things.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Aw: Re: Re: Re: Any possible type alias that can also set a default value for a function arg? [ In reply to ]
> > As per my recent foray into abusing existence-checking for Singleton assurance
> > along such lines as
> >
> > >>> try: self.initialized
> > >>> except AttributeError: print('first instantiation'); self.initialized = True
> >
> > and then changing that to
> >
> > >>> try: self.initialized:bool
>
> But that's not equivalent code.

I learned as much (RHS vs LHS).

But it did not _intuitively_ resonate with the sentiment
"type annotation does not change the running of code".

Karsten
--
https://mail.python.org/mailman/listinfo/python-list
Re: Re: Re: Re: Any possible type alias that can also set a default value for a function arg? [ In reply to ]
On Thu, 19 Oct 2023 at 19:34, Karsten Hilbert <Karsten.Hilbert@gmx.net> wrote:
>
> > > As per my recent foray into abusing existence-checking for Singleton assurance
> > > along such lines as
> > >
> > > >>> try: self.initialized
> > > >>> except AttributeError: print('first instantiation'); self.initialized = True
> > >
> > > and then changing that to
> > >
> > > >>> try: self.initialized:bool
> >
> > But that's not equivalent code.
>
> I learned as much (RHS vs LHS).
>
> But it did not _intuitively_ resonate with the sentiment
> "type annotation does not change the running of code".

Unfortunately, that simply means that your intuition was wrong. It
doesn't change my prior statement.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list