变量运算#
运算符优先级:布尔( and
,or
,not
)> 比较( ==
,!=
,>=
,<=
)> 数值 > 正负号 > 幂运算
1. 布尔运算#
or
全为真,取第一个值and
全为真,取最后一个值
var = (2 or 3) * (5 and 6 and 7)
print("var", var); # 2*7
2. 数值#
首个二进制数表示
±
,0 表示正,1 表示负1 字节的最大值为 255
一般情况下,1 个数字占 4 个字节,或 8 个字节
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'