可变和不可变类型

Python 提供两种内置或用户定义的类型。可变类型允许内容的内部修改。典型的动态类型包括列表与字典:列表都有可变方法,如 list.append() 和 list.pop(), 并且能就地修改。字典也是一样。不可变类型没有修改自身内容的方法。比如,赋值为整数 6 的变量 x 并没有 “自增” 方法,如果需要计算 x + 1,必须创建另一个整数变量并给其命名。

my_list = [1, 2, 3]
my_list[0] = 4
print(my_list)  # [4, 2, 3] <- 原列表改变了

x = 6
x = x + 1  # x 变量是一个新的变量

这种差异导致的一个后果就是,可变类型是不 ’稳定 ’的,因而不能作为字典的键使用。合理地使用可变类型与不可变类型有助于阐明代码的意图。例如与列表相似的不可变类型是元组, 创建方式为 (1, 2)。元组是不可修改的,并能作为字典的键使用。

Python 中一个可能会让初学者惊讶的特性是:字符串是不可变类型。这意味着当需要组合一个 字符串时,将每一部分放到一个可变列表里,使用字符串时再组合 (‘join’) 起来的做法更高效。 值得注意的是,使用列表推导的构造方式比在循环中调用 append() 来构造列表更好也更快。

# 创建将0到19连接起来的字符串 (例 "012..1819")
nums = ""
for n in range(20):
    nums += str(n)   # 慢且低效
print(nums)

# 创建将0到19连接起来的字符串 (例 "012..1819")
nums = []
for n in range(20):
    nums.append(str(n))
print("".join(nums))  # 更高效

更好

# 创建将0到19连接起来的字符串 (例 "012..1819")
nums = [str(n) for n in range(20)]
print("".join(nums))

最好 Best

# 创建将0到19连接起来的字符串 (例 "012..1819")
nums = map(str, range(20))
print("".join(nums))

最后关于字符串的说明的一点是,使用 join() 并不总是最好的选择。比如当用预先确定数量的字符串创建一个新的字符串时,使用加法操作符确实更快,但在上文提到的情况下或添加到已存在字符串的情况下,使用 join() 是更好的选择。

foo = 'foo'
bar = 'bar'

foobar = foo + bar  # 好的做法
foo += 'ooo'  # 不好的做法, 应该这么做:
foo = ''.join([foo, 'ooo'])

注解
除了 str.join() 和 +,也可以使用 % 格式运算符来连接确定数量的字符串,但 PEP 3101 建议使用 str.format() 替代 % 操作符。

foo = 'foo'
bar = 'bar'

foobar = '%s%s' % (foo, bar) # 可行
foobar = '{0}{1}'.format(foo, bar) # 更好
foobar = '{foo}{bar}'.format(foo=foo, bar=bar) # 最好