Python笔记004-元组的拆包和命名元组
以下是我学习《流畅的Python》后的个人笔记,现在拿出来和大家共享,希望能帮到各位Python学习者。
首次发表于: 微信公众号:科技老丁哥,ID: TechDing,敬请关注。
本篇主要知识点:
-
元组的拆包就是将元组内部的每个元素按照位置一一对应的赋值给不同变量,可以应用到变量赋值,函数参数赋值,获取元组中特定位置的元素值等场合。
-
namedtuple: 用于存储对象序列,不能改变元素值,可以像dict一样通过名字进行访问,可以通过_asdict()转换为dict,其作用相当于只有属性没有方法的类。
1. 元组的拆包
Python中的元组tuple和列表list类似,不同之处在于元组的元素不能修改,所以被经常称为不可变列表,在形式上,元组用小括号()表示,而列表用中括号[]表示。
元组的拆包就是将元组内部的每个元素按照位置一一对应的赋值给不同变量,比如:
tupleA
=
(
10
,
20.5
)
first
,
second
=
tupleA
# 对二元素元组拆包
print
(
first
)
# 10
print
(
second
)
# 20.5
a
,
b
,
c
,
d
=
(
'A'
,
20.15
,
2019
,
'10:15:14'
)
# 多元素元组的拆包
print
(
a
)
# A
print
(
b
)
# 20.15
print
(
c
)
# 2019
print
(
d
)
# 10:15:14
如果拆包应用于上面的简单赋值,那倒是没什么新奇之处。拆包其实被经常用于给函数的参数赋值,比如:
def
func1
(
a
,
b
)
:
print
(
'a: '
,
a
,
'b: '
,
b
)
tupleA
=
(
10
,
20.5
)
func1
(
*
tupleA
)
# 拆包后作为函数的参数,a: 10 b: 20.5
另外一种拆包的应用场景是,某些函数返回一个tuple,而我们需要对其进行拆包,比如:
def
func2
(
x
)
:
return
(
x
,
x
*
2
,
x
*
x
)
data1
,
data2
,
data3
=
func2
(
3
)
print
(
data1
)
# 3
print
(
data2
)
# 6
print
(
data3
)
# 9
在拆包时,有的元素不是我们所需要的,那就用占位符来代替,即用_代表一个占位符,而*代表多个占位符
data1
,
_
,
data3
=
func2
(
3
)
# 用_代表一个变量
print
(
data1
)
# 3
data1
,
*
rest
=
func2
(
3
)
print
(
data1
)
# 3
print
(
rest
)
# [6,9]
嵌套元组,顾名思义是元组中包含有元组,对其进行拆包和普通元组的拆包类似。
areas
=
[
(
'hubei'
,
'wuhan'
,
1200
,
(
150
,
260
)
)
,
(
'hunan'
,
'changsha'
,
3600
,
(
100
,
200
)
)
,
(
'shandong'
,
'jinan'
,
800
,
(
260
,
180
)
)
]
for
province
,
city
,
data1
,
(
data2
,
data3
)
in
areas
:
print
(
'P:{}, C:{}, data2:{},data3:{}'
.
format
(
province
,
city
,
data2
,
data3
)
)
2. 命名元组
命名元组(namedtuple)类似于tuple,都可以用于存储对象序列,但是它比tuple更加强大,除了延续tuple不能改变元素值这一特性之外,还有其本身的特点,比如可以像dict一样通过名字访问元素值,还可以通过_asdict()转换为dict类型。
命名元组可以构建一个带有字段名的元组和一个有名字的类,其消耗的内存和元组是一样的。
在面向对象的思想下,如果我们需要构建一个简单的类,只是用于存储几个简单的属性,而没有具体的方法,我们可以写成:
class
PersonCls
:
# 定义一个类,只有属性,没有具体的方法,用于存储某些属性值
def
__init__
(
self
,
name
,
age
,
score
)
:
self
.
name
=
name
self
.
age
=
age
self
.
score
=
score
def
__repr__
(
self
)
:
return
'PersonCls(name={},age={},score={})'
.
format
(
self
.
name
,
self
.
age
,
self
.
score
)
PC1
=
PersonCls
(
'Jack'
,
20
,
85
)
PC2
=
PersonCls
(
'Rose'
,
18
,
92
)
print
(
PC1
)
# PersonCls(name=Jack,age=20,score=85)
print
(
PC2
)
# PersonCls(name=Rose,age=18,score=92)
print
(
PC1
.
age
)
# 20
print
(
PC2
.
score
)
# 92
这样的写法是可行的,但不是Python风格,对这种情况,完全可以交给namedtuple来做,比如,在python里面的写法为:
from
collections
import
namedtuple
Person
=
namedtuple
(
'Person'
,
[
'name'
,
'age'
,
'score'
]
)
# 构造一个namedtuple类
P1
=
Person
(
'Jack'
,
20
,
85
)
# 构建具体的实例,其赋值顺序要一一对应
P2
=
Person
(
age
=
18
,
name
=
'Rose'
,
score
=
92
)
# 如果指定变量名,顺序不用一一对应
print
(
P1
)
# Person(name='Jack', age=20, score=85)
print
(
P2
)
# Person(name='Rose', age=18, score=92)
print
(
P1
.
age
)
# 可以像dict一样通过属性名进行访问
print
(
P2
.
score
)
# 92
上面的
Person=namedtuple('Person',['name', 'age', 'score'])
就相当于构建一个只有属性没有方法的Person类,其属性为:‘name’, ‘age’, ‘score’,代码更加简单,且更有Python味儿。在内存上来说,会比定义一个类要小一些,因为此时不需要用
__dict__
来存放实例的属性。
命名元组除了从tuple继承来的属性之外,还有其专有属性,最常用的是
_fields, _make(), _asdict()
。如下:
# namedtuple专有属性:
from
collections
import
namedtuple
Person
=
namedtuple
(
'Person'
,
[
'name'
,
'age'
,
'score'
]
)
print
(
Person
.
_fields
)
# ('name', 'age', 'score')
# _fields属性是一个包含这个类所有属性名称的tuple
person1
=
(
'zhangsan'
,
25
,
59
)
p1
=
Person
.
_make
(
person1
)
# _make()接受一个可迭代对象生成一个实例
print
(
p1
)
# Person(name='zhangsan', age=25, score=59)
print
(
p1
.
_asdict
(
)
)
# OrderedDict([('name', 'zhangsan'), ('age', 25), ('score', 59)])
# _asdict()将实例的属性和值以OrderedDict的方式展示出来。
首次发表于: 微信公众号:科技老丁哥,ID: TechDing,敬请关注。
本文所有代码都已经上传到我的github,欢迎下载
参考资料:
- 《流畅的Python》,Luciano Ramalho (作者) 安道 , 吴珂 (译者)。