Tooltip Type for Python Instance Variables

Not sure about the Python convention for variable types like hinting - I did them in the arguments of the __init__ constructor, as shown here:

 class LoggedVar(Generic[T]): def __init__(self, value: T, name: str, logger: Logger) -> None: self.name = name self.logger = logger self.value = value` 

link to the above code snippet: https://docs.python.org/3/library/typing.html#user-defined-generic-types

But I also see PEP conventions annotating instance variables as such (snippet below), and then also introducing types in __init__ arguments:

 class BasicStarship: captain: str = 'Picard' # instance variable with default damage: int # instance variable without default stats: ClassVar[Dict[str, int]] = {} # class variable` def __init__(self, damage: int, captain: str = None): self.damage = damage if captain: self.captain = captain # Else keep the default 

Finally, later in article PEP526 it is said that for convenience and conditionality the following can be done:

 class Box(Generic[T]): def __init__(self, content): self.content: T = content 

url for the two above code snippets: https://www.python.org/dev/peps/pep-0526/#class-and-instance-variable-annotations

So, is one of these conventions better / more widely accepted than the others I should strive for (better readability, etc.)?

+5
source share
2 answers

I would recommend using the first version, where you assign types to your __init__ method parameters for most cases.

This particular method has the least amount of redundancy, while still allowing type inspectors to verify that you are calling this __init__ method correctly elsewhere in your code.

I would recommend using either the second or third version, where you explicitly annotate your fields (inside or outside __init__ ), when your __init__ method has become quite complicated to the point where one or more of the following statements apply:

  • It’s not so clear what exactly your fields should begin with
  • There is no longer a mapping between your parameters and your fields
  • You have complex initialization logic that hides how your fields are assigned.

However, it was not clear to me whether the second or third version is preferable - I personally prefer the third version because it is more conceptually clean and does not seem to confuse the concept of instance attributes with a class, but I can’t deny that the second version looks cleaner.

I asked about this on the gitter β€œinput” channel and received the following response from Guido (which, regardless of what you did not know, made Python and is currently working on mypy and is compiling similar materials):

It seems that in any case there are strong opinions. I really prefer to add attribute annotations to the body of the class, rather than spatter them across all __init__ and other methods. I also think that with PEP 526 this will be the future (also with things like class-based NamedTuple declarations and possibly https://github.com/ericvsmith/dataclasses ).

( link to quote )

So, it seems that the second version is recommended compared to the third, and that the definition of classes in this way will become more deeply integrated into the Python language itself at some point in the future!

Edit: PEP 557, data classes was recently adopted and appears to be included for inclusion in Python 3.7.

+1
source

I would stick to what you do in LoggedVar, it follows the same rules as everywhere else in Python, so there is less and less confusion.

The BasicStarShip class changes the scope of variables by moving them from the __init__ function. With the captain, announced that BasicStarShip.captain will return "Picard".

PEP526 annotations are nice to read, but this new rule for one specific case is the __init__ function. From Zen of Python : "Special cases are not complex enough to break the rules."

+1
source

Source: https://habr.com/ru/post/1269579/


All Articles