In practice most constructor implementations are trivial in that they simply map self
attributes to correspondingly named parameters.
class Foo:
x: int
y: int
z: int
def __init__(self, x: int, y: int, z: int):
self.x = x
self.y = y
self.z = z
The typical workflow consists of a) annotating the types for each attribute, b) creating parameters for said attributes, c) assigning attributes to the parameters. This is 3x more typing than necessary. Modern languages have provided a way to reduce this repetitive ceremony.
Kotlin and Scala have primary constructors that will function as field type annotations, parameter declarations, and implicit assignments to the parameter arguments all at once.
class Foo (
var x: Int,
var y: Int,
var z: Int
)
var foo = Foo(3,7,5)
TypeScript also provides a shorthand notation for this behavior
class Foo {
constructor(
public x: number,
public y: number,
public z: number
) {}
}
var foo = new Foo(3,7,5)
Swift has automatic initializers for structs.
After using these languages, manually writing class constructors in Python feels like a chore.
In Python, the @dataclass
decorator does allow for this
from dataclasses import dataclass
@dataclass
class Foo:
x: int
y: int
z: int
foo = Foo(5,7,3)
however it is not the standalone behavior, but includes other undesired effects like making the object unhashable (and so unable to be added to sets) by default, along with value object notions of __eq__
and other magic methods the user is forced to opt into by using the decorator. I may not want to represent an entity as a âdata classâ, but still get the automatic constructor behavior.
Requiring an import statement is also annoying, since automatic constructors is something Iâd like to opt into for nearly every class I ever write, so I will have to write this in nearly every file. It would be the norm rather than the exception. Providing this either as a globally accessible decorator or as a dedicated syntax construct would be good for having reasonable defaults.
Besides a class decorator or dedicated keyword, perhaps a decorator specifically for the __init__()
method would work. (But again, without requiring an import statement please.)
class Foo:
@auto
def __init__(self, x: int, y: int, z: int):
... # automatically assigns self.x = x, self.y = y, self.z = z