说明
《Python 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
Python 的有些方法被设计成原地操作(in-place),不返回新的对象,而是直接原对象进行修改。Python 的很多可变对象都有这种机制,众多三方库包也大量采用了这种方法。本文将介绍原地操作的逻辑的应用场景。
我们以最为常见的列表的 append() 方法为例,它是一个典型的原地操作。
a = [1,2]
b = a.append(3)
print(a)
# [1, 2, 3]
print(b)
# None
a = a.append(4)
print(a)
# None
append() 是一个原地操作(inplace),后将原对象进行修改,返回的是 None 值,因此我们不能再给 append() 操作赋值,因为赋值的标识符号的对象为 None,如果再赋值给原对象,原对象的标识符就是 None 了。
字符串是不可变对象,因此它的方法都不是原地操作,如:
s = 'ABC'
s.lower()
# 'abc'
s
# 'ABC'
总结下,原地操作的特点:
原地操作(in-place),又叫就地操作,是指在算法(如排序)直接使用输出来覆盖输入,因此不需要额外的空间。当把输入写入到仅允许写入的内存或流当中时,只考虑算法执行过程中的空间开销可能更恰当一些。在诸如对数空间归约等理论应用上,更典型的做法往往是将输出占用忽略(在这些情况下,更重要的是输出为仅允许写入)。
当提到排序算法时,或者更一般地说,指重新排列数组/列表的算法时,这不是“就地”的用法。
Python 中的许多操作都有“就地”版本。下面列出的函数提供了比通常语法更原始的就地操作符访问;例如,语句 x+=y
等效于 x = operator.iadd(x, y)
。另一种说法是 z = operator.iadd(x, y)
等价于复合语句 z = x; z += y
。
在一些情况下请注意,当调用就地方法时,计算和赋值将在两个单独的步骤中执行。就地函数只执行第一步,即调用就地方法。第二步,赋值不处理。
对于字符串、数字和元组等不可变目标,会计算更新后的值,但不会将其赋回输入变量:
a = 'hello'
iadd(a, ' world')
# 'hello world'
a
# 'hello'
对于列表和字典等可变目标,就地方法将执行更新,因此无需后续赋值:
s = ['h', 'e', 'l', 'l', 'o']
iadd(s, [' ', 'w', 'o', 'r', 'l', 'd'])
# ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
s
# ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
常用的内置方法均有原地版本,如 __add__
的原地版本是 __iadd__
,以 i 开头。
三方库很多方法都给给出 inplace 参数是否执行原地操作,默认不进行,为 True 时进行。如 pandas 中:
df.reset_index(inplace=True)
Python 中常见的内置数据类型的原地方法有:
我们来写一个原地操作的函数,对原对象进行修改,返回可以是任意的,但最好按照习惯返回 None。
class Wallet():
def __init__(self, n):
self.n = n
def add_money(self, other):
self.n += other
return
def __repr__(self):
return f'<Wallet: {self.n}>'
wallet = Wallet(10)
wallet
# <Wallet: 10>
wallet.add_money(8)
wallet
# <Wallet: 18>
更新时间:2022-06-23 20:40:32 标签:python 原地 操作