Python Class Constructors

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 18

Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

1 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

.__init__()

.__new__()

class

>>> class SomeClass:


... pass
...

>>> # Call the class to construct an object


>>> SomeClass()
<__main__.SomeClass object at 0x7fecf442a140>

SomeClass class
pass

SomeClass

2 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

.__call__()

.__new__()
.__init__()

.__init__() self

.__new__()
.__init__()

Point
.__new__() .__init__()

# point.py

class Point:
def __new__(cls, *args, **kwargs):
print("1. Create a new instance of Point.")
return super().__new__(cls)

def __init__(self, x, y):


print("2. Initialize the new instance of Point.")
self.x = x
self.y = y

def __repr__(self) -> str:


return f"{type(self).__name__}(x={self.x}, y={self.y})"

Point class

.__new__() cls
self *args
**kwargs

.__new__()

Point .__new__() cls


object super()
.__init__()

.__init__() self
x y
.x .y
Point()

3 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

.__init__()

.x .y x y

.__repr__() Point

Point point.py

>>> from point import Point

>>> point = Point(21, 42)


1. Create a new instance of Point.
2. Initialize the new instance of Point.

>>> point
Point(x=21, y=42)

Point()
point

.__new__() .__init__() Point

>>> from point import Point

>>> point = Point.__new__(Point)


1. Create a new instance of Point.

>>> # The point object is not initialized


>>> point.x
Traceback (most recent call last):
...
AttributeError: 'Point' object has no attribute 'x'
>>> point.y
Traceback (most recent call last):
...
AttributeError: 'Point' object has no attribute 'y'

>>> point.__init__(21, 42)


2. Initialize the new instance of Point.

>>> # Now point is properly initialized


>>> point
Point(x=21, y=42)

.__new__() Point

.__init__()

.__init__()
Point

.__new__()

4 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

.__init__()

.__new__() B A

# ab_classes.py

class A:
def __init__(self, a_value):
print("Initialize the new instance of A.")
self.a_value = a_value

class B:
def __new__(cls, *args, **kwargs):
return A(42)

def __init__(self, b_value):


print("Initialize the new instance of B.")
self.b_value = b_value

B.__new__() B.__init__()
ab_classes.py

>>> from ab_classes import B

>>> b = B(21)
Initialize the new instance of A.

>>> b.b_value
Traceback (most recent call last):
...
AttributeError: 'A' object has no attribute 'b_value'

>>> isinstance(b, B)
False
>>> isinstance(b, A)
True

>>> b.a_value
42

B() B.__new__() A B B.__init__()


b .b_value b .a_value 42

.__init__() .__new__()

.__init__()
.__init__()
.__init__()

.__init__()

5 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

.__init__()
Rectangle .width .height

>>> class Rectangle:


... def __init__(self, width, height):
... self.width = width
... self.height = height
...

>>> rectangle = Rectangle(21, 42)


>>> rectangle.width
21
>>> rectangle.height
42

.__init__() self
.__new__() .__init__()
.width .height width height
.__init__()

self .__init__()
.__init__()

.__init__() None TypeError

>>> class Rectangle:


... def __init__(self, width, height):
... self.width = width
... self.height = height
... return 42
...

>>> rectangle = Rectangle(21, 42)


Traceback (most recent call last):
...
TypeError: __init__() should return None, not 'int'

.__init__() TypeError

.__init__() None None


return None

.__init__() .width .height

.__init__()
Rectangle width height

6 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

>>> class Rectangle:


... def __init__(self, width, height):
... if not (isinstance(width, (int, float)) and width > 0):
... raise ValueError(f"positive width expected, got {width}")
... self.width = width
... if not (isinstance(height, (int, float)) and height > 0):
... raise ValueError(f"positive height expected, got {height}")
... self.height = height
...

>>> rectangle = Rectangle(-21, 42)


Traceback (most recent call last):
...
ValueError: positive width expected, got -21

.__init__() width height


.width .height ValueError

.__init__() .__init__()
super()

>>> class Person:


... def __init__(self, name, birth_date):
... self.name = name
... self.birth_date = birth_date
...

>>> class Employee(Person):


... def __init__(self, name, birth_date, position):
... super().__init__(name, birth_date)
... self.position = position
...

>>> john = Employee("John Doe", "2001-02-07", "Python Developer")

>>> john.name
'John Doe'
>>> john.birth_date
'2001-02-07'
>>> john.position
'Python Developer'

.__init__() Employee super().__init__() name birth_date


.name .birth_date Person

.__init__() object
.__init__()

7 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

.__init__()

Greeter

# greet.py

class Greeter:
def __init__(self, name, formal=False):
self.name = name
self.formal = formal

def greet(self):
if self.formal:
print(f"Good morning, {self.name}!")
else:
print(f"Hello, {self.name}!")

.__init__() name formal


False formal

formal False
.greet()

Greeter greet.py

>>> from greet import Greeter

>>> informal_greeter = Greeter("Pythonista")


>>> informal_greeter.greet()
Hello, Pythonista!

>>> formal_greeter = Greeter("Pythonista", formal=True)


>>> formal_greeter.greet()
Good morning, Pythonista!

informal_greeter name
formal .greet() informal_greeter

name formal Greeter formal True


.greet()

.__init__()
.__new__()

.__new__()
.__new__()
object

.__new__()

8 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

int float tuple str

.__new__()

.__new__()

super().__new__()

class SomeClass:
def __new__(cls, *args, **kwargs):
instance = super().__new__(cls)
# Customize your instance here...
return instance

