In the example below. The init method of MyClass defined the attribute self._user
has optionally the type of UserInput
and is initialized as None
. The actual user input should be provided by the method set_user
. For some practical reason, the user input cannot be provided to the method __init__
. After giving user input, other methods method_1
and method_2
can be called.
Question to professional Python programmers: do I really need to add assert ... not None
in every method that uses self._user
? Otherwise, VS Code Pylance
type checking will complain that self._user
might be None
.
However, I tried the same code in PyCharm with its built-in type checking. This issue is not raised there.
And as professional Python programmers, do you prefer the Pylance
type checking in VS Code, or the built-in type checking in PyCharm?
Thanks in advance.
class UserInput:
name: str
age: int
class MyClass:
def __init__(self):
self._user: UserInput | None = None
def set_user(self, user: UserInput): # This method should be called before calling any methods.
self._user = user
def method_1(self):
assert self._user is not None # do I actually need it
# do something using self._user, for example return its age.
return self._user.age # Will get warning without the assert above.
def method_2(self):
assert self._user is not None # do I actually need it
# do something using self._user, for example return its name.
CodePudding user response:
I think it's safest and cleanest if you keep the assert
s in. After all, it is up to the user of your class in which order he calls the instance methods. Therefore, you cannot guarantee that self._user
is not None
.
CodePudding user response:
I think it's bad practice to use assert
in production code. When things go wrong, you get lots of AssertionError
, but you don't have any context about why that assertion is being made.
Instead I would catch the issue early, and not handle it later. If set_user()
should be called earlier, I'd be tempted to put the user in the __init__
method, but the same principle applies.
@dataclass
class UserInput:
name: str
age: int
class NoUserException(TypeError):
pass
class MyClass:
# Or this could be in the __init__ method
def set_user(self, user: UserInput | None):
if not user:
raise NoUserException()
self._user: user
def method_1(self):
# do something using self._user, for example return its age.
return self._user.age
def method_2(self):
# do something using self._user, for example return its name.
return self._user.name
You already stated that set_user
will be called first, so when that happens you'll get a NoUserException
if the user is None.
But I'd be tempted to not even do that. If I were writing this, I'd have no NoneType checking in MyClass
, and instead not call set_user
if the user was None.
m = MyClass()
user = ...
if user:
m.set_user(user)
... # anything else with `m`
else:
# here is where you would get an error