今日(きょう)(さわ)がしく(たわむ)れ生きる人々の漫画映画(まんがえいが)

Python(3) Cheatsheet

好吧,我还是回来学 Python 了。顺便在这里稍微留一个简易 Cheatsheet 免得再次出现这种要再学一次的惨状。

语法

基本

语句

Python 中每一语句一行,没有语句结束的标识(如 C 中的 ; )。Line continuation 有两种方式:

  • 显式:在行末使用反斜杠 \ 表示语句在这一行没有结束;

  • 隐式:例如:

    # 隐式续行:函数调用
    print('This is a',
        'line continuation')
    # 隐式续行:(), [], {} 这些括号
    if (condition1 and
            condition2):
        pass
    def foo(
            x, # 隐式续行每行可以跟随注释
            y):
        pass
    

续的行的缩进似乎是随意的。( 这里有一份推荐的续行方式指南 ,但(划去)去你的吧我才不记。)

语句块与缩进

Python 的语句块以上一行的 : 开始,语句块中每行语句必须以相同的缩进开始,缩进应该叠加,每叠一层语句块增加的缩进不一定相同,如:

if condition1:
    do_something()
else:
        if condition2:
          do_other_things()
always_do()

标识符

Python 的标识符第一个字符不能为 0-9,其余的可为 0-9, A-Z, a-z, _ 以及很多其它的 Unicode 字符(如中文),大小写敏感。标识符不能与关键字重合:

False      await      else       import     pass
None       break      except     in         raise
True       class      finally    is         return
and        continue   for        lambda     try
as         def        from       nonlocal   while
assert     del        global     not        with
async      elif       if         or         yield

形如 _* , __*__ , __* 的标识符有特殊意义,之后说明。

语义数据类型

这里尝试包括字面值以及一些可以通过特殊语法构造的对象(即不使用普适的类或函数等)。

字符串

字面值:详见: String and Bytes literals

# 这两种字符串中不能直接出现换行或是反斜杠或是对应的引号,必须转义
# 当然,也有其它转义字符
str1 = 'string1 with \\ and \n and \' in it'
str2 = "string2 with \\ and \n and \" in it"
# 这种字符串中只有反斜杠必须转义
longstr1 = '''a normal string'''
longstr2 = '''a normal string: ''\'''' # 当然这种情况还是需要做些处理
longstr3 = """another"""
longstr4 = """but this is
how it is supposed
to be used"""
# 上面任意一种字符串前都可以加上修饰前缀
# 这里略
somestr1 = r'''raw string with \ as a normal character'''
# 相邻字符串会自动连接
concat1= '''Hello ''' "World" # concat1 = "Hello World"
格式化的字符串

这个真的太绝望了,脚本语言是吧 Python……其实这个并不是字符串字面值,而是类似于 str.format 的一种包装,是运行时求值的。

官方文档这里 拉下去看例子吧。

字节数组

可以用类似字符串的方式来表示,使用 b 作为字符串前缀即可,字符串内部只能含有 ASCII 字符。

数字

  • 整数:中间可以掺杂任意单个的下划线,下划线会被直接忽略。整数是无限精度的。

    • 十进制:非零数字开头;

    • 二进制: 0b0B 开头;

    • 八进制: 0o0O 开头;

    • 十六进制: 0x0X 开头,十六进制 a-f 不分大小写。

  • 浮点数: [数字].[数字]数字e数字 的格式, e 大小写均可。

  • 虚数/复数: 在普通数字后加后缀 jJ 表示虚数单位,可以加上一个实数表示复数。

序列

字符串、字节数组也属于序列。

天哪,我举例子吧……

a = (1, 2, 3)
b = (1, )
c = [1, 2, 3]
d = (*a, ) # d = (1, 2, 3)
e = [*a, 4] # e = [1, 2, 3, 4]
f = {*a} # f = {1, 2, 3}
g = {"a": 1, "b": 2}
h = {**g, "c": 3} # h = {"a": 1, "b": 2, "c": 3}

i = [(x, y) for x in range(1, 4) for y in range(3, 5) if x == y]
# i = [(3, 3)]
j = {(x, y) for x in range(1, 4) for y in range(3, 5) if x == y}
# j = {(3, 3)}
k = {x: y for x in range(1, 4) for y in range(3, 5) if x == y}
# k = {3: 3}
元组

内含有逗号 , 的括号 () 会被解释为元组(tuple),有时候无需括号也可以生成元组。

列表
陈列(Display)

Lambda

max = lambda x, y : x if x > y else y

一些内建常值类型

  • None: None

  • NotImplemented: NotImplemented

  • Ellipsis: Ellipsis...

  • True, False: TrueFalse

数据运算与操作

似乎 Python 也支持操作符重载了?

下面表格是随便排的序,优先级请多用括号。

加减乘除括号

乘方

e ** x

反码

~x == -(x+1) # 因为 Python 整数无限精度,所以实际怎样不知道

