在Python中,什么时候以及为何使用:=Over=
最近,Python 3.8引入了“冒号等于”(:=)的用法,类似于“等于”运算符(=)。试过后发现,使用此运算符可加快速度并缩短代码,理解它绝对有价值。
当我们用数学写方程式时,我们可能会写像a=5,a+b=7之类的方程式。然后,可以使用简单的代数运算来找到b=2。在这种情况下,等号表示相等。变量a和b是常数,虽然在初始化问题时不知道它们的值,但它存在并且不会更改。
另一方面,在数学中,对于关系“ x被定义为y ” 存在不同的表示法。如果要写x:=y,则不是x和y具有数量相等的关系,而是将x定义为y是什么值。它比对称更单向。说实话这有点难,但是在高科技研究论文开始之初,该符号实际上仅适用于一长串变量定义。
无论如何,在最新版本的Python 3.8中出现了对:=或“walrus操作符” 的接受使用(确实看起来像水平的walrus)。尽管它不能完全解决数学上的问题,但它来自在编程上下文中在表达式内定义变量的相同思想。
这是从Python开发人员引入walrus运算符的基本原理:
Naming the result of an expression is an important part of programming, allowing a descriptive name to be used in place of a longer expression, and permitting reuse. Currently, this feature is available only in statement form, making it unavailable in list comprehensions and other expression contexts.
翻译:命名表达式的结果是编程的重要组成部分,它允许使用描述性名称代替较长的表达式,并允许重用。当前,此功能仅以语句形式可用,从而使其在列表推导和其他表达式上下文中不可用。
- PEP 572
接下来就看看实际的walrus操作符吧。
函数f被定义为f=lambda x: x+2,它只是在任何输入中添加了2,考虑以下代码:
data=[1,2,3,4]
f_data=[y for x in data if (y :=f(x)) is not 4]
结果是[3,5,6],因为这些是不等于值4的函数的结果。这是一个比另一种方法更有效的实现,即通过函数运行两次输入:
f_data=[f(x) for x in data if f(x) is not 4]
要注意的是,由于3.8版本是新的,一些没有更新的环境可能不支持它。
我们再举一个例子。有一些文本文件,名为text.txt。它包含三行字母来自a-i。
abc
def
ghi
假设我们要逐行遍历此文本文件。有几种方法可以做到这一点。我们可以使用内置函数.readlines()。
for line in open('text.txt','r').readlines():
print(line)
立马可以看出,它可以满足我们的要求。另一方面,如果不能使用内置函数呢?并不是所有的应用程序都有这些方便的函数,可以完全按照要求执行。你也可以使用下面的解决方案,它将文本逐行分割:
for line in open('text.txt','r').read().split('
'):
print(line)
这个解决方案也可以工作,但是堆栈函数没有它们所能做到的那么简单和干净。我们可以用walrus操作符来写这个:
while chunk :=open('text.txt').read():
print(chunk)
在这里,我们只是将chunk定义为读取文件。它是挺干净整洁的,不像平时那座粑粑山。另一方面,写while chunk=open…也不对,因为你不能在计算一个单独的表达式时创建变量赋值。
作为另一个例子,以上面给出的函数f(x)的定义为例,在输入上加上2。使用walrus操作符,下面的列表g构造是完全有效的:
g=[y :=f(3), y**2, y**3] #contents: [5, 25, 125]
我在这里做了这些—— y被定义为f(3)它在后面被用在同一个表达式中。我们不能写像g=[y=f(3),…]这样的东西,因为使用=的变量的赋值必须在它自己的行中完成,而不是在另一个表达式中。也可以用标准的equals操作符写成两行:
y=f(3)
g=[y,y ** 2,y ** 3]
到目前为止,walrus操作符的用法应该相对清楚了。
:=可用于在评估另一个表达式时分配变量。
由于变量赋值的形式var=expr必须写在自己的行上,因此walrus运算符缩短空间通过运行原本是一个非法的变量赋值在评估另一个表达式,它创建一个列表或一个文件的阅读。
在许多方面,:=运算符与占位符变量的定义类似,例如for i in range(x):,其中变量i在for循环的表达式内初始化。可以将其视为这些“隐藏变量初始化”的扩展或概括。
但是,walrus操作符不能用于所有功能。看看下面这个就知道了:
a :=3 #must be done with a=3.
a=b :=4 #must be done with a=b=4
a=(b :=4) #legal, but not recommended
探究一下为什么a=(b:=4)这种表达方式有效还能用。这是因为b:=4不仅使b等于4,而且返回它的值。这也是为什么上面的列表理解语句(如果y:=f(x))不是4)起作用的原因。该语句将b:=4作为表达式计算,该成教表达式将返回一个值。结果:a和b都被设为4。
更进一步,在第一个语句周围加上括号,如- (a:=3),就可以正常运行,因为使用括号将其内部的所有内容标记为表达式。Walrus操作符只能在其他表达式中使用。
让我们越过边界进入非python的领域。在这里,我们将探索一些类似的用法,这些用法可能很有用。试试呗,又不亏。
考虑一个函数指数,它将基数提升到exp。
def exponent(base,exp):
return base**exp
如果我想将4的值乘以3的幂,又要存储该幂的值(3),该怎么办?我可以使用walrus操作符:
exponent(base=4, exp=(storage:=3))
三个存储到变量存储中,该函数可以正常运行,并且我为自己节省了一行代码和一些运行时间。在walrus操作符的大规模使用中,这些节省可能会增加一点点速度。
Walrus运算符甚至可以在if语句中使用。在下面的示例中,(placeholder:=x)计算结果为xis的任何值。如果该输出等于4,则无论如何将其存储在占位符中。通常,这种用法没有太大的实际价值,因为我们正在进行冗余分配(如果是x!=4?),但这也是一种可能,万一有时候用得上呢。
x = 4
if (placeholder:=x) == 4:
print(placeholder) #output: 4
作为与unpythonic接壤的代码的另一个示例(Python社区是否已经确定了有关walrus运算符的内容?),可以考虑以下完全合理的功能。
f=lambda x : (m :=x+1) + (m**2)
f(3)返回20,因为(m :=x+1)计算结果为4,并且(m**2)计算结果为16。他们的总和等于20,采用的方法既干净又令人满意,但又有点……偷偷摸摸。无论如何,walrus操作符至少是一项有用的功能。
关键点walrus操作符用表示:=,并在Python 3.8中引入。此运算符仅用于另一个表达式中的变量分配。至少,可以节省一行或多行代码,并且最多可以极大地加快大数据的处理速度。从循环到函数到列出理解,再到if语句到回旋变量赋值,到处都可以使用Walrus运算符。
写:=Over=文章只是深入探究,多了解了解,毕竟多懂一点总是好的,万一用的上呢?
想了解更多精彩资讯,请点一下关注吧。