Variable Types in a class - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: Variable Types in a class (/thread-38386.html) |
Variable Types in a class - nafshar - Oct-06-2022 When looking at a class, how do we know what the types of variables are? as an example: class Node: def __init__(self, value, next_node=None, prev_node=None): self.value = value self.next = next_node self.prev = prev_nodeHow do we know that self.next is a "Node" type? Thanks RE: Variable Types in a class - XavierPlatinum - Oct-06-2022 Python has a type() function for just that.print(type(your_variable)) RE: Variable Types in a class - nafshar - Oct-06-2022 (Oct-06-2022, 07:31 PM)XavierPlatinum Wrote: Python has a I realize you can get the type programmatically, but when simply reviewing the code to understand it, how can you tell what the type is? RE: Variable Types in a class - deanhystad - Oct-06-2022 Use type annotations. This example is tricky since Node has not been defined. The convention for this case is to use a string. class Node: def __init__(self, value:float, prev:'Node' = None, next:'Node' = None): self.value = value self.prev = prev self.next = nextYou can also use typing_extensions.Self from typing_extensions import Self class Node: def __init__(self, value:float, prev:Self = None, next:Self = None): self.value = value self.prev = prev self.next = next RE: Variable Types in a class - ndc85430 - Oct-06-2022 The values themselves have types, but the variables that refer to them do not. Python is dynamically typed, so a variable can refer to values of different types: x = 1 # x refers to an integer x = "foo" # now x refers to a stringThere are type hints - see the typing module, though as per the note in the docs, these aren't enforced. RE: Variable Types in a class - Yoriz - Oct-06-2022 You could use a dataclass for thisfrom dataclasses import dataclass from typing import Optional @dataclass class Node: value: float next: Optional["Node"] = None prev: Optional["Node"] = None RE: Variable Types in a class - deanhystad - Oct-07-2022 Other than dataclasses you don't see typing used much for instance variables. This is likely because instance variables are really just entries in a dictionary. Since instance variables are really just dictionary entries, you can add instance variables at any time, not just in the __init__ method. Even dataclass objects allow adding attributes. Using Yoriz' example: from dataclasses import dataclass @dataclass class Node: value: float next: "Node" = None prev: "Node" = None x = Node(5) x.string = "Hello" print(x, x.string) "string" is an attribute of x. x might be the only Node in history to have a "string" attribute, making x not only different from other Note objects by having a unique ID and different instance variable values, but also by having an additional instance variable.If you want to restrict class instances to only having variables that you define, you can also use Pydantic. Defining a class using pydantic looks very, very similar to defining a dataclass. from pydantic import BaseModel class Node(BaseModel): value: float prev: "Node" = None next: "Node" = None x = Node(value=5) x.string = "Hello" Instead of adding a "string" attribute to x we get a ValueError. BaseModel overrides __setattr__() to raise an exception instead of adding the "string":"Hello" to the object dictionary (x.__dict__).Another way to get very similar behavior is using __slots__. class Node(): __slots__ = ("value", "prev", "next") value: float prev: "Node" next: "Node" def __init__(self, value:float, prev:"Node" = None, next:"Node" = None): self.value = value self.prev = prev self.next = next x = Node(value=5) x.string = "Hello" Here we get an AttributeError, which I think is a better choice than a ValueError. The error is raised not because something overrode the normal __setattr__() behavior to prevent adding items to the object dictionary, but because classes that define __slots__ don't have an object dictionary at all. When a class uses __slots__, all instances of the class have the same attributes. The attributes can have different values, but you cannot add any new instance variables.
RE: Variable Types in a class - nafshar - Oct-07-2022 deanhystad - Your explanation of this issue is brilliant and very educational. I am most grateful for the time you took to explain it so clearly. Realizing "instance variables are really just entries in a dictionary" is foundational to understanding python. Not sure how you gained this deep insight into Python, but understanding it at these levels is required by all, especially me :) Yoriz's suggestion of dataclass is also very helpful. Thank you Yoriz. RE: Variable Types in a class - Yoriz - Oct-07-2022 If you are actively using a type checker the following code would flag an error from dataclasses import dataclass from typing import Optional @dataclass class Node: value: float next: Optional["Node"] = None prev: Optional["Node"] = None node = Node(0.1) node.string = "Hello"For instance in vscode with the type checker mode set to at least basic, pylance would put a red line under string and hovering over it would show the following:
Python version 3.10 added slots as a parameter to dataclass, The following can now be done from dataclasses import dataclass from typing import Optional @dataclass(slots=True) class Node: value: float next: Optional["Node"] = None prev: Optional["Node"] = None node = Node(0.1) node.string = "Hello"this will give the same AttributeError: 'Node' object has no attribute 'string' error
RE: Variable Types in a class - deanhystad - Oct-07-2022 I'm not a fan of how decorators look but using @dataclass(slots=True) is so much cleaner than using __slots__. That is a great addition. |