python学习之路☞8.Expression, Operand, Operators

python学习之路☞8.Expression, Operand, Operators

#python,#Expression,#Operand,#Operators,

Expression

'''
表达式(Expression): 由操作数(Operand) + 运算符(Operator)组成,产生一个值
'''

Operand

'''
操作数(Operand): 参与运算的数据对象
  分类:
    字面量(literal): 就是数据值,比如 42 3.14 "hi" True ...
    变量(varible): x name total ...
    函数调用(funcation): len(s) abs(-1) ...
    子表达式(Expression): (a + b) ...
'''

Operator

'''
运算符(Operator): 对操作数(Operand)执行的操作的符号
  分类:
    算术(Arithmetic): + - * / // % **
    比较(Comparison): > < == != >= <=
    逻辑(Logical): and or not
    赋值(Assignment): = += -= *= /=
    位运算(Bitwise): & | ^ ~ << >>
    成员(Membership): 
      in
      not in
    身份(Identity):
      is
      is not
    条件/三元(Conditional expression — 内联 if/else,返回值):
      x if condition else y

  要点说明
    **运算符的元数**
      一元:一个操作数,如 `not True`、`-x`
      二元(最常见):两个操作数,如 `a + b`
      三元:即条件表达式,`x if condition else y`
'''

Arithmetic Operators

