Reputation: 3205
With the type hinting syntax specified in PEP 484 and 585, is there any way to indicate that a function's parameter should be a mutable reference that would be modified by the function?
For instance, C# has ref
paramters, so in Python, is there any equivalent? e.g.
>>> def foo(spam: "Mutable[List[int]]"):
... spam.append(sum(spam))
...
>>> a = [1, 2, 3]
>>> foo(a)
>>> a
[1, 2, 3, 6]
or if not, how could I define such a type without causing the inspection logic to think that it was a special Mutable
class instead of a List[int]
? Obviously this would be used as a tool for the developer to understand a method more easily, instead of one that would be used to fundamentally change the program.
For clarity, I'm aware that Lists by definition are mutable, but I'm wondering if there is a way to define when it will be mutated, for example
>>> def bar(sandwich: Mutable[List[str]], fridge: List[str]):
... sandwich.extend(random.sample(fridge, k=3))
Upvotes: 5
Views: 393
Reputation: 64228
Lists, by default, are considered to always be mutable. So if you want to indicate some list will never be changed, it's better to indicate that explicitly by using some read-only interface or protocol such as typing.Sequence
or typing.Collection
instead.
These two types are meant to have the same semantics as the corresponding collections.abc types. I suppose you can kind of think of them as roughly the same as C#'s IReadOnlyCollection.
from typing import Sequence, overload
def foo(seq: Sequence[int]) -> None:
# This type checks
for item in seq:
print(seq)
# ...but this does not. Mypy reports a
# '"Sequence[int]" has no attribute "append" error', for example
seq.append(5)
# This type checks, since lists satisfy the Sequence protocol
foo([1, 2, 3, 4])
# Same thing with tuples
foo((1, 2, 3, 4))
class CustomSequence(Sequence[int]):
@overload
def __getitem__(self, i: int) -> int: ...
@overload
def __getitem__(self, s: slice) -> Sequence[int]: ...
def __getitem__(self, x: Union[int, slice]) -> Union[int, Sequence[int]]:
if isinstance(x, int):
return 1
else:
return [1, 2]
def __len__(self) -> int:
return 1
# Or any other kind of Sequence, actually.
foo(CustomSequence())
And if you want a general-purpose mutable sequence, use MutableSequence
. Note that lists satisfy both the Sequence and MutableSequence protocols.
Upvotes: 3
Reputation: 5473
Lists are mutable in Python and thus an explicit Mutable
class reference is not required:
In [3]: from typing import List
In [7]: def foo(spam:List[int]):
...: spam.append(sum(spam))
...: return spam
In [8]: a = [1,2,3]
In [9]: foo(a)
Out[9]: [1, 2, 3, 6]
Upvotes: 3