In Python, can you have classes with members that are themselves pointers to members of the type of the same class? For example, in C, you might have the following class for a node in a binary tree:
struct node {
int data;
struct node* left;
struct node* right;
}
How would you equivalently create this in python?
I think this might be helpful
from typing_extensions import Self
class Node:
"""Binary tree node."""
def __init__(self, left: Self, right: Self):
self.left = left
self.right = right
typing_extensions offers a Self class to reference class itself which I think is most elegent way to self-reference(PEP 673).
As others have mentioned, you can also use string literals. But it comes to problem when you have multiple type hints.
# python 3.10
var: str | int
And then you write something like
class Node:
def __init__(self, var: 'Node' | SomeClass):
self.var = var
It will raise an TypeError: unsupported operand type(s) for |: 'str' and 'type'.
While this, as other answers have pointed out, is not a problem due to the dynamic typing, in fact, for Python3, this is a very real issue when it comes to type annotations. And this will not work (note a type annotation of the method argument):
class A:
def do_something_with_other_instance_of_a(self, other: A):
print(type(other).__name__)
instance = A()
other_instance = A()
instance.do_something_with_other_instance_of_a(other_instance)
results in:
def do_something_with_other_instance_of_a(self, other: A):
NameError: name 'A' is not defined
more on the nature of a problem here: https://www.python.org/dev/peps/pep-0484/#the-problem-of-forward-declarations
and this is the only way if you have to keep your code compatible with earlier versions of Python.
Instead, for the sake of getting autocompletion in my IDE (PyCharm), you can docstrings like this:
Update: alternatively, instead of using docstrings, you can use "type: " annotations in a comment. This will also ensure that mypy static type checking will work (mypy doesn't seem to care about docstrings):
This question deserves a revamp for 2021. Let's get some code then run through a breakdown.
from __future__ import annotations
from dataclasses import dataclass
@dataclass
class Node:
data: int
left: Node
right: Node
As of Python 3.7, we have PEP 563 -- Postponed Evaluation of Annotations, which means one can use type hints to reference the class, inside the class. It does need to be enabled, which is what our first line of code does.
The @dataclass
decorator is part of the Data Classes, also added in 3.7, and gives us a convenient way of defining
a class, especially one that is primarily members definitions.
I have used Node
rather than node
, since class names are usually capitalised in python, to avoid collision with variables and modules. This is a stylistic thing and can be safely ignored most of the time.
Finally, from Python 3.10, you can drop the from __future__...
import as it will be enabled by default. The release date for that is... Oh, it's today!
Emulating a C struct in Python (using str instead of int as the data type):
"Declaration":
class Node(object):
data = None # str
left = None # Node object or None
right = None # Node object or None
Usage:
root = Node()
root.data = "foo"
b = Node()
b.data = "bar"
root.left = b
z = Node()
z.data = "zot"
root.right = z
Python is a dynamic language. Attributes can be bound at (almost) any time with any type. Therefore, the problem you are describing does not exist in Python.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With