I am trying to do the equivalent of:
class A:
def __init__(self):
self.b = self.get_b()
def get_b(self):
return 1
using @dataclass
. I want to use a @dataclass
here because there are other (omitted) fields initialized from provided constructor arguments. b
is one of the fields that is initialized from an instance method's result. Executing this:
@dataclass
class A:
b = self.get_b()
def get_b(self):
return 1
shows that self
is not defined in b
's scope. Is it possible to get a reference to self
here?
Use the __post_init__
method.
from dataclasses import dataclass, field
@dataclass
class A:
b: int = field(init=False)
def __post_init__(self):
self.b = self.get_b()
Not exactly an improvement, is it? The default value assigned to a field is equivalent to a default parameter value in __init__
, e.g.,
def __init__(self, b=0):
self.b = b
Just like you can't use self
in such a parameter default, you can't use it as the field default value. The default value has to exist before the instance actually exists.
We create the field explicitly so that we can pass init=False
, preventing the generated __init__
method from expecting an argument to initialize self.b
.
If the function get_b
is really independent of an instance (that is, you don't need an instance of A
in order to return the value 1
), you can use an already defined function as a default factory.
from dataclasses import dataclass, field
@dataclass
class A:
def get_b(self=None):
return 1
b: int = field(default_factory=get_b, init=False)
Here, get_b
will be called as a function with zero arguments (hence the default value for self
in the definition) rather than be invoked from a class instance. This is, though, rather unorthodox and I wouldn't recommend structuring your code like this.