矩阵相乘?

@

地板除

//

取余数

%

printf 式格式化

'%d %.1f' % (1, 2) == '1 2.0' # True

位左右移

2 << 1 == 4 and 2 >> 1 == 1 # True
# 因为无限精度,所以实际嗯哼

大于小于等于

同 C

相同引用

is

包含

in

布尔操作

and / or / not not 可以用于 is not / not in

赋值表达式

:=

条件表达式

x if C else y

序列操作

对于一个序列 seq ,可能的操作:

  • 类似普通数组: seq[0]

  • 数组反向: seq[-1]

  • 对于 dict: seq["key"]

  • Slicing:例如普通 list:

    • 序号取 1 到 3 (在 4 前停)共 3 个元素: seq[1:4]

    • 1 开始取,序号每递增 2,在 4 前停: seq[1:4:2]

  • Slicing:例如某些矩阵(?): seq[1:4, 2:4] 差不多就那意思

流程控制语句

return, yield, break, continue, raise 这些先略过。

if:

if condition1:
    pass
elif condition2:
    pass
else:
    pass

while:

while condition:
    pass

for:

for item in list:
    pass

函数

def function_name(arg1, arg2="default"):
    pass

函数定义时的参数顺序大概是:

def foo(
        pos1, pos2,               # 位置参数

        /,                        # 强制不能使用 foo(pos1=...)
                                  # 来调用函数
                                  # pos1 的值只能通过位置指定
        named1, named2="default", # 此后的参数可以使用关键词参数

        *otherpos,                # 收集多余的位置参数
                                  # 可以将 otherpos 这一名称省略
                                  # 此时变为 def foo(..., *, ...)
                                  # 意为星号后必须为关键词参数
                                  # 不能这样用 def foo(*)

        named3, named4="default", # 前面星号这里强制使用 foo(name3=...)
                                  # 来指定 name3, name4 的值

        **othernamed):            # 收集多余的关键词参数
    pass

摘录并翻译一下文档的一段话: https://docs.python.org/3/reference/expressions.html#calls

首先,生成一个还未填进参数的列表。如果有 N 个位置参数(positional arguments),那么这 N 个参数就先填进列表的最开头。 然后,对于每一个关键词参数(keyword argument),先用参数标识找到其在列表中对应的位置。 如果关键词参数对应的位置已填入了参数,那么抛出 TypeError 异常。否则,将值填进列表中。 处理完后,如果列表还有参数没有填入值的话,使用默认值;如没有默认值,则抛出 TypeError 错误。

如果位置参数比正式参数(formal parameters)多,则抛出 TypeError 异常。(除非存在 *identifier 的正式参数,此时此参数将会接收到一个含有多余参数的 tuple,此参数默认为空 tuple。) 如果某个关键词参数的标识没有对应任一个正式参数的名称的话,抛出 TypeError 异常。(除非存在 **identifier 的正式参数,此时此参数将会接收到一个含有多余参数的 dictionary,此参数默认为空 dictionary。)

(天哪……躺平)

lambda

前面已有。

面对对象

class ClassName:
    def __init__(self):
        pass
class Inheritance(ClassName):
    pass

特殊名字的成员函数

Python 的面对对象的东西(几乎)全部基于具有特殊名字的函数。关键字里 private , protected 没有的。行吧。

__* 这样的名称是私有的成员。

类中的函数(一般)要包涵个 self 参数。

  • 生命周期:

    • __new__

    • __init__

    • __del__

  • 类型转换:

    • __repr__

    • __str__

    • __bytes__

    • __format__

    • __bool__

    • __hash__

  • 比较运算:

    • __lt__

    • __le__

    • __eq__

    • __ne__

    • __gt__

    • __ge__

  • 类的功能性:(meta?)

    • __getattr__

    • __getattribute__

    • __setattr__

    • __delattr__

    • __dir__

    • __get__

    • __set__

    • __delete__

    • __set_name__

    • __init_subclass__

  • 与内建函数有关?:

    • __len__

  • 模仿可调用的对象:

    • __call__

  • 模仿可取下标的对象:

    • 类本身取下标:( class[i] 这样)

      • __class_getitem__

    • 容器类:

      • __getitem__

      • __length_hint__

      • __getitem__

      • __setitem__

      • __delitem__

      • __missing__

      • __iter__

      • __reversed__

      • __contains__

  • 模仿数字类型: https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types

啊我不管了 https://docs.python.org/3/reference/datamodel.html#special-method-names

全局函数(?)

下面名称后没有跟括号的就表示用法过多略了。但一般还是比较符合直觉的?

