Reputation: 9816
I'm trying out using Python's type annotations
with abstract class.
My __init__
function looks like this:
from abc import ABCMeta
class SomeClass(object, metaclass=ABCMeta):
def __init__(self, *args, **kwargs):
print("Initiating %s object.", self.__class__.__name__)
self.username = kwargs['data']
assert isinstance(self.username, str)
is_premioum = kwargs.get('premioum', False)
self.money_investmant = kwargs.get('investmant')
if isinstance(self.money_investmant, str):
self.money_investmant = float(self.money_investmant)
As you can see, kwargs
could contain arguments from a several number of types- float
, bool
and str
.
Now, I am trying to write the type annotation for the function, that looks like this:
def __init__(self, *args, **kwargs: Union[bool, str, float]) -> None:
But my PyCharm
IDE alerts me:
Except type 'Integral', got 'str' instead
And:
Cannot find referance 'get' in bool | str | float'
Am I doing something wrong?
How should I write the type annotation for kwargs if it contains arguments from multiple types?
Upvotes: 10
Views: 11765
Reputation: 2699
If one wants to describe specific named arguments expected in kwargs, one can instead pass in a TypedDict which defines required and optional parameters. Optional parameters are what were the kwargs:
This allows one to have unset (NOT None default) optional arguments AND have type hints on them.
This is also useful if they keys have invalid python variable names because TypedDict is the only way to define the types of those values aside from the very general **kwargs value type hinting.
import typing
from abc import ABCMeta
class RequiredProps(typing.TypedDict):
# all of these must be present
data: str
class OptionalProps(typing.TypedDict, total=False):
# these can be included or they can be omitted
premium: bool
investment: typing.Union[str, float]
class ReqAndOptional(RequiredProps, OptionalProps):
pass
class SomeClass(object, metaclass=ABCMeta):
def __init__(self, *args, kwargs: ReqAndOptional):
print("Initiating %s object.", self.__class__.__name__)
self.username = kwargs['data']
assert isinstance(self.username, str)
is_premium = kwargs.get('premium', False)
assert isinstance(is_premium, bool)
self.money_investment = kwargs.get('investment')
assert isinstance(elf.money_investment, (str, float))
if isinstance(self.money_investment, str):
self.money_investment = float(self.money_investment)
Upvotes: 2
Reputation: 160377
See this bug and this bug on the issue tracker for PyCharm. This is apparently an issue with PyCharm's checker; mypy
(another type checker for Python) does not complain when I execute similar code.
There's already a fix for this and, it's apparently available in build 171.2014.23. Until then, I'd suppose Any
would suffice as a temporary workaround to get the checker to stop complaining.
Upvotes: 4