'''
要点说明
/  永远返回 float(即使整除)。
// 向下取整,负数结果会"更小":`-7//2 = -4`  而非 -3。
** 优先级高于一元负号:`-2**2 = -4`,若要得 4 需写  `(-2)**2`。
%  结果符号与**除数**一致,可用于判断奇偶、循环索引等。
'''
print(10 + 3) # → 13
print(10 - 3) # → 7
print(10 * 3) # → 30
print(10 / 3) # → 3.3333…  (始终返回 float)
print(10 // 3) # → 3        (向下取整除)
print(10 % 3) # → 1        (取余/模)
print(2 ** 10) # → 1024     (幂)

# 负数的整除:
print(-7 // 2) # → -4  (向下,不是向零)
print(-7 %  2) # → 1   (结果符号同除数)

0

Comparison Operators

'''
要点说明
**链式比较** Python 独有语法,`a < b < c` 等价于 `a < b and b < c`,但 b 只求值一次,效率更高。
比较运算符可作用于任何实现了 `__eq__` / `__lt__` 等魔法方法的对象(列表、字符串、自定义类均可)。
**注意**:不要用 `==` 比较 `None`,应用 `is None`。
'''
print(5 == 5) # → True
print(5 != 3) # → True
print(5 >  3) # → True
print(5 <  3) # → False
print(5 >= 5) # → True
print(5 <= 4) # → False

# 链式比较(Python 特有):
print(1 < 5 < 10) # → True  等价于 1<5 and 5<10
print(1 < 5 > 3)  # → True

# 字符串按字典序比较:
print("apple" < "banana")  # → True

1

Logical Operators

'''
要点说明
短路求值:and 遇假即停,or 遇真即停,右侧不执行。
逻辑运算符返回操作数本身(非强制 bool),利用此特性可简洁地设默认值或做空值保护:obj and obj.method()。
优先级:not > and > or,均低于比较运算符。
'''
print(True and False)  # → False
print(True or  False)  # → True
print(not True)        # → False
print(not False)       # → True

# 短路求值——返回操作数本身,不强转 bool:
print(0   and "hello")   # → 0        (左假即停)
print(5   and "hello")   # → "hello"  (左真返右)
print(0   or  "hello")   # → "hello"  (左假返右)
print("x" or  "hello")   # → "x"      (左真即停)

# 实用模式:
input_val = ''
name = input_val or "anonymous"
cache = '123'
def compute():
  pass # 功能性代码
result = cache or compute()
print(f'{result=}')

2

Assignment Operators

'''
要点说明
增量赋值(`+=`  等)是语法糖,底层调用  `__iadd__`  等原地操作魔法方法,
                  对可变对象(list)原地修改,
                  对不可变对象(str、int)创建新对象。
**海象运算符 :=**  是赋值**表达式**(有返回值),
            而普通  `=`  是语句(无返回值)。
            常用于 while 循环和推导式中避免重复计算。
'''
x = 10 # 基本赋值

x += 3 # x = x + 3  → 13
print(f'{x=}')
x -= 2 # x = x - 2  → 11
print(f'{x=}')
x *= 2 # x = x * 2  → 22
print(f'{x=}')
x /= 4 # x = x / 4  → 5.5
print(f'{x=}')
x //= 2 # x = x // 2 → 2.0
print(f'{x=}')
x **= 3 # x = x ** 3 → 8.0
print(f'{x=}')
x %= 3 # x = x % 3  → 2.0
print(f'{x=}')

# 海象运算符 := (Python 3.8+)
data = "123456"
if n := len(data):
    print(f"有 {n} 个元素")

# 多重赋值 / 解包:
a, b = 1, 2
print(f'{a=},{b=}')
a, b = b, a  # 交换
print(f'{a=},{b=}')
x = y = z = 0
print(f'{x=},{y=},{z=}')

3

Bitwise Operators

'''
要点说明
&:两位均为1才得1
|:至少一位为1得1
^(异或):两位不同得1,相同得0
~:取反,结果为  `-(n+1)`,因为补码表示
左移  `n << k`  等价于乘以 2ᵏ,右移等价于整除 2ᵏ,比乘除法更快。
常用于权限标志位、底层数据处理、加密算法。
'''

原码、反码、补码

为什么计算机用补码存储负数?

'''
位可视化
三者的转换流程(以 -11 为例,8位):
原码:符号位 + 绝对值的二进制
      1  000 1011   (最高位 1 表示负,后面是 11 的二进制)

反码:原码符号位不变,其余各位取反
      1  111 0100

补码:反码 + 1
      1  111 0101   ← 计算机实际存的就是这个

验证(补码加法,结果应=0):
  0000 1011   (+11 的补码)
+ 1111 0101   (-11 的补码)
─────────────
1 0000 0000   最高位溢出丢弃 → 得 0  ✓

要点说明
**为什么用补码?**
原码和反码都有"正零"和"负零"两种表示(`0000 0000`  和  `1000 0000`),逻辑混乱。

补码只有一个零,且**加减法可以统一成加法**——CPU 不需要专门的减法电路,节省硬件。

**8位补码范围**:-128 到 +127(非对称,因为 -128 没有对应的正数)

**`~n = -(n+1)` 的来源:** 对补码按位取反,恰好跳过了"加 1"这步,所以结果是比补码少 1,即 `-(n+1)`。这不是规定,是补码数学的自然结论。

**Python 与固定位宽语言的区别:** C/Java 的 `int` 固定 32 位,左移超出会溢出丢位。Python 的 `int` 是任意精度,会自动扩展,永远不溢出——代价是内存占用略大,但对位运算的语义更纯粹。
'''
print(bin(-11))            # '-0b1011'  (Python显示原码形式)
print((-11).bit_length())  # 4 (不含符号位)

4

& 按位与 (AND)

两位均为 1 → 结果为 1,否则为 0

'''
位可视化
a=10 0000 1010 = 10
b=12 0000 1100 = 12
a&b  0000 1000 = 8

要点说明
**规则**:1 & 1 = 1,其余全为 0
**掩码(mask)**:用 AND 提取某几位。例如  `n & 0xFF`  只保留最低 8 位,高位全部清零。
**判断奇偶**:`n & 1`,结果 1 = 奇数,0 = 偶数(比  `n % 2`  更底层)。
**判断 2 的幂**:`n & (n-1) == 0`(2 的幂二进制只有一个 1)。
'''
# 按位对齐:
#   0000 1010   (10)
# & 0000 1100   (12)
# ─────────────
#   0000 1000   (8)
a =  10   # 二进制: 0000 1010
b =  12   # 二进制: 0000 1100
r = a & b # → 8
print(f'{r=}')

# 实用技巧:
n = 100
print(n & 1)        # 判断奇偶(末位是否为1)
print(n & 0xFF)     # 取低8位(掩码操作)
print(n & (n-1))    # 清除最低位的1(判断2的幂)

5

| 按位或 (OR)

至少一位为 1 → 结果为 1

'''
位可视化
a=10 0000 1010 = 10
b=12 0000 1100 = 12
a|b  0000 1110 = 14

要点说明
**规则**:0 | 0 = 0,其余全为 1
**置位(set bit)**:用 OR 把某一位强制设为 1。`n |= (1 << k)`  把第 k 位设 1。
**权限标志位**:文件系统、网络协议常用 OR 组合多个权限,用 AND 检查某权限。
**注意**:不要与逻辑  `or`  混淆,`|`  无短路,两侧都会求值。
'''
# 按位对齐:
#   0000 1010   (10)
# | 0000 1100   (12)
# ─────────────
#   0000 1110   (14)
a =  10  # 二进制: 0000 1010
b =  12  # 二进制: 0000 1100
r = a | b  # → 14
print(f'{r=}')

# 实用技巧:
flags = 0b0000
READ    = 0b0001  # 权限位 1
print(f'{READ=}')
WRITE   = 0b0010  # 权限位 2
print(f'{WRITE=}')
EXECUTE = 0b0100  # 权限位 3
print(f'{EXECUTE=}')
flags |= READ | WRITE  # 开启读写权限
print(f'{flags=}')

6

^ 按位异或 (XOR)

两位不同 → 1,相同 → 0

'''
位可视化
a=10 0000 1010 = 10
b=12 0000 1100 = 12
a^b  0000 0110 = 6

要点说明
**规则**:相同得 0,不同得 1
**可逆性**:`a ^ b ^ a = b`,异或可以"撤销",用于简单加密和无临时变量交换。
**找唯一数**:数组中只有一个数出现奇数次,其余出现偶数次,对所有元素连续异或即得该数(重复数互相抵消)。
常用于校验和(checksum)和 RAID 奇偶校验。
'''
# 按位对齐:
#   0000 1010   (10)
# ^ 0000 1100   (12)
# ─────────────
#   0000 0110   (6)
a =  10  # 二进制: 0000 1010
b =  12  # 二进制: 0000 1100
r = a ^ b  # → 6
print(f'{r=}')

# 特性:
n = 100
print(f'{n=}')
print(n ^ n)  # → 0   (自身异或得0)
print(n ^ 0)  # → n   (与0异或不变)

print(f'{a=},{b=}')
print(a ^ b ^ a)  # → b (可还原)

# 不用临时变量交换两数:
a, b = 10, 20
print(f'{a=},{b=}')

a ^= b; b ^= a; a ^= b
# a=20, b=10
print(f'{a=},{b=}')

7

~ 按位取反 (NOT)

每一位 0 变 1、1 变 0,结果 = -(n+1)

'''
位可视化
n = 10 的取反过程(8位)
n=10 0000 1010 = +10
~n   1111 0101 = -11
红色 = 符号位(0正 1负)

要点说明
**为何 ~10 = -11**?因为计算机用**补码**存储整数。对补码按位取反,恰好等于 -(n+1)。
Python 的 int 是**任意精度**(无固定位宽),取反结果遵循同样规律:`~n = -(n+1)`。
**实用**:`n & ~mask`  清除 mask 中为 1 的那些位(先取反再与)。
'''
# 理解过程(以8位补码为例):
# 10 的补码:  0000 1010
# 按位取反:   1111 0101   ← 这是 -11 的补码
# 验证 -11:   原码 1000 1011
#            取反 1111 0100
#            加1  1111 0101  ✓
n =  10  # 原码:  0000 1010
print(~n)  # 为什么是 -11?

# 公式:~n = -(n + 1)
print(~0)   # → -1
print(~1)   # → -2
print(~-1)  # → 0

# 实用:
mask = 199
print(~n & mask)   # 清除某些位
print(n & ~mask)   # 清除 mask 对应的位

8

<< 左移 (Left shift)

二进制整体左移 n 位,低位补 0,等价于 × 2ⁿ

'''
位可视化
1 << 0 到 1 << 4
1<<0 0000 0001 = 1
1<<1 0000 0010 = 2
1<<2 0000 0100 = 4
1<<3 0000 1000 = 8
1<<4 0001 0000 = 16

要点说明
**左移 k 位 = × 2ᵏ**,但比乘法更快(直接移位操作)。
**生成掩码**:`1 << k`  生成第 k 位为 1、其余为 0 的掩码,再配合 &、|、^ 操作任意位。
**Python 不会溢出**:C/Java 左移超过位宽会丢失高位,Python 的 int 是任意精度,会正确扩展。
'''
n = 1
print(n << 0)  # → 1    二进制: 0000 0001
print(n << 1)  # → 2    二进制: 0000 0010
print(n << 2)  # → 4    二进制: 0000 0100
print(n << 3)  # → 8    二进制: 0000 1000
print(n << 4)  # → 16   二进制: 0001 0000

# 等价于乘以 2 的幂:
print(5 << 3)  # → 40   等价于 5 * 8

# 生成位掩码:
print(1 << 0)  # → 0b00000001  (第0位)
print(1 << 3)  # → 0b00001000  (第3位)
print(1 << 7)  # → 0b10000000  (第7位)

# Python int 无溢出,可无限左移
print(1 << 100)  # → 一个很大的数

9

>> 右移 (Right shift)

二进制整体右移 n 位,等价于 // 2ⁿ(向下取整)

'''
位可视化
64 >> 0 到 64 >> 4
64>>0 0100 0000 = 64
64>>1 0010 0000 = 32
64>>2 0001 0000 = 16
64>>3 0000 1000 = 8
64>>4 0000 0100 = 4

要点说明
**右移 k 位 = // 2ᵏ**(向下整除,负数也成立)。
**算术右移**:Python 右移补符号位(正数补 0,负数补 1),不会改变数的正负。
**取第 k 位**:`(n >> k) & 1`,先把目标位移到最低位,再用 AND 取出。
`-1 >> 任意正数 = -1`,因为 -1 的补码全是 1,右移补 1 仍然全是 1。
'''
n = 64  # 二进制: 0100 0000
print(n >> 1)  # → 32   0010 0000
print(n >> 2)  # → 16   0001 0000
print(n >> 3)  # →  8   0000 1000
print(n >> 6)  # →  1   0000 0001
print(n >> 7)  # →  0   0000 0000  (全移走了)

# 等价于整除 2 的幂:
print(100 >> 2)   # → 25  等价于 100 // 4

# 负数右移(算术右移,补符号位):
print(-8 >> 1)    # → -4  (保持负号)
print(-1 >> 10)   # → -1  (全1,永远是-1)

# 取某一位的值(索引值从0开始):
n = 8  # 0000 1000
k = 3
print((n >> k) & 1)  # 取第 k 位(0或1)

10

Membership Operators

'''
要点说明
in 对不同容器的时间复杂度不同:
· list / tuple:O(n) 线性查找
· set / dict:O(1) 哈希查找
· str:O(n·m) 子串搜索

大量成员检查时应优先用 set 而非 list。

自定义类可通过实现 __contains__ 魔法方法支持 in 运算符。
'''
# str(检查子串)
print("he" in "hello")       # → True
print("xyz" not in "hello")  # → True

# list
print(3 in [1, 2, 3])        # → True
print(5 not in [1, 2, 3])    # → True

# dict(检查键)
print("a" in {"a":1,"b":2})  # → True
print(1   in {"a":1,"b":2})  # → False (值不算)

# set(O(1) 查找)
print(3 in {1, 2, 3, 4})     # → True

# tuple
print((1,2) in [(1,2),(3,4)]) # → True

11

Identity Operators

'''
要点说明
is 比较的是 id()(内存地址),== 比较的是值(调用 __eq__)。

只在两种场景用 is:
1. 与 None 比较:x is None
2. 与单例比较:x is True(少见)

小整数缓存(-5 到 256)是 CPython 的实现细节,不同解释器行为不同,不要依赖它。
'''
# is 比较的是"同一个对象",不是"相等"
a = [1, 2, 3]
b = [1, 2, 3]
c = a

print(a == b)    # → True  (值相等)
print(a is b)    # → False (不同对象)
print(a is c)    # → True  (同一对象)

# None 判断惯用法(推荐):
x = None
print(x is None)      # → True  ✓ 正确
print(x == None)      # → True  ✗ 不推荐

# 小整数缓存(CPython 实现细节):
x = 256; y = 256
print(x is y)    # → True  (CPython 缓存 -5~256)
x = 257; y = 257
print(x is y)    # → False (超出缓存范围)

12

Conditional expression Operators

'''
要点说明
条件表达式是表达式(有返回值),普通 if 是语句(无返回值),因此可嵌入函数调用、列表推导、lambda 等任何需要值的地方。

与 C/Java 的 ?: 语义相同,但语法不同:Python 把条件写在中间。

嵌套超过两层时建议改用普通 if/elif/else,或字典映射。
'''
# 语法:值1 if 条件 else 值2
x = 10
result = "正" if x > 0 else "非正"
print(f'{result=}')  # → "正"

# 嵌套(可读性差,谨慎使用):
grade = "A" if x>=90 else "B" if x>=80 else "C"
print(f'{grade=}')

# 用在函数参数中:
print("偶数" if x % 2 == 0 else "奇数")

# 用在列表推导中:
nums=[ -123456, 12, 2323 ]
print([abs(n) if n >= 0 else -n for n in nums])

# 用于赋值默认值:
user_input = ''
val = user_input if user_input else "默认值"
print(f'{val=}')

13

参考

expressions

Comments