How do I add default parameters to functions when using type hinting?
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.
How to type hint function with a callable argument and default value
You could use the @overload for correctly type hinting of function with default argument for your case:
from typing import Callable, List, TypeVar, overload, Set
T = TypeVar("T")
@overload
def transform(data: List[int]) -> Set[int]: ...
@overload
def transform(data: List[int], ret_type: Callable[[List[int]], T]) -> T: ...
# untyped implementation
def transform(data, ret_type = set):
return ret_type(data)
a = [1, 2, 3]
my_set: Set = transform(a)
Type Hinting: Default Parameters
You can't typehint strings, you can only typehint objects and arrays, so this is incorrect:
function setName ( string $name = "happ") {
(The reason you don't get a compile-time error here is because PHP is interpreting "string" as the name of a class.)
The wording in the docs means that if you do this:
function foo(Foo $arg) {
Then the argument passed to foo() must be an instance of object Foo. But if you do this:
function foo(Foo $arg = null) {
Then the argument passed to foo() can either be an instance of object Foo, or null. Note also that if you do this:
function foo(array $foo = array(1, 2, 3))
Then you can't call foo(null). If you want this functionality, you can do something like this:
function foo(array $foo = null) {
if ($foo === null) {
$foo = array(1, 2, 3);
}
[Edit 1]
As of PHP 5.4, you can typehint callable
:
function foo(callable $callback) {
call_user_func($callback);
}
[Edit 2]
As of PHP 7.0, you can typehint bool
, float
, int
, and string
. This makes the code in the question valid syntax. As of PHP 7.1, you can typehint iterable
.
How to type hint a Callable of a function with default arguments?
Define this:
class Foo(Protocol):
def __call__(self, x: int = ..., /) -> float:
...
then type hint foo
as Foo
instead of Callable[[int], float]
. Callback protocols allow you to:
define flexible callback types that are hard (or even impossible) to express using the
Callable[...]
syntax
and optional arguments are one of those impossible things to express with a normal Callable
. The /
at the end of __call__
's signature makes x
a positional-only parameter, which allows any passed function to bar
to have a parameter name that is not x
(your specific example of foo
calls it arg
instead). If you removed /
, then not only would the types have to line up as expected, but the names would have to line up too because you would be implying that Foo
could be called with a keyword argument. Because bar
doesn't call foo
with keyword arguments, opting into that behavior by omitting the /
imposes inflexibility on the user of bar
(and would make your current example still fail because "arg" != "x"
).
Type-hinting an overloaded function when parameter default is determined by module level variable
That's not possible. There is a proposal on GitHub to add typeof
from TypeScript, but that's a different thing - it doesn't track mutable variables like you've shown.
I don't think such a feature can be implemented, even in theory. It brings a lot of new complexity into type checking. I can think of some problematic scenarios:
- Passing a callback
def foo(callback: Callable[[], int]):
some_module.definitely_returns_an_int = callback
option_default = "int"
foo(test) # ok?
option_default = "str"
Now foo
has saved a function that returns a string.
- Tracking mutations that happen inside functions
def ints_are_the_bomb():
global option_default
option_default = "int"
option_default = "str"
some_other_module.baz()
value = test()
Can you be sure about the type of value
? There's no guarantee that some_other_module.baz()
didn't call your_module.ints_are_the_bomb()
. So now you need to track all changes that can ever happen to your_module.option_default
, potentially across modules. And if client code (if this is a library) can change the flag, then it's just impossible.
To generalize, the type of a value (including functions) can't change when you mutate something. That could break distant code that also happens to have a reference to this object.
Type-hinting parameters with a sentinel value as the default
Something I like to do — which is only a slight variation on @Blckknght's answer — is to use a metaclass to give my sentinel class a nicer repr and make it always-falsey.
sentinel.py
from typing import Literal
class SentinelMeta(type):
def __repr__(cls) -> str:
return f'<{cls.__name__}>'
def __bool__(cls) -> Literal[False]:
return False
class Sentinel(metaclass=SentinelMeta): pass
main.py
from sentinel import Sentinel
class DEFAULT(Sentinel): pass
You use it in type hints exactly in the same way @Blckknght suggests:
def spam(ham: list[str]|None|type[DEFAULT] = DEFAULT): ...
But you have the added advantages that your sentinel value is always falsey and has a nicer repr:
>>> DEFAULT
<DEFAULT>
>>> bool(DEFAULT)
False
Related Topics
Python: Fastest Way to Create a List of N Lists
Fitting a Normal Distribution to 1D Data
Removing Control Characters from a String in Python
List of All Available Matplotlib Backends
How to Check If One Dictionary Is a Subset of Another Larger Dictionary
Efficient Way to Remove Keys with Empty Strings from a Dict
What Does a Leading '\X' Mean in a Python String '\Xaa'
Mixing Cdef and Regular Python Attributes in Cdef Class
Pandas Equivalent of Oracle Lead/Lag Function
Passing a Data Frame Column and External List to Udf Under Withcolumn
Python Imaging Library - Text Rendering
How to Use If/Else in a Dictionary Comprehension
Default Filter in Django Admin
Anaconda/Conda - Install a Specific Package Version