.__new__() .__new__()
cls

*args **kwargs
.__new__() *args **kwargs

.__new__() .__new__()
.__new__() super()
object.__new__() .__new__()

object

object.__new__()
object.__new__() TypeError

>>> class SomeClass:


... def __new__(cls, *args, **kwargs):
... return super().__new__(cls, *args, **kwargs)
... def __init__(self, value):
... self.value = value
...

>>> SomeClass(42)
Traceback (most recent call last):
...
TypeError: object.__new__() takes exactly one argument (the type to instantiate)

*args **kwargs super().__new__()


object.__new__() TypeError

object.__new__() .__init__()

9 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

.__new__() SomeClass

>>> class SomeClass:


... def __init__(self, value):
... self.value = value
...

>>> some_obj = SomeClass(42)


>>> some_obj
<__main__.SomeClass object at 0x7f67db8d0ac0>
>>> some_obj.value
42

SomeClass .__new__() object.__new__()


value SomeClass.__init__()
SomeClass some_obj

.__new__()

.__new__()
Distance float

.__init__()

>>> class Distance(float):


... def __init__(self, value, unit):
... super().__init__(value)
... self.unit = unit
...

>>> in_miles = Distance(42.0, "Miles")


Traceback (most recent call last):
...
TypeError: float expected at most 1 argument, got 2

float.__new__()
object.__new__()

.__new__() .__init__()

10 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

>>> class Distance(float):


... def __new__(cls, value, unit):
... instance = super().__new__(cls, value)
... instance.unit = unit
... return instance
...

>>> in_miles = Distance(42.0, "Miles")


>>> in_miles
42.0
>>> in_miles.unit
'Miles'
>>> in_miles + 42.0
84.0

>>> dir(in_miles)
['__abs__', '__add__', ..., 'real', 'unit']

.__new__()
cls super().__new__() float.__new__()
value .unit

Distance
Distance(10, "km") + Distance(20, "miles")

Distance
Distance .unit
dir()
float

.__new__()

Pet .__new__()

11 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

# pets.py

from random import choice

class Pet:
def __new__(cls):
other = choice([Dog, Cat, Python])
instance = super().__new__(other)
print(f"I'm a {type(instance).__name__}!")
return instance

def __init__(self):
print("Never runs!")

class Dog:
def communicate(self):
print("woof! woof!")

class Cat:
def communicate(self):
print("meow! meow!")

class Python:
def communicate(self):
print("hiss! hiss!")

Pet .__new__()

Pet

>>> from pets import Pet

>>> pet = Pet()


I'm a Dog!
>>> pet.communicate()
woof! woof!
>>> isinstance(pet, Pet)
False
>>> isinstance(pet, Dog)
True

>>> another_pet = Pet()


I'm a Python!
>>> another_pet.communicate()
hiss! hiss!

Pet
.__new__() .__new__()

.__init__() Pet Pet.__new__()


Pet

.__new__()

12 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

Singleton .__new__()
.__new__()

>>> class Singleton(object):


... _instance = None
... def __new__(cls, *args, **kwargs):
... if cls._instance is None:
... cls._instance = super().__new__(cls)
... return cls._instance
...

>>> first = Singleton()


>>> second = Singleton()
>>> first is second
True

Singleton ._instance None


.__new__() cls._instance is None

Singleton .__init__()
.__init__() Singleton()

if Singleton cls._instance

Singleton first second


is first second
Singleton

collections.namedtuple
.__new__()
collections.namedtuple() namedtuple() tuple

named_tuple_factory()
.__new__() NamedTuple

13 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

# named_tuple.py

from operator import itemgetter

def named_tuple_factory(type_name, *fields):


num_fields = len(fields)

class NamedTuple(tuple):
__slots__ = ()

def __new__(cls, *args):


if len(args) != num_fields:
raise TypeError(
f"{type_name} expected exactly {num_fields} arguments,"
f" got {len(args)}"
)
cls.__name__ = type_name
for index, field in enumerate(fields):
setattr(cls, field, property(itemgetter(index)))
return super().__new__(cls, args)

def __repr__(self):
return f"""{type_name}({", ".join(repr(arg) for arg in self)})"""

return NamedTuple

itemgetter() operators

named_tuple_factory() type_name
*fields

NamedTuple tuple

.__slots__
.__dict__

.__new__() cls *args

TypeError

.__name__ type_name

for itemgetter()
index setattr() enumerate()
index

super().__new__()

.__repr__()

NamedTuple

named_tuple_factory() named_tuple.py

14 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

>>> from named_tuple import named_tuple_factory

>>> Point = named_tuple_factory("Point", "x", "y")

>>> point = Point(21, 42)


>>> point
Point(21, 42)
>>> point.x
21
>>> point.y
42
>>> point[0]
21
>>> point[1]
42

>>> point.x = 84
Traceback (most recent call last):
...
AttributeError: can't set attribute

>>> dir(point)
['__add__', '__class__', ..., 'count', 'index', 'x', 'y']

Point named_tuple_factory()

Point .x .y

AttributeError

dir() point

.__new__() .__init__()

.__new__() .__init__()

.__init__()

.__new__()

15 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

16 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

17 of 18 4/1/2022, 9:18 PM
Python Class Constructors: Control Your Object Instantiation – Real Python https://realpython.com/python-class-constructor/#:~:text=Class%20constructors%20are%20a%20fu...

⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅

18 of 18 4/1/2022, 9:18 PM

You might also like