变量运算#

运算符优先级:布尔( andornot )> 比较( ==!=>=<= )> 数值 > 正负号 > 幂运算

1. 布尔运算#

  • or 全为真,取第一个值

  • and 全为真,取最后一个值

var = (2 or 3) * (5 and 6 and 7)
print("var", var); # 2*7

2. 数值#

  1. 首个二进制数表示 ±,0 表示正,1 表示负

  2. 1 字节的最大值为 255

  3. 一般情况下,1 个数字占 4 个字节,或 8 个字节

  4. 1 个字符(及整数)占 1 个字节

名称

千字节

字节

比特位

符号

kB

B

bit

关系

1 k = 1024 B

1 B = 8 bit

1 bit = 1·(0/1)

  • 原码、反码、补码

原码 ⟷ 补码

补码

正数

相等

相等

负数

首位不变,其他位取反,末位 +1

反码=补码 +1

加法

使用补码

使用补码

乘法

先移位翻倍,然后做加法

先移位翻倍,然后做加法

  • 位运算

符号

功能

备注

&

按位与

逐位比较,逐位取 0 或 1

按位或

逐位比较,逐位取 0 或 1

按位异或

逐位比较,不同为 1,用于 0, 1 互换

~

取反

结果 -1(补码运算)

<<

左移

左移 1 位,数值 ×2

>>

右移

左移 1 位,数值 ÷2

3. 时间#

协调世界时(Coordinated Universal Time,UTC)是标准的、与时区无关的时间表示法。UTC 对于计算机来说非常好用,自 UNIX 纪元以来,它以秒来表示时间。但,UTC 对于人类来说并不理想。人类的时间是相对于他们当前所处的位置而言的。

3.1. 转化#

from datetime import datetime, timedelta

text = '2012-09-20'
y = datetime.strptime(text, '%Y-%m-%d')
z = datetime.now()
diff = z - y
diff
# datetime.timedelta(3, 77824, 177393)

3.2. 查询#

若需要执行大量类似的日期计算,最好安装 python-dateutil 包。

from datetime import datetime
from dateutil.relativedelta import relativedelta
from dateutil.rrule import FR

d = datetime.now()
print(d)
# 2012-12-23 16:31:52.718111
# Next Friday
print(d + relativedelta(weekday=FR))
# 2012-12-28 16:31:52.718111

# Last Friday
print(d + relativedelta(weekday=FR(-1)))
# 2012-12-21 16:31:52.718111

# 获取当前 datetime
now = datetime.now()
print(now)
# 获取指定日期和时间
dt = datetime(2020, 4, 19, 12, 20)
print(dt)

3.3. 运算#

from datetime import timedelta

a = timedelta(days=2, hours=6)
b = timedelta(hours=4.5)
c = a + b
c.days # 2
c.seconds # 37800

# datetime 加减
print(now + timedelta(hours=10))
print(now - timedelta(days=1))

当执行计算时,应该要注意的是 datetime 模块是可正确处理闰年的。

from datetime import datetime

a = datetime(2012, 3, 1)
b = datetime(2012, 2, 28)
a - b
datetime.timedelta(2)
(a - b).days # 2

3.4. 换算#

Python 提供了两种方式来完成时区变换。旧的方法,使用 time 内置模块,非常容易出错。新的方法,使用内置的 datetime 模块,在社区构建的 pytz 包的帮助下,效果非常好。

from datetime import datetime

# datetime 变换为 timestamp
t = dt.timestamp()
print(t)
# timestamp 变换为 datetime
print(datetime.fromtimestamp(t))
# timestamp 变换为 UTC 标准时区的时间
print(datetime.utcfromtimestamp(t))

# str 变换为 datetime
cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')
print(cday)

# datetime 变换为 str
print(now.strftime('%a, %b %d %H:%M'))

4. 文本#

由于历史原因,计算机中存在不同的编码方案。在计算机内存中,统一使用 Unicode 编码,当需要保存到硬盘或需要传输的时候,就变换为 UTF-8 编码。

  • Unicode: 为 2 个字节,统一编码标准,支持多语言

  • UTF-8: 把一个 Unicode 字符根据不同数字大小编码成 1-6 个字节,常用英文字母被编码成 1 个字节,汉字通常是 3 个字节,只有很生僻的字符才会被编码成 4-6 个字节。

  • ASCII 编码:为 1 个字节,美国人发明

4.1. Unicode#

ord(str) 可将单个字符转化为 Unicode 值

Unicode 值

数字字符

数字 +48

大写字母

字母表序号 +64

小写字母

字母表序号 +90

import unicodedata

s1 = 'Spicy Jalape\u00f1o'
s2 = 'Spicy Jalapen\u0303o'
s1
# 'Spicy Jalapeño'
s2
# 'Spicy Jalapeño'
s1 == s2
# False

