When I define a class, how can I include arguments in its methods' signatures which have to be of the same class? I am building a graph structure which should work like this, but here is a simplified example:
class Dummy:
def __init__(self, value: int, previous: Dummy=None):
self._value = value
self._previous = previous
@property
def value(self):
return self._value
def plus_previous(self):
return self.value + self._previous.value
d1 = Dummy(7)
d2 = Dummy(3, d1)
d2.plus_previous()
This results in the following error:
NameError: name 'Dummy' is not defined
I mean, I can do it the Python 2 way, but I was hoping there is a more python-3-ic solution than this:
class Dummy:
def __init__(self, value: int, previous=None):
assert type(previous) is Dummy or previous is None
...
Although I agree, it is a rather ugly hack, you can use strings as type hints as well:
class Dummy:
def __init__(self, value: int, previous: 'Dummy'=None):
self._value = value
self._previous = previous
@property
def value(self):
return self._value
def plus_previous(self):
return self.value + self._previous.value
as is described in PEP-484 on type hints:
When a type hint contains names that have not been defined yet, that definition may be expressed as a string literal, to be resolved later.
A situation where this occurs commonly is the definition of a container class, where the class being defined occurs in the signature of some of the methods. For example, the following code (the start of a simple binary tree implementation) does not work:
class Tree: def __init__(self, left: Tree, right: Tree): self.left = left self.right = right
To address this, we write:
class Tree: def __init__(self, left: 'Tree', right: 'Tree'): self.left = left self.right = right
The string literal should contain a valid Python expression (i.e.,
compile(lit, '', 'eval')
should be a valid code object) and it should evaluate without errors once the module has been fully loaded. The local and global namespace in which it is evaluated should be the same namespaces in which default arguments to the same function would be evaluated.
A problem with this hack however is that if you do a rename in the IDE, it is definitely possible that the IDE will not take these string literals into account and thus fail to rename these.