abs(-11)                 # 11
all([True, True, False]) # False
any([True, True, False]) # True
ascii('中文')             # "'\\u4e2d\\u6587'"
bin(3)                   # '0b11'
bool('A')                # True
breakpoint()             # 用法过多略
bytearray                # 创建 bytearray
bytes                    # 创建 bytes
callable(lambda x:x)     # True
chr(8364)                # '€'
@classmethod             # 是个 decorator
compile                  # 如其名,复杂
complex(1, 2)+complex('0+1j') # (1+3j)
delattr(x, 'foobar')     # 同 del x.foobar
dict                     # 创建 dict
dir                      # 列举属性
divmod(7, 3)             # (2, 1)
enumerate                # yield (n, elem) for elem in seq
eval                     # 如名
exec                     # 和 eval 是同一类的?
filter(lambda x: x>5, [5, 6]) # list(_) == [6]
float                    # 创建 float
format                   # 返回格式化的字符串
frozenset                # 创建 frozenset
getattr(x, 'foobar', "default") # 不解释
globals()                # 返回当前全局符号表
hasattr(x, 'foobar')     # 不解释
hash(x)                  # 不解释
help                     # 恩
hex(255)                 # '0xff'
id                       # 略
input('请输入')           # _ == 输入的内容
int                      # 创建 int,可使用 base 参数
isinstance(object, class)# 恩
issubclass(class, class1)# 恩
iter                     # 创建对应的 iter
len                      # length
list                     # 创建 list
locals()                 # 返回当前局域符号表
map(lambda x: x+1, [3, 4, 5]) # list(_) == [4, 5, 6]
max                      # 恩
memoryview               # 不懂
min                      # 恩
next(iterator, default)  # 恩
object                   # 创建 object
oct(8)                   # '0o10'
open                     # fopen 多一点
ord('a')                 # 97
pow(base, exp [,mod])    # 乘方,mod 参数是为了计算效率
print                    # 恩
property                 # 额设置 getter setter?
range                    # range(10) == range(0, 10, 1)
repr                     # 返回对象的表示,最好可以再用 eval 还原
reversed                 # 创建反向 iter
round(number [,ndigits]) # 四舍五入
set                      # 创建 set
setattr(x, 'foobar', 10) # 不解释
slice                    # 创建 slice,与 range 差不多
sorted                   # 排序,一般不应该叫 sort 吗
@staticmethod            # decorator 不懂
str                      # 创建 str
sum(iterable [,start])   # 恩
super                    # 在类函数中返回上级类,可加一些参数
tuple                    # 创建 tuple
type                     # 返回/创建一个类/类型
vars                     # 返回 __dict__
zip                      # 不懂
__import__               # 见后续模块系统

模块系统

import math
import math as pymath
from math import log10

之后用到再补充。

pip install numpy

异常系统

x = 5
y = 0
try:
    z = x/y
    raise AssertionError() from Exception()
except ZeroDivisionError as e:
    print('Error: ', e)
except:
    print('Catches all other errors')
else:
    print('No exceptions')
finally:
    z = 0
    print(z)

内建异常类型

额这里就不摘录了。 https://docs.python.org/3/library/exceptions.html#base-classes

常用库

之后用到再慢慢补充。基本还是到官方文档去查看库的详细内容为好。

math

这个不用说了。

time

https://docs.python.org/3/library/time.html

和时间有关的函数。值得一提的是 sleep 在这个库里。

threading

https://docs.python.org/3/library/threading.html

多线程相关。用到比较多的应该是里面的 Thread 类。

asyncio

要用到 asyncawait 关键字。 async 用于定义异步函数, await 用于等待本应异步的函数的返回。

async def some_async_func():
    await asyncio.sleep(1) # 休眠一秒
await some_async_func()

异步函数执行返回的结果是一个 coroutine 对象,需要使用库函数或 await 才能真正执行:

>>> main()
<coroutine object main at 0x1053bb7c8>

库本身的函数: - asyncio.sleep(seconds) : 等待秒数,常与 await 连用; - asyncio.run(async_func()) : 执行一个 coroutine 对象,但不等待; - asyncio.create_task(async_func()) : 执行一个 coroutine 对象,并返回一个 Task 对象, Task 对象可以用于后续的 await 或者用于取消该任务(但是实际上 create_task 后任务已经可能执行了,所以取消不一定有什么用?); - asyncio.gather(co1, ..., future1, ...) : 将一系列的 coroutine 等对象执行,返回对应的 future 对象,返回值为系列返回值的列表;

要注意的是,因为程序其实还是单线程,所以如果有 input() 等的阻断式操作,整个逻辑大概就会死得很惨。可以看这里: Prompt for user input using python asyncio.create_server instance

subprocess

import subprocess
process = subprocess.Popen(executablePath,
                           stdout=subprocess.PIPE,
                           universal_newlines=True)
while True:
    line = process.stdout.readline()
    # process output line
    if something():
        break
process.terminate()
# import os
# import signal
# os.kill(process.pid, signal.SIGINT) # if process captures SIGINT for some reason

signal

def pre_exit():
    # something to do before exiting
    exit()
signal.signal(signal.SIGINT, pre_exit)

评论