Python - 数据类构建器
数据类构建器概述
class Coordinate:
def __init__(self, lat, lon):
self.lat = lat
self.lon = lon
Coordinate 类的作用是保存经纬度属性,为__init__方法编写样板代码容易让人感到枯燥,尤其是属性较多的时候。想想看,每一个属性都要写3次。更糟糕的是,样板代码并没有给我们提供Python 对象都有的基本功能
>>> moscow = Corrdinate(55.76,37.62)
>>> moscow # 莫斯科
<__main__.Corrdinate object at 0x000001DA7AC0B040> # 1
>>> location = Corrdinate(55.76,37.62)
>>> location == moscow # 2
False
>>> (location.lat,location.lon) == (moscow.lat,moscow.lon) # 3
True
- 1: 继承自object 的__repr__ 作用不大
- 2:== 没有意义,因为继承自object的__eq__方法比较对象的ID
- 3:想要比较两个地理位置的经纬度,只能一一比较各个属性。
下面使用nammedtuple 构建Coordinate 类。namedtuple 使一个工厂方法,使用指定的名称和字段构建 tupple 子类
>>> from collections import namedtuple
>>> Corrdinate = namedtupe('Corrdinate','lat lon')
>>> issubclass(Corrdinate,tuple)
True
>>> moscow = Corrdinate(55.756,37.617)
>>> moscow
Corrdinate(lat=55.756, lon=37.617) # 1
>>> moscow == Corrdinate(lat=55.756,lon=37.617) # 2
True
>>>
- 1: 有用的__repr__
- 2: 有意义的__eq__
新出现的typing.NamedTuple 具有一样的功能,不过可以为各个字段添加类型注解
>>> import typing
>>> Corrdinate = typing.NamedTuple('Corrdinate',[('lat',float),('lon',float)]) # Corrdinate = typing.NamedTuple('Corrdinate',lat=float,lon=float)。这种写法也可以可读性更高
>>> issubclass(Corrdinate,tuple)
True
>>> typing.get_type_hints(Corrdinate)
{'lat': <class 'float'>, 'lon': <class 'float'>}
从Python 3.6 开始,typing.NamedTuple 也可以在class 语句中使用,类型注解按 "PEP256 - Syntax For Variable Annotations" 标准编写。这样写出的代码可读性更高,而且方便
覆盖方法或添加新方法,下面再次定义了Corrdinate 类,经纬度属性均为float 类型,同时自定义了__str__方法。
from typing import NamedTuple
class Corrdinate(NamedTuple):
lat: float
lon: float
def __str__(self):
ns = 'N' if self.lat >=0 else 'S'
we = 'E' if self.lon >= 0 else 'W'
return f'{abs(self.lat):.1f}°{ns},{abs(self.lon):.1f}°{we}'
在typing.NamedTuple生成的 init 方法中,字段参数的顺序与在class语句中出现的顺序相同
与typing.NamdTuple 一样dataclass 装饰器也支持使用PEP 526句法来声明实例属性。dataclass 装饰器读取变量注解,自动为构建的类生成方法。如下例子:
from dataclasses import dataclass
@dataclass(frozen = True)
class Corrdinate:
lat: float
lon: float
def __str__(self):
ns = 'N' if self.lat >=0 else 'S'
we = 'E' if self.lon >= 0 else 'W'
return f'{abs(self.lat):.1f}°{ns},{abs(self.lon):.1f}°{we}'
1.可变实例
3个数据类构建起之间的主要区别在于,collections.namedtuple 和 typing.NamedTuple 构建的类是tuple 的子类,因此实例是不可变的。@datacalss 默认构造可变的类。不过@dataclass 装饰器接受一个关键字参数frozen,指定frozen=True,初始化实例之后,如果为字段赋值,则抛出异常
2.class 句法
只有typing.NamedTuple 和 dataclass 支持常规的class语句句法,方便为构建的类添加方法和文档字符串
3.构造字典
两种具名元组都提供了构造dict对象的实例方法(_dict()),可根据数据类实例的字段构造字典。dataclasses 模块也提供了构造字典的函数。即dataclasses.asdict.
namedtuple
具名元组(namedtuple) 是 python 标准库 collections 中的工厂函数。它接受两个参数,第一个参数表示类的名称,
第二个参数是类的字段名。后者可以是可迭代对象,也可以是空格隔开的字符串
>>> from collections import namedtuple
# 构建一个City类
>>> City = namedtuple('City','name country poplution')
# 实例化对象
>>> tokyo = City('Tokyo','JP',36.933)
>>> tokyo
City(name='Tokyo', country='JP', poplution=36.933)
# 访问实例属性
>>> tokyo.poplution
36.933
>>> tokyo[1]
'JP'
除了从普通元组继承来的属性之外,具名元组还有一些自己专有的属性:
# 获得类的字段名
>>> City._fields
('name', 'country', 'poplution')
>>> bj_data = ('beijing','china','36.666')
# 接收一个可迭代对象新建一个city对象
>>> bj = City._make(bj_data)
# 以dict形式返回属性和值
>>> bj._asdict()
{'name': 'beijing', 'country': 'china', 'poplution': '36.666'}
# Python 3.7 开始namedtuple接受defaults关键字参数,值为一个产生N项的可迭代对象,为从右数的N个字段指定默认值
>>> City = namedtuple('City','name country poplution',defaults=['1111'])
>>> City('shenzhen','china')
City(name='shenzhen', country='china', poplution='1111')
NamedTuple
from typing import NamedTuple
class Coordinate(NamedTuple):
lat:float # 1
lon:float
reference: str = 'WGS84' # 2
- 1 每个实例字段都要注解类型
- 2 实例字段reference 注解了类型,还指定了默认值。
使用 typing.NameTuple 构建的类,拥有的方法并不比collections.namedtuple 生成的更多,而且同样也从tuple 继承方法。
唯一的区别是多了类属性__annotations__,在运行时,Python完全忽略该属性
类型提示入门
类型提示(也叫类型注解)声明函数参数、返回值、变量和属性的预期类型
关于类型提示,首先你要知道,Python字节码编译器和解释器根本不强制你提供类型信息
运行时没有作用
from typing import NamedTuple
class Coordinate(NamedTuple):
lat:float # 1
lon:float
reference: str = 'WGS84' # 2
c = Coordinate('str1','str2')
print(c) # Coordinate(lat='str1', lon='str2', reference='WGS84')
运行后,发现并没有报错也不会发出警告
类型提示主要为第三方类型检查工具提供支持,例如Mypy 和 Pycahrm IDE内置的类型检查器
这些静态分析工具,在“静态”状态下检查Python 源码,并不运行代码
如下,安装mypy 后检查 Coordinate,可以看到有提示信息:
变量注解的语法
基本语法如下:
var_name: some_type
最常使用以下类型:
- 一个具体类,例如:str 或 Student
- 一个参数化容器类,例如: list[int],tuple[str,float]等。
- typing.Optional,例如Optional[str],声明一个字段类型可以str 或 None
指定初始化值:
var_name: some_type = a_value
变量注解的意义
类型提示在运行时没有作用。然而 Python 在导入时(加载模块时)会读取类型提示,构建__annotations__字典
供typing.NamedTuple和@dataclass使用,增强类功能
# demo3.py
class DemoPlainClass:
a: int # 1
b: float = 1.1 # 2
c = 'spam' # 3
演示:
>>> from demo3 import DemoPlainClass
>>> DemoPlainClass.__annotations__
{'a': <class 'int'>, 'b': <class 'float'>}
>>> DemoPlainClass.a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'DemoPlainClass' has no attribute 'a'
>>> DemoPlainClass.b
1.1
>>> DemoPlainClass.c
'spam'
1.a出现在__annotations__中
,但被抛弃了,因为该类没有名为a的属性
2.b作为注解记录在案,而且是一个类属性,值为1.1
3.c是普通的类属性,没有注解
注意,特殊属性__annotations__由解释器创建,记录源码中出现的类型提示,即使是普通的类。a只作为注解存在,不是类属性,因为没有绑定值。b和c存储为类属性,因为它们绑定了值。 这3个属性都不出现在DemoPlainClass的实例中。使用 o= DemoPlainClass() 创建一个对象,o.a 抛出AttributeErroer,而o.b和o.c 检索类属性,值分别为1.1 和 'spam',行为与一个常规的Python对象相同
模式匹配类实例
类模式通过类型和属性(可选)匹配类实例。类模式的匹配对象可以是任何类的实例,而不仅仅是数据类的实例
类模式有3中变体:简单类模式、关键字类模式和位置类模式
简单类模式
关键字类模式
import typing
class City(typing.NamedTuple):
continent: str
name: str
country: str
cities = [
City('Asia','Tokyo','JP'),
City('Asia','Delhi','IN'),
City('North America','Mexico City','MX'),
City('North America','New York','US'),
City('South America','Sao Paulo','BR')
]
def match_asian_cities():
results = []
for city in cities:
match city:
case City(continent='Asia'):
results.append(city)
return results
print(match_asian_cities())
#out: [City(continent='Asia', name='Tokyo', country='JP'), City(continent='Asia', name='Delhi', country='IN')]
本文来自博客园,作者:chuangzhou,转载请注明原文链接:https://www.cnblogs.com/czzz/p/15858282.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!