Reputation: 1087
How to annotate the type of an instance variable that is only avaiable after __init__
? I'd like to list all instance attributes inside __init__
as per POLS.
MWE:
class MyClass(object):
def __init__(self):
self.foo :Union[CustomClass, None] = None
def set_foo(self):
self.foo = CustomClass()
def use_foo(self):
self.foo.do_something()
Inside __init__
, if I just annotate foo as self.foo: CustomClass = None
, Pylint will complain:
T484: Incompatible types in assignment (expression has type None, variable has type "CustomClass").
However, if I annotate foo
as self.foo: Union[CustomClass, None] = None
(as in above MWE), PyLint will then complain inside use_foo
function:
T484: "None" has no attribute "do_something".
How do I make PyLint happy? (w/o disabling T484)
Upvotes: 2
Views: 974
Reputation: 9427
The easiest way I can think of is to simply initialise self.foo
to ""
instead of None
.
This means that self.foo.upper()
will be available, so pylint will have no cause to complain.
If you don't want use_foo
to be useable until get_foo
(which probably would be better called set_foo
) is called, you could check to make sure that self.foo
is populated, or keep a boolean field stating whether it has ever been run.
If your class is a little more complicated than a string, you'll have to do a quick check before using self.foo
.
def use_foo(self):
if self.foo is None:
raise EnvironmentError("You haven't called get_foo!")
self.foo.upper()
This is not a very clean solution - I think we can do better.
Lets try outsourcing this check to a decorator;
def ensure_foo(func):
def inner_func(self, *args, **kwargs):
if self.foo is None:
raise EnvironmentError("You haven't called get_foo!")
func(self, *args, **kwargs)
return inner_func
I haven't personally tried this with pylint - but if pylint is clever enough to work out what's going on, slapping @ensure_foo
on top of your class methods is going to be a lot cleaner than putting None checks everywhere...
Upvotes: 2