Python 运算符与优先级

运算符

几乎任何语言的运算符,在基础语法上都是最为简单的,但是在很多算法当中往往有着妙用。

这篇笔记从运算符的优先级开始:下面从优先级开始认识 Python 中的运算符,并从各个类型进行剖析其中的代表运算符,语法和一些注意事项。

运算符优先级

下表对 Python 中运算符的优先顺序进行了总结,从最高优先级(最先绑定)到最低优先级(最后绑定)。除非语法显式地指明,否则运算符均为双目运算符。 相同单元格内的运算符从左至右组合的(只有幂运算符是从右至左组合的)。

运算符描述类型级别
(expressions...),[expressions...], {key: value...}, {expressions...}绑定或加圆括号的表达式,列表显示,字典显示,集合显示括号甲子
x[index], x[index:index], x(arguments...), x.attribute抽取,切片,调用,属性引用括号甲丑
await xawait 表达式表达式
**乘方算术运算丙子
+x, -x, ~x正,负,按位非位运算丙丑
*, @, /, //, %乘,矩阵乘,除,整除,取余算术运算丙寅
+, -加和减算术运算丙卯
<<, >>移位位运算丙卯
&, ^, |按位与、异或、或位运算丙卯
in, not in, is, is not, <, <=, >, >=, !=, ==比较运算:包括成员检测和标识号检测比较运算
not x布尔逻辑非逻辑运算戊子
and布尔逻辑与逻辑运算戊丑
or布尔逻辑或逻辑运算戊寅
ifelse条件表达式(不是条件语句)表达式
lambdalambda 表达式表达式
:=赋值表达式表达式
  • 括号 > await > 乘方 > 一元 > 算术 = 位 > 比较 > 逻辑 > 表达式

算术运算

就是常规的数学意义上的值运算,优先级也是 乘方 > 求正负 > 乘除求余 > 加减

求正负

正值、负值和按位取反运算符都是 一元运算符

  1. - (负值) 运算符:求负;通过 __neg__() 特殊方法来重载。
  2. + (正值) 运算符:求正,几乎不使用,C++中某些情况还可以有整数提升的作用;通过 __pos__() 特殊方法来重载。
x = -10.0
print(+x)	# -10.0
print(-x)	# 10.0

加减乘除

数值上的加减乘除没有意思,下面的案例,自定义一个字符串类(只含有大小写字母),重载加减乘除:

详细的描述有点繁琐,具体效果可看代码注释。

  1. 重载 __add__ :添加合并。
  2. 重载 __sub__ :减掉一个包含在内的字母。
  3. 重载__mul__ :包含在内的字母个数相乘。
  4. 重载 __truediv__:减掉全部包含在内的字母。
class OrderedStr:
    def __init__(self, string: str=''):
        """根据ASCII码排序"""
        self.string = ''.join(sorted([*string]))

    def __add__(self, other):
        return OrderedStr(self.string + other.string)

    def __sub__(self, other):
        s = [*self.string]
        [s.remove(i) for i in set(other.string) if s.count(i)]
        return OrderedStr(''.join(s))

    def __mul__(self, other):
        s = [*self.string]
        [s.append(i * ((other.string.count(i)-1)*self.string.count(i))) for i in set(other.string) if s.count(i)]
        return OrderedStr(''.join(s))

    def __truediv__(self, other):
        s = [*self.string]
        for i in set(other.string):
            while True:
                if s.count(i):
                    s.remove(i)
                else:
                    break
        return OrderedStr(''.join(s))

    def __str__(self):
        return self.string

def main():
    s1 = OrderedStr("xyzabccbb")
    s2 = OrderedStr("bab")
    print(s1)		# abbbccxyz
    print(s1 + s2)	# aabbbbbccxyz
    print(s1 - s2)	# bbccxyz
    print(s1 * s2)  # abbbbbbccxyz
    print(s1 / s2)  # ccxyz

if __name__ == '__main__':
    main()

这里主要是要说明可以重载运算符

整除与取余

对于整数,和小学数学中的描述一样,除数 ÷ 被除数 = 商 ... 余数

对于浮点数,商是和余数都是浮点数,除数 = 整数大小是商 * 被除数 + 余数,余数往往不是理想值,这是由于浮点型在内存中的存储方式导致的。

