ChatGPT解决这个技术问题 Extra ChatGPT

How do I add default parameters to functions when using type hinting?

If I have a function like this:

def foo(name, opts={}):
  pass

And I want to add type hints to the parameters, how do I do it? The way I assumed gives me a syntax error:

def foo(name: str, opts={}: dict) -> str:
  pass

The following doesn't throw a syntax error but it doesn't seem like the intuitive way to handle this case:

def foo(name: str, opts: dict={}) -> str:
  pass

I can't find anything in the typing documentation or on a Google search.

Edit: I didn't know how default arguments worked in Python, but for the sake of this question, I will keep the examples above. In general it's much better to do the following:

def foo(name: str, opts: dict=None) -> str:
  if not opts:
    opts={}
  pass
The last function is the correct way. It's the same way scala language does it too.
you have a mutable default type - that will lead to problems
@noɥʇʎԀʎzɐɹƆ Not unless you're using it for, e.g. memoization. :P

n
noɥʇʎԀʎzɐɹƆ

Your second way is correct.

def foo(opts: dict = {}):
    pass

print(foo.__annotations__)

this outputs

{'opts': <class 'dict'>}

It's true that's it's not listed in PEP 484, but type hints are an application of function annotations, which are documented in PEP 3107. The syntax section makes it clear that keyword arguments works with function annotations in this way.

I strongly advise against using mutable keyword arguments. More information here.


See legacy.python.org/dev/peps/pep-3107/#syntax. Type hinting is just an application of function annotations.
Wow, I didn't know about the mutable default arguments in Python... especially coming from Javascript/Ruby where default arguments work differently. Not gonna rehash what's already been said ad nauseum around SO about it, I'm just glad I found out about this before it bit me. Thanks!
I was always advised to use None rather than a mutable type like {} or [] or a default object as mutations to that object without a deep-copy will persist between iterations.
define enough functions with mutable keyword arguments and it is only a matter of time before you find yourself looking back on a 4 hour debugging session questioning your life choices
Shouldn't there be no whitespace around the = in dict = {} like it is convention for non-type-hinted keyword arguments?
T
Tomasz Bartkowiak

If you're using typing (introduced in Python 3.5) you can use typing.Optional, where Optional[X] is equivalent to Union[X, None]. It is used to signal that the explicit value of None is allowed . From typing.Optional:

def foo(arg: Optional[int] = None) -> None:
    ...

Shouldn't there be no whitespace around the = in Optional[int] = None like it is convention for non-type-hinted keyword arguments?
@actual_panda the answer is correct. the style is different when there are type hints. there are examples in PEP 484
K
Kirkalicious

I recently saw this one-liner:

def foo(name: str, opts: dict=None) -> str:
    opts = {} if not opts else opts
    pass

Hi @Kirkalicious, thanks for your answer. Could you explain how it works?
The empty dict passed as a default parameter is the same dict for every call. So if the function mutates it then the default next time will be the mutated value from last time. Making None the default and then checking inside the method avoids this problem by allocating a new dict each time the method is invoked.
Can you update your answer (without "Edit:", "Update:", or similar)? Comments may disappear at any time.
How about opts = opts or {}
One issue with this -- If opts is a mutable parameter that callers will want to see modified values in, it will fail when {} is passed in. Probably safer to stick with the traditional two-liner if opts is None: opts = {}. If you need a one-liner, I'd prefer opts = {} if opts is None else opts.