说说 Python 元组的高级用法

1 元组记录

元组可以当做存放数据的记录。元组中的元素用于存放记录字段数据,而元素所在的位置用于表达该字段的隐含含义。

Luciano Ramalho 举了这样一个示例:

lax_coordinates=(33.33,-11.92)
logging.info('longitude -> %s',lax_coordinates[0])
logging.info('latitude -> %s',lax_coordinates[1])

city,year,pop,chg,area=('Tokyo',2013,232,0.22,281)
logging.info('city -> %s',city)
logging.info('area -> %s',area)

traveler_ids=[('USA','232'),('ESP','11')]
for passport in sorted(traveler_ids):
    logging.info('%s/%s' % passport)

for country,_ in traveler_ids:
    logging.info('country -> %s',country)

运行结果:

INFO - longitude -> 33.33
INFO - latitude -> -11.92
INFO - city -> Tokyo
INFO - area -> 281
INFO - ESP/11
INFO - USA/232
INFO - country -> USA
INFO - country -> ESP
  1. 可利用元组的位置,得到相关数据,但必须清楚该位置所指向的数据含义。
  2. 也可以利用元组,给多个变量一次性赋值。
  3. 利用 for 循环可以分别提取出元组里的元素,这叫作拆包(unpacking)。
  4. 第三个用例是先排序,然后再拆包到一个变量,最后用 % 格式运算符将自动匹配到对应的元组元素中打印出来。
  5. 第四个用例是先拆包到一个变量和一个占位符 _,然后打印出这个变量。

2 元组拆包

利用元组拆包,我们可以使用一行代码,同时给多个变量一次性初始化赋值。

元组拆包可以应用到任何可迭代对象上。这些可迭代对象中的元素数必须要跟接受这些元素的元组的空档数一致。

(1)数据交换

利用元组拆包,可以很优雅地通过一行代码实现两个变量之间的数据交换。

a = 1
b = 2
a, b = b, a
logging.info('a -> %s',a)
logging.info('b -> %s',b)

运行结果:

INFO - a -> 2
INFO - b -> 1

(2)拆分函数入参

利用 * 运算符可以把一个可迭代对象拆分成某个函数的多个入参。

r = divmod(20, 8)
logging.info('r -> %s', r)

i = (20, 8)
r = divmod(*i)
logging.info('r -> %s', r)

quotient, remainder = divmod(*i)
logging.info('quotient -> %s', quotient)
logging.info('remainder -> %s', remainder)

运行结果:

INFO - r -> (2, 4)
INFO - r -> (2, 4)
INFO - quotient -> 2
INFO - remainder -> 4

python 的 divmod() 函数,会返回一个包含商和余数的元组。divmod(a, b) 中,a 是被除数,b 是除数,而返回的结果是 (商,余数)。

(3)占位符方式

在进行拆包的时候,如果有些返回值不是我们想要的,可以使用 _ 占位符忽略它们。

_,filename=os.path.split('/home/xxx/readme.txt')
logging.info('filename -> %s',filename)

运行结果:

INFO - filename -> readme.txt

os.path.split() 函数会返回以路径和最后一个文件名组成的元 组 (path, last_part),而我们只需要文件名,那么这里就可以使用 _ 占位符忽略路径值。

(4)处理多余的值

在多值赋值的场景下,我们可以使用 * 来处理剩下的值。所谓的剩下的值,就是没有明确被赋值的值。

a, b, *rest = range(5)
logging.info('a,b,rest -> %s,%s,%s', a, b, rest)
a, b, *rest = range(3)
logging.info('a,b,rest -> %s,%s,%s', a, b, rest)
a, b, *rest = range(2)
logging.info('a,b,rest -> %s,%s,%s', a, b, rest)

运行结果:

INFO - a,b,rest -> 0,1,[2, 3, 4]
INFO - a,b,rest -> 0,1,[2]
INFO - a,b,rest -> 0,1,[]

* 的变量可以是左侧变量表达式中的任意一个变量。

a, *body, c, d = range(5)
logging.info('a, body, c, d -> %s,%s,%s,%s', a, body, c, d)
*head, b, c, d = range(5)
logging.info('head,b,c,d -> %s,%s,%s,%s', head, b, c, d)

运行结果:

INFO - a, body, c, d -> 0,[1, 2],3,4
INFO - head,b,c,d -> [0, 1],2,3,4

3 嵌套元组拆包

只要接受元组的嵌套结构与表达式本身的嵌套结构一致, Python 就可以自动拆包。

metro_areas = [('Tokyo', 'JP', 36.933, (35.689722, 139.691667)), ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
               ('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
               ('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
               ('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833)),
               ]
fmt = '{:15} | {:9.4f} | {:9.4f}'
for name, cc, pop, (latitude, longitude) in metro_areas:
    if longitude <= 0:
        logging.info(fmt.format(name, latitude, longitude))

运行结果:

INFO - Mexico City     |   19.4333 |  -99.1333
INFO - New York-Newark |   40.8086 |  -74.0204
INFO - Sao Paulo       |  -23.5478 |  -46.6358

经纬度是经度与纬度的合称组成一个坐标系统,称为地理坐标系统,它是一种利用三度空间的球面来定义地球上的空间的球面坐标系统,能够标示地球上的任何一个位置。

负纬度表示位于南半球(S)的位置而负经度表示西半球(W)的位置。示例代码中,元组拆包后,过滤出西半球的坐标,然后打印出来。

4 具名元组

4.1 用法

我们可以利用 collections.namedtuple 这个工厂函数来构建一个带名字的元组。

用 namedtuple 构建的类的实例跟普通的对象实例相比,所占用的内存要小一些,因为 Python 没有使用 dict 来存放这些实例的属性。

from collections import namedtuple
City=namedtuple('City','name country population coordinates')
tokyo=City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
logging.info('tokyo -> %s',tokyo)
logging.info('population -> %s',tokyo.population)
logging.info('tokyo[0] -> %s',tokyo[0])
logging.info('tokyo[1] -> %s',tokyo[1])

运行结果:

INFO - tokyo -> City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
INFO - population -> 36.933
INFO - tokyo[0] -> Tokyo
INFO - tokyo[1] -> JP

创建一个具名元组需要两个入参,一个是类名,另一个是类中各个字段的名字。后者是由空格分隔开的字段名所组成的字符串。City=namedtuple('City','name country population coordinates')

放入数据时,需要把数据以逗号分隔的形式传入到具名类的构造函数中。tokyo=City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))

然后就可以通过字段名或者位置来获取具名元组中的某个字段的信息。tokyo.populationtokyo[0]

4.2 专有属性

除了从普通元组那里继承来的属性之外,具名元组还定义了一些自己的专有属性。

  • _fields 属性包含了这个类所有字段名称元组。
  • _make() 方法接受一个可迭代对象来生成这个类的一个实例。
  • _asdict() 方法会把具名元组以 collections.OrderedDict 的形式返 回出来,我们可以利用它来打印出元组中的信息。
logging.info('_fields -> %s',City._fields)
LatLong = namedtuple('LatLong', 'lat long')
delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))
delhi = City._make(delhi_data)
logging.info('delhi._asdict() -> %s',delhi._asdict())

运行结果:

INFO - _fields -> ('name', 'country', 'population', 'coordinates')
INFO - delhi._asdict() -> OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935), ('coordinates', LatLong(lat=28.613889, long=77.208889))])

示例中的 delhi_data 是一个嵌套结构,内部嵌套了包含经纬度信息的具名元组。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354