print(10 // 3# 3
print(10 % 3)		# 1
print(7.2 // 3)		# 2.0
print(7.2 % 3)  	# 1.2000000000000002
print(7.2 // 2.4)	# 3.0
print(7.2 % 2.4)	# 4.440892098500626e-16 不是0
  • % 也被用在字符串格式化。

乘方

乘方运算的底数和指数都可以是浮点数,也可以是负数。

print(2 ** 3)	# 2^3 == 8
print(2.1 ** 3)	# 9.261000000000001  底数是浮点数
print(2 ** 3.5) # 11.313708498984761 指数是浮点数
print(2 ** -1)	# 0.5
print(-2 ** 3)  # -8
  • 幂运算符的绑定比在其左侧的一元运算符更紧密;但绑定紧密程度不及在其右侧的一元运算符。比如 2 ** ~-1,先后给 -1 绑定的顺序是 -, ~, **
  • 可使用 __pow__() 进行重载。

矩阵乘法

矩阵乘法也是一个一般只在数学领域才会使用到的运算。下面仅给出一个例子:

import numpy as np

r = np.array([[1, 2, 3, 4]])
c = np.array([[1], [2], [3], [4]])
print(r @ c)		# 1^2+2^2+3^2+4^2==30

位运算

位运算和逻辑运算都有 与或非 三种典型运算,不同的是,逻辑运算更多的是对语句或表达式判断真假值,而位运算只是基于数据内容进行以比特位为单元的操作。

非、与、或、异或

  1. 非(NOT)运算具有更高的优先级,是一元运算符,其表现为按位取反
  2. 与(AND)运算 按位与,经常用来保留数据的某些比特位置,比如说保留最后一个比特位置:x & 1
  3. 或(OR)运算
  4. 异或(XOR)运算
x, y = 0b1101, 0b1001	# 0b 开始的二进制数
print(~x)				# 0b0010 == 2
print(x & y)			# 0b1001 == 9
print(x | y)			# 0b1101 == 13
print(x ^ y)			# ob0100 == 4
  • python 中对与数字应该和 JavaScript 部分一样,先将数字转成字符串,再去判断值,所以 11.0 有相同的哈希值,在作为字典的索引时,表示相同的内容。即对于 d = {1: ‘a’}d[1]d[1.0] 都能解读到 ‘a’
  • 0b1101 赋值给 x ,相当于二进制字符串 ‘0b1101’ 解读成 13 在进行赋值;更多的,八进制字符串以 0o 开头,十六进制字符串以 0x 开头。
  • 可使用 __not__()__and__()__or__()__xor__() 进行自定义。

移位

移位分为左移位和右移位,左移位往高位移动,移位 1 次相当于乘 2 ;右移位往低位移动,移位 1 次相当于整除 2 。

x = 0b11010010	# 210
print(x >> 1)	# 210/2 == 105  0b01101001
print(x << 1)   # 210*2 == 420  0b110100100
  • 移位运算的优先级低于算术运算。
  • 使用 __lshift__()__rshift__() 方法来自定义。

比较运算

比较运算:值运算成员检测标志号比较,返回布尔值 TrueFalse

自定义的 比较方法 可以不返回布尔值。

比较运算的连串、嵌套。

值比较

值比较使用运算符 <, >, ==, >=, <=!= 将两个对象的值进行比较。

  • 相等比较时,相等的对象应该或者具有相同的哈希值 hash(x) == hash(y)

成员检测

成员检测运算符包含 innot in,如果 xs 的成员则 x in s 求值为 True,否则为 Falsex not in s 返回 x in s 取反后的值。

  • 所有内置序列和集合类型以及字典都支持此运算,对于字典来说 in 检测其是否有给定的键。

标志号比较

标识号比较的运算符包括 isis not,用于检测对象:当且仅当 xy 是同一对象时 x is y 为真。 一个对象的标识号可使用 id() 函数来确定。 x is not y 会产生相反的逻辑值。

逻辑运算

运算符 not x 将在 x 为真 False,否则 True

表达式 x and y 首先对 x 求值;如果 x 为假则返回该值;否则对 y 求值并返回其结果值。换句话说,两者为真才为真,出现假值直接返回,求值顺序从左到右

表达式 x or y 首先对 x 求值;如果 x 为真则返回该值;否则对 y 求值并返回其结果值。换句话说,两者真有则为真,出现真值直接返回,求值顺序从左到右

注意:

  1. not 将创建一个新值,必须是一个布尔值。例如:not "" 返回 True,不能返回字符串或其他任何值。
  2. andor 表达式的返回值不必为布尔值,而是返回最后被求值的值。例如:
x, y = 1, 3
x == 1 and y > 1	# True, x==1为真,继续求y>1的值,最后返回y>1的值
x == 1 and y		# 3	  , x==1为真,继续求y的值,最后返回y的值
x == 1 or y < 1		# True, x==1为真,不继续求值,直接返回真
x != 1 or y			# 3   , x!=1为真,继续求y的值,最后返回y的值

表达式运算

条件表达式

条件表达式(有时称为**“三元运算符**”),具有最低的优先级。

其格式 x if C else y 首先是对条件进行判断。 如果条件为真,x 将被求值并返回其值;否则将对 y 求值并返回其值。

x = 1
y = 2*x if x % 2 else x  # 奇数取2倍,偶数取本身

赋值表达式

赋值表达式(命名表达式、海象表达式)将一个表达式赋值给一个标识符,同时还会返回表达式的值。

这是一个很不常用的表达式,赋值语句有更好理解的语法和适用性。

lambda 表达式

完全可以理解为一个轻巧的函数。

def lambda(*args)
	return expression
f1 = lambda

f2 = lambda *args: expression	# f1, f2 具有相同的作用
  • lambda 表达式被用于创建匿名函数,生成一个函数对象。
  • expression 只能是表达式,不能包含任何语句

await 表达式

挂起一个 awaitable 对象等待执行,只能在协程函数内部使用。一个简单的例子如下:

from asyncio import run

async def get_now():
    import datetime
    return datetime.datetime.now()

async def show_now():
    now = await get_now()
    print(now)

if __name__ == '__main__':
    run(show_now())

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值