t1 = unicodedata.normalize('NFC', s1)
t2 = unicodedata.normalize('NFC', s2)
t1 == t2
# True

去除所有的音符标记:

NFC 表示字符是全组成的。 NFD 表示使用组合字符,每个字符应该是能完全分解开的。

t1 = unicodedata.normalize('NFD', s1)
''.join(c for c in t1 if not unicodedata.combining(c))
# 'Spicy Jalapeno'

把所有的 Unicode 组合字符都去掉:

import unicodedata
import sys

cmb_chrs = dict.fromkeys(c for c in range(sys.maxunicode)
                         if unicodedata.combining(chr(c)))

a = 'pýtĥöñ'
b = unicodedata.normalize('NFD', a)
b.translate(cmb_chrs)
# python

4.2. ASCII 码#

将所有的 Unicode 十进制数字字符映射为它们对应的 ASCII 版本

digitmap = {
    c: ord('0') + unicodedata.digit(chr(c))
    for c in range(sys.maxunicode) if unicodedata.category(chr(c)) == 'Nd'
}

# Arabic digits
x = '\u0661\u0662\u0663'
# x
# '١٢٣'
x.translate(digitmap)
# '123'

另一种用来清理文本的技术涉及 I/O 解码和编码函数。大致思路是首先对文本做初步的清理,然后通过结合 encode()decode() 操作来修改或清理文本。

a = 'pytĥon is awesome\n'
b = unicodedata.normalize('NFD', a)
b.encode('ascii', 'ignore').decode('ascii')
# 'python is awesome\n'

4.3. 字节码#

在 Python 中,有两种类型来表示字符数据的序列:“字节” 和 “字符串”。 “字节” 的实例包含原始的、无符号的 8 位值(通常用 ASCII 编码显示)。重要的是,”字符串”实例没有相关的二进制编码,“字节” 实例也没有相关的文本编码。要将 Unicode 数据变换为二进制数据,必须调用 “字符串”的编码方法。要将二进制数据变换为 Unicode 数据,必须调用 “字节” 的解码方法。可为这些方法显式地指定想使用的编码,或接受系统默认值,通常是 UTF-8。

a = b"h\x65llo"
print(list(a))
print(a)

字符串”的实例包含代表人类语言文字字符的 Unicode 编码。但,Python 默认是不自动识别 Unicode 的。

a = "a\u0300 propos"
print(list(a))
print(a)

这时需要手动解决。Python 提供了相应的 2 种类型变换方法对 “字符串”和 “字节” 进行变换,其中,encode() 用于 “字符串”转 “字节” 叫,decode() 用于 “字节” 转 “字符串”。

a = "a\u0300 propos"
a = a.encode("utf-8")
print(list(a))
print(a)

当编写 Python 程序时,在接口的最远边界进行 Unicode 数据的编码和解码是很重要的;这种方法通常被称为 Unicode 三明治。程序的核心应该使用包含 Unicode 数据的 “字符串”类型。这种方法可让你很好地接受替代性的文本编码(如 Latin-1、Shift JIS 和 Big5),同时严格控制你的输出文本编码(最好是 UTF-8)。

def to_str(bytes_or_str):
    if isinstance(bytes_or_str, bytes):
        value = bytes_or_str.decode("utf-8")
    else:
        value = bytes_or_str
    return value  # Instance of str


print(repr(to_str(b"foo")))
print(repr(to_str("bar")))


def to_bytes(bytes_or_str):
    if isinstance(bytes_or_str, str):
        value = bytes_or_str.encode("utf-8")
    else:
        value = bytes_or_str
    return value  # Instance of bytes


print(repr(to_bytes(b"foo")))
print(repr(to_bytes("bar")))

一个问题是,“字节” 和 “字符串的工作方式似乎是一样的,但它们的实例之间是不兼容的,故必须慎重对待你所传递的字符序列的类型。如,不能使用 字符串”实例 + byte 实例。若要向/从文件读取或写入二进制数据,请始终使用二进制模式(如 "rb""wb" )打开文件。

5. 文本匹配#

5.1. Shell#

一般来说,fnmatch() 的匹配模式所采用的大小写区分规则和底层文件系统相同。若这个区别对我们而言很重要,就应该使用 fnmatchcase() 。它完全根据我们提供的大小写方式来匹配:

from fnmatch import fnmatch, fnmatchcase

# On OS X (Mac)
fnmatch('foo.txt', '*.TXT')
# False

# On Windows
fnmatch('foo.txt', '*.TXT')
# True

5.2. 正则表达式#

*+ 后添加一个 ?,会强制将匹配算法调整为寻找最短的可能匹配。

text = 'UPPER PYTHON, lower python, Mixed Python'

re.findall('python', text, flags=re.IGNORECASE)
# ['PYTHON', 'python', 'Python']
re.sub('python', 'snake', text, flags=re.IGNORECASE)
# 'UPPER snake, lower snake, Mixed snake'