'Dynamic Type Annotation and Adding a key-value-pair for pep8 [duplicate]
I'm currently working through "Python Crash Course" from No Starch and I'm trying to get used to pep8, by writing the code examples with flake8.
from typing import Any
def build_person(
first_name: str,
last_name: str,
age: int = None) -> Any:
#Expression of type "None" cannot be assigned to parameter of type "int"
#Type "None" cannot be assigned to type "int"
"""Return a dictionary of information about a person."""
person = {"first": first_name, "last": last_name}
if age:
person["age"] = age
#Argument of type "int" cannot be assigned to parameter "__v" of type "str"
#in function "__setitem__"
"int" is incompatible with "str"
return person
musician = build_person("Jimi", "Hendrix", 25)
print(musician)
In this piece of code I'm not really sure how I should do the type annotation for the age argument. I want it to be an int when used, but simply a Nonewhen not used, but None is obviously not an int. Naturally flake8 complains. Also I'm not sure how to annotate the dynamically changing return dict.
Is this simply a case where adherence to pep8 does not make sense, or is there an easy solution?
Secondly, flake8 seems to be unhappy about my way of adding a key-value-pair to the dictionary. I'm not sure what the corresponding message means though.
Solution 1:[1]
You probably want to use either
age: int | None = None
or
from typing import Optional
...
age: Optional[int] = None
or
from typing import Union
...
age: Union[int, None] = None
All expressions are equivalent.
Solution 2:[2]
A valid annotation for this function that avoids the use of Any would be:
from typing import Dict, Optional, Union
def build_person(
first_name: str,
last_name: str,
age: Optional[int] = None
) -> Dict[str, Union[int, str]]:
"""Return a dictionary of information about a person."""
person: Dict[str, Union[int, str]] = {
"first": first_name,
"last": last_name
}
if age:
person["age"] = age
return person
musician = build_person("Jimi", "Hendrix", 25)
print(musician)
A better option than Dict[str, Union[int, str]] IMO would be a TypedDict, which specifies the types of each key individually:
from typing import Optional, TypedDict
class _PersonRequired(TypedDict, total=True):
# Required fields for Person.
first: str
last: str
class Person(_PersonRequired, total=False):
age: int
def build_person(
first_name: str,
last_name: str,
age: Optional[int] = None
) -> Person:
"""Return a dictionary of information about a person."""
person = Person(first=first_name, last=last_name)
if age:
person["age"] = age
return person
musician = build_person("Jimi", "Hendrix", 25)
print(musician)
but better still would be avoiding Dict entirely here and using a @dataclass, which is actually built for this exact type of use case:
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class Person:
first: str
last: str
age: Optional[int] = None
musician = Person("Jimi", "Hendrix", 25)
print(musician)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |
