在实际的开发过程中,我们经常需要编写一些函数用于返回多个值,例如
def latlon_to_address(lat, lon):
"""返回某个经纬度的地理位置信息"""
# 对输入进行处理,得到country, province, city
return country, province, city
country, province, city = latlon_to_address(lat, lon)
但随着业务的进展,现在,有需要返回区/县(distinct),这时候,我们需要对函数添加一个返回值distinct如下:
return country, province, city, distinct
紧接着,还需要对调用语句做修改:
country, province, city, distinct = latlon_to_address(lat, lon)
# 或者
country, province, city, _ = latlon_to_address(lat, lon)
项目代码在之前可能有多处使用
country, province, city = latlon_to_address(lat, lon)
我们必须一一找到并进行修改,这带来了巨大的工作量,但是如果我们一开始就使用NamedTuple,这些问题就可以得到规避。
我们可以通过新建一个类,它继承自NamedTuple:
from typing import NamedTuple
class Address(NamedTuple):
country: str
province: str
city: str
def latlon_to_address(lat, lon):
country = ''
province = ''
city = ''
return Address(
country=country,
province=province,
city=city
)
addr = latlon_to_address(lat, lon)
如果我们有新的业务需求,只需修改address类即可,之前调用的代码不需要更改
这时候可能大家有疑问,这样做和我直接使用一个自定义类有什么区别呢?
-
简洁性:
NamedTuple
通常比自定义类更简洁。定义一个NamedTuple
只需要一行代码,并且在定义字段时可以直接使用字段名和类型注释。而自定义类则需要更多的代码来定义类及其属性,并且需要手动编写__init__
、__repr__
等方法。 -
不可变性:
NamedTuple
实例是不可变的,一旦创建就无法修改其字段的值。而自定义类的实例通常是可变的,可以通过方法修改实例的属性值。 -
属性访问:
NamedTuple
会自动生成属性访问器,使得可以通过属性名直接访问字段值。而在自定义类中,需要手动编写方法来实现属性的访问和设置。 -
性能:由于
NamedTuple
是内置类型,其性能通常会比自定义类更好。
我们有如下代码:
class Point(NamedTuple):
x: int
y: int
p = Point(1, 2)
如果我们尝试修改其中的元素,python解释器会返回如下的错误:
Traceback (most recent call last):
File "test.py", line 41, in <module>
p.x = 3
AttributeError: can't set attribute
可以看到,如果继承NamedTuple,我们的类就拥有了元组的特性