Is this PyCharm-inspection a false positive? "Cannot find reference '__class__' in 'None'"

183 views Asked by At

In my codebase there is some amount of None.__class__. PyCharm marks this as as a warning:

Cannot find reference '__class__' in 'None'

I am using PyCharm 2022.3 (Community Edition) if that matters.

However, when I try it out in REPL I get this sensible output which seems to be consistent across different python versions (including Python 2.7 and Python 3.10) from what I have tried:

>>> None.__class__
<type 'NoneType'>

Is there a hidden danger I am not seeing? The documentation https://docs.python.org/3/library/constants.html#None seems to suggest NoneType is a proper part of the language and not some implementation-quirk.

1

There are 1 answers

13
bad_coder On

which seems to be consistent across different python-versions (including python2.7 and python3.10)

Location of the NoneType has changed across Python versions, see Where is the NoneType located?

The two main ways of getting NoneType from Python 3.10 onward are calling the builtin type(None) or importing it, both are equivalent although using type(None) saves one import:

from types import NoneType
assert type(None) is NoneType

You may need to adjust PyCharm's inspections to be version specific for your project, see Wrong Python version in PyCharm's inspections.

>>> None.__class__
<type 'NoneType'>

Is there a hidden danger I am not seeing?

Using builtin functions, in this case type(), is always preferred. Calling the builtin type() would also be portable across Python versions.

The alternative of calling the __class__ descriptor directly makes things generally more complicated, see Difference between type(obj) and obj.__class__ and also Python __class__(). Lastly, in typeshed the NoneType is remarkably simple.


I do not think that this is a PyCharm linter bug but that the warning follows the same trend as mypy, see Warn when NoneType is used in a type #11288 and Treating NoneType as None and warning against using NoneType. #13153.

In effect, using mypy on the snippet:

from types import NoneType

my_var = None.__class__
the_type: NoneType = my_var

gives:

nonetype_test.py:4: error: NoneType should not be used as a type, please use None instead  [valid-type]
nonetype_test.py:4: error: Incompatible types in assignment (expression has type "Type[None]", variable has type "None")  [assignment]

If instead we use builtins.type with subscripting (see the end note under the deprecated typing.Type):

the_type2: type[None] = type(None)

Mypy doesn't complain (and neither does the PyCharm linter):

Success: no issues found in 1 source file