主要介绍以下三种构建方法:
构建:
1) namedtuple创建:一个类名和一个字段名称列表。后一个参数可以是产生字符串的可迭代对象,也可以是一整个以空格分隔的字符串
2) 可以通过_make()
方法创建类实例
3) 不能使用class 句法创建实例 ;不能直接添加类方法(可以绕一步);
构建字典:
collections.namedtuple._asdict()
:
1) 返回namedtuple实例构建的dict对象 ;
2) 通过json.dumps(instance._asdict())
可以dump json
访问字段:
1) _field()
返回类的字段名tuple , 注意这里不能是实例._fields
, 而是 类名._fields
2) 通过实例.name
和索引范围字段
设置字段默认值:
通过default
字段设置:namedtuple('classname','attribute1 attribute2 ...',default = val1,val2,...)
from collections import namedtuple
coordinate = namedtuple('cordinate','lat lon')
moscow = coordinate(12.345,16.789)
moscow_new = coordinate(12.345,16.789)
print(moscow == moscow_new) #可以直接比较两个namedtuple instance 是否相等, 只用class 构建的类比较的是两个instance 的id而不是值;
City = namedtuple('City','name country population coordinates')
tokyo = city('Tokyo', 'JP', 36.933, (35.689722, 139.691667)) #构建方法1
print(tokyo)
#构建方法2
nxt = coordinate(33.4565,84.572)
nxt_data = ('shanghai','CH',100,nxt)
shanghai = City._make(nxt_data)
print(shanghai)
# 构建字典
print(shanghai._asdict())
#构建json
import json
json.dumps(shanghai._asdict())
#访问字段
print(city._fields)
print(shanghai.coordinates)
print(shanghai[-1])
# 设置字段默认值
Point = namedtuple('Point','x y z',defaults=[0,1,2])
a = Point()
b = Point(1)
c = Point(1,2)
print(a,b,c)
True
city(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
City(name='shanghai', country='CH', population=100, coordinates=cordinate(lat=33.4565, lon=84.572))
{'name': 'shanghai', 'country': 'CH', 'population': 100, 'coordinates': cordinate(lat=33.4565, lon=84.572)}
('name', 'country', 'population', 'coordinates')
cordinate(lat=33.4565, lon=84.572)
cordinate(lat=33.4565, lon=84.572)
Point(x=0, y=1, z=2) Point(x=1, y=1, z=2) Point(x=1, y=2, z=2)
typing.NamedTuple
的主要功能在类型注解,与collections.namedtuple
的区别在于:
类型注解:
var_name : some_type
from typing import NamedTuple
class Point(NamedTuple):
x:float
y:float
def __str__(self):
if self.x>0 and self.y>0:
return 'First quadrant'
elif self.x<0 and self.y>0:
return 'Second quadrant'
a = Point(8.8,9.0)
print(a)
First quadrant
@dataclass 是
Python 的一个装饰器,用于自动生成类的一些常用方法,如 __init__
、__repr__
、__eq__
等。不需要显式地定义这些方法,dataclass 会根据类的字段自动生成。
from dataclass import dataclass
@dataclass(*,init =True, repr=True,eq=True,order=False,unsafe_hash=False,frozen=False)
* 表示后面的都是关键字参数;
参数说明
参数 | 作用 | 默认值 | 备注 |
---|---|---|---|
init | 生成 | True | 如果用户自己实现了 init,则忽略该参数 |
repr | 生成 | True | 如果用户自己实现了 |
eq | 生成 | True | 如果用户自己实现了 |
order | 生成 | False | 设为 True 时,如果 eq=False,或者自行定义或继承其他用于比较的方法, 则抛出异常 |
unsafe_hash | 生成 | False | 语义复杂,有多个问题需要 注意,详见 dataclass 函 数的文档 |
frozen | 让实例不可变 | False | 防止意外更改实例,相对安全,但不是绝对不可变 |
default_factory
参数值可以是一个函数、一个类,或者其他可调用对象,在每次创建数据类的实例时调用(不带参数),构建默认值。这样每个实例都会有各自的函数/类/对象,而不是所有实例共享一个函数/类/对象__init__
); 添加 __post_init__
方法,@dataclass 将在生成的 __init__
后调用 __post_init__
。
2) __post_init__
的作用:执行验证; 根据其它字段计算一个字段的值;
3) typing.ClassVar
:用来标注类变量(而非实例变量)的一种方式。它是 typing 模块中的一部分,提供了对类型注解的支持,特别是在面向对象编程中,帮助明确区分实例变量和类变量。
5) 仅做初始化的变量 InitVar: 有时候不希望某个属性出现在所有实例对象中,例如定义一个Company 类, 其中Company 的name 从某个数据库database 中获得,但不希望这个database 出现在所有的实例对象中。则一般会使用InitVar 放在__init__
中,在__post_init__
处理后使用。 注意:InitVar 变量应该传递给 __post_init__
方法,因此__post_init__
需要接收self 和 InitVar变量; 注意不能从类中访问InitVar ,因为InitVar 不会成为类的属性,估cls.
或self.
是访问不到的from dataclasses import dataclass
@dataclass
class point:
x:float = 0.0 # 1)提供类型+默认值
y:float = 0.0
def __str__(self):
if self.x>0 and self.y>0:
return f'{self.x},{self.y} First quadrant'
elif self.x<0 and self.y>0:
return f'{self.x},{self.y} Second quadrant'
elif self.x == 0.0 and self.y == 0.0:
return f'{self.x},{self.y}'
pointA = point()
print(pointA)
0.0,0.0
from dataclasses import dataclass,field
@dataclass
class ClubMember:
name:str
guests:list = field(default_factory=list) # 2.类属性用作实例属性, 用field 注册 list , 不能直接写成guests:list =[]
# 每个实例都会有各自的list,而不是所有实例共享一个list
visitors:list[str] = field(default_factory=list) # 3. 说明list的类型 是str
athlete:bool =field(default=False,repr=False)
@dataclass
class HackerClubMember(ClubMember):
all_handles = set() #类属性 , 所有实例共享
handle:str = '' #实例字段
def __post_init__(self):
cls = self.__class__ #获取实例所属的类
if self.handle == '':
self.handle = self.name.split()[0] #如果是空字符串,则设置为name 的第一部分
if self.handle in cls.all_handles: #如果self.handle 在cls.handle 中
raise ValueError(f'handle {self.handle} already exists')
cls.all_handles.add(self.handle) # 把新的handle 添加到cls.all_handles 中
mem1 = HackerClubMember('li haw')
print(mem1)
#mem2 = HackerClubMember('li ai') # raise error , 'li' already exists
mem2 = HackerClubMember('li ai',handle='liu')
HackerClubMember(name='li haw', guests=[], visitors=[], handle='li')
from dataclasses import dataclass
from typing import ClassVar #从typing 中引入ClassVar
@dataclass
class Company:
name:ClassVar[str] = 'tengxun'
mem:ClassVar[list[str]] = [] #mem : 类属性,是str-list ,初始值为空list
def add_mem(self,mem_name):
cls = self.__class__ #获取当前实例的类
cls.mem.append(mem_name) #类属性增加内容
Company1 = Company()
Company1.add_mem(mem_name = 'ma')
for item in iter('zhang wang li zhao'.split()):
Company1.add_mem(item)
print(Company1.mem)
['ma', 'zhang', 'wang', 'li', 'zhao']
from dataclasses import dataclass,InitVar
from typing import ClassVar,Tuple
database = ('TechNova Solutions','BlueSky Innovations','Quantum Dynamics','Pinnacle Enterprises')
@dataclass
class company:
name:str = None #实例属性
database:InitVar[tuple[str]] = None
mem_num:ClassVar[int] = 0 #类属性
# def __post_init__(self): error :
# cls = self.__class__
# if self.name is None and cls.database is not None:
# self.name = cls.database[0] error : database 不是类属性,访问不到
def __post_init__(self,database):
cls = self.__class__
if self.name is None and database is not None:
self.name = database[0]
company1 = company(database=database)
print(company1)
company(name='TechNova Solutions')
case [str(name),_,_,(float(lat),float(lon))]:
第一项必须为str 实例 最后一项必须是二元组,两项均为 float 实例。
class(name) 这种模式只适用于:bytes dict float frozenset int list set str tuple
import typing
class City(typing.NamedTuple):
continet: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', 'São Paulo', 'BR'),
]
result_Asia = []
result_America = []
#关键字匹配
for city in cities:
match city:
case City(continet = 'Asia'): # 注意不是 City(continet == 'Asia') ,
# city 匹配 City(continet = 'Asia') ,continet的属性值='Asia'
result_Asia.append(city)
case City(continet ='North America' ,country ='cc'): #匹配2个属性
result_America.append(city)
print(result_Asia)
print(result_America)
#位置类匹配
result_pos = []
for city in cities:
match city:
case City('Asia',_,Country):
result_pos.append(city)
print(Country)
print(result_pos)
[City(continet='Asia', name='Tokyo', country='JP'), City(continet='Asia', name='Delhi', country='IN')]
[]
JP
IN
[City(continet='Asia', name='Tokyo', country='JP'), City(continet='Asia', name='Delhi', country='IN')]
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。