在 Python 中,类的部分用途是用来表示数据。正是通过使用 __init__ 函数,我们可以在创建对象时接受数据,并使用 self 关键字将这些数据值分配给对象。你可能会注意到,有时这个代码设置有很多模板。换句话说,你必须写相同结构的代码来简单地在一个对象上存储简单的值。这有时会显得很冗长。这就是Python数据类出现的地方。从Python 3.7版开始,你可以使用一种新的语法来创建类,以便在你的应用程序中保存数据,这就是我们将在本教程中研究的内容。
数据类的定义
回顾一下我们在 Python 中使用 __init__ 和 super() 定义一个类的通常方式。
class Book():
def __init__(self, title, author, price):
super().__init__()
self.title = title
self.author = author
self.price = price
def __str__(self):
return f'{self.title} by {self.author}, costs {self.price}'
def __repr__(self):
return f'title={self.title},author={self.author},price={self.price}'
book1 = Book('Python Crash Course', 'Eric Matthes', 23.99)
book2 = Book('Serious Python', 'Julien Danjou', 25.43)
# print each object
print(book1)
print(book2)
# use str() and repr()
print(str(book1))
print(repr(book2))
Python Crash Course by Eric Matthes, costs 23.99
Serious Python by Julien Danjou, costs 25.43
Python Crash Course by Eric Matthes, costs 23.99
title=Serious Python,author=Julien Danjou,price=25.43
现在让我们用数据类的方法来看看。要使用数据类,你必须使用from dataclasses import dataclass 来导入它们。然后我们需要用**@dataclass**装饰器来装饰这个类。下面的代码有较少的模板,但我们仍然得到了我们期望的输出。
from dataclasses import dataclass
@dataclass
class Book():
title: str
author: str
price: float
def __str__(self):
return f'{self.title} by {self.author}, costs {self.price}'
def __repr__(self):
return f'title={self.title},author={self.author},price={self.price}'
book1 = Book('Python Crash Course', 'Eric Matthes', 23.99)
book2 = Book('Serious Python', 'Julien Danjou', 25.43)
# print each object
print(book1)
print(book2)
# use str() and repr()
print(str(book1))
print(repr(book2))
Python Crash Course by Eric Matthes, costs 23.99
Serious Python by Julien Danjou, costs 25.43
Python Crash Course by Eric Matthes, costs 23.99
title=Serious Python,author=Julien Danjou,price=25.43
后期初始化
如果你决定使用数据类,你可以访问一个__post_init__方法,它可以执行额外的对象初始化,因为数据类像魔术一样自动处理了init函数。数据类装饰器提供了一个名为__post_init__的特殊函数,你可以覆盖它,它在内置的 init 函数完成后被调用。下面是一个实际操作的例子。
from dataclasses import dataclass
@dataclass
class Book:
title: str
author: str
pages: int
price: float
# the __post_init__ function lets us customize additional properties
# after the object has been initialized via built-in __init__
def __post_init__(self):
self.description = f'{self.title} by {self.author}, {self.pages} pages'
# create some Book objects
book1 = Book('Python Crash Course', 'Eric Matthes', 544, 23.99)
book2 = Book('Serious Python', 'Julien Danjou', 225, 25.43)
# use the description attribute
print(book1.description)
print(book2.description)
Python Crash Course by Eric Matthes, 544 pages
Serious Python by Julien Danjou, 225 pages
默认值
在 Python 中使用类的一部分是利用在运行时为对象设置默认值的能力。由于数据类会自动处理__init__方法,这一点似乎在数据类中被忽略了。你仍然可以使用缺省值,但是语法上有些不同。这里有一个例子。
from dataclasses import dataclass, field
@dataclass
class Book:
# you can define default values when attributes are declared
title: str = 'Empty Book'
author: str = 'Your Imagination'
pages: int = 0
price: float = 0.0
# Create a default book object
book1 = Book()
print(book1)
# Create a specified book, price is set by field operator
book1 = Book('Python Crash Course', 'Eric Matthes', 544, 23.99)
book2 = Book('Serious Python', 'Julien Danjou', 225, 25.43)
print(book1)
print(book2)
Book(title='Empty Book', author='Your Imagination', pages=0, price=0.0)
Book(title='Python Crash Course', author='Eric Matthes', pages=544, price=23.99)
Book(title='Serious Python', author='Julien Danjou', pages=225, price=25.43)
不可变的数据类
在这个数据类教程中,我们要看的最后一件事是如何制作不可变的对象。这可以通过简单地将frozen=True传递给@dataclass装饰器来实现。
from dataclasses import dataclass
@dataclass(frozen=True)
class Book:
title: str
author: str
pages: int
price: float
# You can define methods in a dataclass like any other
def bookinfo(self):
return f'{self.title}, by {self.author}'
# create some instances
book1 = Book('Python Crash Course', 'Eric Matthes', 544, 23.99)
book2 = Book('Serious Python', 'Julien Danjou', 225, 25.43)
# access fields
print(book1.title)
print(book2.author)
# print the book itself - dataclasses provide a default
# implementation of the __repr__ function
print(book1)
# comparing two dataclasses
book3 = Book('Automate the Boring Stuff with Python', 'Al Sweigart ', 592, 26.99)
print(book1 == book3)
# change some fields, call a regular class method
book1.title = 'Python for Kids'
book1.pages = 864
print(book1.bookinfo())
Python Crash Course
Julien Danjou
Book(title='Python Crash Course', author='Eric Matthes', pages=544, price=23.99)
False
Traceback (most recent call last):
File "C:/python/OOP/dataclass.py", line 33, in
book1.title = 'Python for Kids'
File "", line 3, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'title'