Python基本语法

基本语法

注释

# 注释

输入输出函数

# 输入
input("请输入:")

# 打印
print("xxx")

变量操作

# 赋值
a = 100
b = 200
c = 300

# 序列解包赋值,左侧变量数量与右侧序列元素数一致
t = (100, 200, 300)
l = [100, 200, 300]
s = "edf"
a, b, c = t
a, b, c = l
a, b, c = s
a, b, c = 100, 200, 300

# 左侧变量数量与右侧序列元素数不一致,剩余的给到最后一个变量
a, *b = t

# 匿名变量,约定使用下划线表示
_ = 1

# 删除变量
del a

命名约定

# 模块
module_name
# 包
package_name
# 类
ClassName
# 方法
function_name
# 异常
ExceptionName
# 全局常量
GLOBAL_CONSTANT_NAME
# 全局变量
global_var_name
# 实例变量
instance_var_name
# 方法参数
function_parameter_name
# 局部变量
local_var_name
# 类常量
CLASS_CONSTANT_NAME
# 特殊作用的方法或属性
__function_name__
# 私有变量
__var_name
# 内部变量
_var_name
# 避免关键字
class_

运行代码

eval("1 + 2")

数据类型

基本数据类型

# 整数
a = -100

# 浮点数
b = 99.99

# 精确十进制数
import decimal
a = decimal.Decimal("0.1")
b = decimal.Decimal("0.2")
print(a + b) 
# 0.3
c = decimal.Decimal("0.3")
print(a + b == c)
# True

# 数学计数法
print(0.00005)
# 5e-05

# 复数
x = 1 + 2j
print(x.real)
# 1
print(x.imag)
# 2

# 布尔值
c = True
d = False

# 内置函数返回None
e = None

# 字符串
f = "f"

# 列表
g = [1, 2, 3, 4]

# 元组
h = (1, 2, 3, 4)
h = 1, 2, 3, 4

# 集合
i = {1, 2, 3, 4}

# 字典
j = {
     "name": "Tom",
     "age": 18
}

布尔类型

调用bool()结果为False的情况:

  • 定义为False的对象:NoneFalse
  • 值为0的数字类型:00.00jDecimal(0)Fraction(0,1)
  • 空的序列和集合:''()[]{}set()range(0)

True的值等于整数1 False的值等于整数0

序列

序列是一种可遍历的集合类型,包括字符串、列表、元组、集合。列表和集合为可变序列,字符串和元组为不可变序列。一个序列对象是一个可迭代对象,可迭代对象可重复使用,而迭代器是一次性使用的

序列均可进行以下操作

  • +* 拼接与复制
  • isis not 判断是否为同一对象
  • innot in 判断元素中是否存在某值
  • del 删除序列中的元素

序列构造器,参数可为另外一个类型的可迭代对象(包括其他类型的序列或迭代器)

  • list() 列表
  • tuple() 元组
  • str() 字符串,列表或元组转字符串,结果是字符串是列表或元组的代码表现形式
  • set() 集合
# 求最小值
a = (1, 2, 3)
min(a)
# 求最大值
max(a)

# 求长度
len(a)

# 求和
sum(a)

# 排序,返回结果列表
sorted(a)
# 按某方法结果排序
sorted(a, key=len)

# 生成反向迭代器
reversed(a)

# 任意一个元素的值为True,则结果为True
any(a)
# 所有元素的值为True,则结果为True
all(a)

# 创建枚举对象
enumerate(a)

# 多列表联合转成元组列表, 以长度最短的列表长度为元组长度
x = [1, 2, 3]
y = [4, 5, 6]
z = [7, 8, 9]
zipped = zip(x, y, z)
list(zipped)
# [(1, 4, 7), (2, 5, 8), (3, 6, 9)]

# 以长度最长的列表长度为元组长度,没有对应元素的位置以None代替
import itertools
zipped = itertools.zip_longest(x, y, z)

# 遍历映射
# ord函数返回字符的编码
mapped = map(ord, "ABC")
# 支持多参数
# pow函数返回幂运算结果
mapped = map(pow, [2, 3, 10], [5, 2, 3])

# 遍历过滤
filterd = filter(str.islower, "aBc")

# 生成迭代器
iterator = iter(a)
# 遍历迭代器,当没有元素时抛异常
next(iterator)
# 当没有元素时返回默认值
next(iterator, -1)

字符串

字符串是不可变的

# 常规字符串,推荐双引号表示人类可读的文本,单引号表示数据
a = "a"
a = 'a'

# 多行字符串
a = """
a
a
"""

# 取消转义
a = r"\n"
print(a) #\n

# 单行字符串分开多行
a = "aaa\
bbb"
print(a) # aaabbb

# 字符串切片
string = "abcdefg"
string[0] # a
string[-1] # g
string[0:3] # abc
string[:3] # abc
string[-3:-1] # ef
string[-3:] # efg
string[0:6:2] # ace
string[::-1] # gfedcba

# 获取字符串长度
len(string)

# 字符串复制
string * 2 # abcdefgabcdefg

# 从左往右查找指定字符的位置,找不到返回-1
string.find("b")
string.find("c", 0, 5)
# 从右往左查找指定字符的位置,找不到返回-1
string.rfind("b")
string.rfind("c", 0, 5)
# 找不到抛异常
string.index("b")
string.rindex("b")


# 查询指定字符出现的次数
string.count("d")
string.count("d", 0, 5)

# 格式化字符串
string = "name:{}, age:{}"
string.format("Tom", "18") # name:Tom, age:18
# 指定参数位置
string = "name:{0}, age:{1}"
# 指定参数名
string = "name:{name}, age:{age}"
string.format(name="Tom", age="18")

# 指定格式,放在冒号右边,参数格式[[fill]align][sign][#][0][width][grouping_option][.precision][type]
# 冒号左边为上面的参数位置和参数名称
# ^居中 <左对齐 >右对齐 =数字右对齐(如有负号,在负号和数字之间填充) ,后面数字指定总宽度
string = "name:{:>10}, age:{:^10}"
# 指定填充字符
string = "name:{:%>10}, age:{:%^10}"
# 数字加正号
string = "age:{:%^+10}"
# 指定小数点后位数
string = "age:{:.2f}"
# 指定总数字位数
string = "age:{:.2g}"
# 输出二进制数
string = "age:{:b}"
# 输出八进制数
string = "age:{:o}"
# 输出十六进制数
string = "age:{:x}"
# 输出表示进制的前缀
string = "age:{:#b}"
# 科学计数法
string = "age:{:e}"
# 定点六位小数
string = "age:{:f}"
# 自动适配科学计数法和定点六位小数
string = "age:{:g}"
# 百分比
string = "age:{:%}"

# f-字符串,python3.6后支持,与format作用相同,效率更高
name = "Tom"
age = "18"
string = f"name:{name}, age:{age}" # name:Tom, age:18
string = f"name:{name:>10}, age:{age:^10}"


string = "name:%s, age:%d"
string % ("Tom", 18) # name:Tom, age:18

# 字符串拼接
a = "abc"
b = "def"
string = a + b # abcdef

# 去掉空格
string = "  a  "
string.strip() # a
string.lstrip()
string.rstrip()
# 指定去掉的字符,参数中的字符串中任意一个字符都会被去除
string.strip("abc")
# 去掉前缀
string.removeprefix("a")
string.removesuffix("c")

# 分割字符串,返回三元组(分割符前部分,分割符,分割符后部分)
a.partition(".")
a.rpartition(".")

# 分割字符串,返回分割后的各部分
a.split(".")
# 指定最大分割次数
a.split(".", 1)
a.rsplit(".", 1)
# 按换行符分割
a.splitlines()

# 字符串拼接,参数可以是任意序列,效率比+高
a = "a"
b = "b"
c = "c"
",".join((a, b ,c)) # a,b,c

# 首字母转大写
a.capitalize()
# 全转小写(能处理所有语言的字母)
a.casefold()
# 每个单词的首字母转大写,其他字母转小写
a.title()
# 大小写反转
a.swapcase()
# 全转大写
a.upper()
# 全转小写
a.lower()

# 对齐类,第一个参数为总用的总长度,第二个参数可选,为用于填充的字符
# 居中对齐
a.center(5)
a.center(5, "p")
# 左对齐
a.ljust(5)
# 右对齐
a.rjust(5)
# 左填充0
a.zfill(5)

# 制表符替换空格
a.expandtabs(4)

# 替换全部
a.replace("a", "b")
# 指定替换次数
a.replace("a", "b", 1)

# 转换表格
table = str.maketrans("abc", "123")
a.translate(table)

# 判断开头
a.startswith("a")
a.startswith("a", 1, 2)
# 判断结尾
a.endswith("a")
a.endswith("a", 0, 1)
# 支持从元组中判断,满足任一一个即可
a.startswith(("a", "b"))

# 是否都是单词第一个字母大写,其他小写
a.istitle()
# 是否全是大写
a.isupper()
# 是否全是字母
a.isalpha()
# 是否是空白字符串
a.isspace()
# 是否都是可打印字符(换行符不可打印)
a.isprintable()

# 是否为数字
a.isdecimal()
a.isdigit()
a.isnumeric()

# 是否是字母或数字
a.isalnum()

# 是否是合法的标识符
a.isidentifier()

# 是否为关键字
import keyword
keyword.iskeyword("if")

# 是否包含
"a" in a
"a" not in a

列表

# 创建列表
list1 = [1, 2, 3, 4]

# 访问列表某个位置的值
list1[0] # 第一个值
list1[-1] # 最后一个值

# 往某位置赋值
list1[0] = 10
list1[1:] = [3, 5, 7]

# 获取列表元素个数
len(list1)

list2 = [5, 6, 7, 8]
# 列表的拼接
list1 + list2 # [1, 2, 3, 4, 5, 6, 7, 8]
# 列表元素重复
list1 * 2 # [1, 2, 3, 4, 1, 2, 3, 4]

# 列表切片,包前不包后
list1[0:3] # [1, 2, 3]
# 第一个参数默认为0
list1[:3]
# 第二个参数默认为数组长度
list1[3:]
# 支持步进
list1[0:4:2]
list1[::2]
# 倒序
list1[::-1]

# 删除列表中的指定元素,可以使用切片语法
del list1[3] # [1, 2, 3]

# 往列表末尾增加一个元素
list1.append(4) # [1, 2, 3, 4]

# 往列表的某个位置插入一个元素
list1.insert(0, 0) # [0, 1, 2, 3, 4]

# 删除第一个指定值
list1.remove(4) # [0, 1, 2, 3]

# 往列表末尾增加另一个列表的元素
list1.extend([4, 5]) # [0, 1, 2, 3, 4, 5]
list1[len(list1):] = [4, 5]

# 返回某个元素并删除
list1.pop(1)

# 逆序
list1.reverse()

# 复制列表,浅拷贝
copyList = list1.copy()
copyList = list1[:]

# 排序
list1.sort()
list1.sort(reverse=True)

# 清除列表中的所有值
list1.clear()

# 列表内部可以是不同类型的值
list1 = [1, 2, 3, "s"]

# 某个值元素计数
list1.count(1)

# 查找第一个某值的位置
list1.index(3)
# 指定查找范围
list1.index(3, 1, 2)

# 嵌套列表
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

matrix = [None] * 3
for i in range(3):
    matrix[i] = [None * 2]

matrix = [[None] * 2 for i in range(3)]

# 访问嵌套列表的元素
matrix[0][0]

# 判断是否包含
1 in [1, 2]

# 列表推导式,生成一个新列表再赋值
x = [i + 1 for i in range(10)]
# 符合if条件才迭代
a = [i + 1 for i in range(10) if i % 2 == 0]
# 嵌套循环
flatten = [col for row in matrix for col in row]

# 列表元素计数
from collections import Counter

value_list = ['1', '1', '2', '5', '5', '5']
value_list_counter = Counter(value_list)
# value_list_counter {'1': 2, '2': 1, '5': 3},类字典结构,key是列表元素,value是个数

# 获取’1‘的个数,获取不到默认值为0
value_list_counter.get('1', 0)

元组

元组元素不可修改,其它与列表类似

# 创建元组
a = (1, 2, 3, 4)
b = 1, 2, 3, 4
# 创建只有一个元素的元组
c = (1,)

# 访问元组
a[0]
a[-1]

# 元组切片
a[:3]
a[3:]
a[:]
a[::-1]

# 嵌套元组
d = a, b

集合

集合是无序的,且元素不可重复。集合中的元素必须是不可变、可哈希的

# 创建集合
i = {1, 2, 3, 4}
a = set("1234")

# 创建不可变集合
i = frozenset("1234")

# 集合推导式
i = {s for s in "abc"}

# 列表转集合
b = set([1, 2, 3, 4])
# 元组转集合
c = set((1, 2, 3, 4))

# 元素不同类型
e = {1, (1,2), "12"}
# 创建空集合
g = set()

# 遍历集合
for each in i:
    print(each)

# 浅拷贝
t = i.copy()

a = {1, 2, 3}
b = {3, 4, 5}
# 是否无交集
a.isdisjoint(b)
# 是否是子集
a.issubset(b)
a <= b
# 是否是真子集
a < b
# 是否是超集
a.issuperset(b)
a >= b
# 是否是真超集
a > b

# 求并集
a.union(b)
a | b
# 求交集
a.intersection(b)
a & b
# 求差集
a.difference(b)
a - b
# 求对称差集
a.symmetric_difference(b)
a ^ b

# 增加一个元素
d.add(5)

f = {6, 7}
# 更新集合元素为并集结果
d.update(f)
# 更新集合元素为交集结果
d.intersection_update(f)
# 更新集合元素为差集结果
d.difference_update(f)
# 更新集合元素为对称差集结果
d.symmetric_difference_update(f)

# 删除一个元素,如果没有则抛异常
d.remove(7)
# 删除一个元素,如果没有不抛异常
d.discard(7)
# 随机返回并删除一个元素
d.pop()
# 清空所有元素
d.clear()

s1 = {1, 2, 3, 5}
s2 = {1, 2, 6, 7}
s3 = s1 & s2
s4 = s1 | s2

字典

Python3.7后字典中的键值对是有序的

字典中的键必须是不可变、可哈希的,字符串类型、数字类型均可作为字典的键

# 创建字典
a = {}
a = {"k1": "v1", "k2": "v2"}
a = dict(k1 = "v1", k2 = "v2")

# 访问字典
a["k1"]
a.get("k1")
# 不存在时返回默认值
a.get("k3", "v3")

# 增加字典值或修改字典值
a["k3"] = "v3"
a["k2"] = "v2"

# 批量修改字典值
a.update({"k1": "v11", "k2": "v22"})
a.update(k1 = "v11", k2 = "v22")

# 有则返回旧值,无则设置并返回新值
a.setdefault("k4", "v4")

# 初始化值一样的字典
keylist = ["k1", "k2"]
dict.fromkeys(keylist, "v1")

# 返回并删除,不存在对应的key则抛异常
a.pop("k1")
# 返回并删除,不存在对应的key则返回默认值
a.pop("k1", "v1")
# 返回键值对元组并删除,如字典有序则返回并删除的是最后一个键值对,否则随机一个
a.popitem()

# 删除
del a["k1"]

# 清空字典元素
a.clear()

# 视图对象,字典改变时,视图对象会跟随改变
# 返回键值对视图对象,视图对象可转为列表
a.items()
# 返回键视图对象
a.keys()
# 返回值视图对象
a.values()

# 浅拷贝
a.copy()

# 获取键值对数量
len(a)

# 判断键是否存在
"k1" in a
"k1" not in a

# 生成迭代器
iterator = iter(a)
# 迭代键
next(iterator)

# 嵌套字典
b = {"k1": {"k11": "v11"}, "k2": {"k22": "v22"}}
b["k1"]["k11"]

# 字典推导式
d = {x: ord(x) for x in "abc"}

检测数据类型

# 检测数据类型,基础数据类型也是一个对象
a = "123"
b = 123

type(a)
# <class 'str>'
type(a) is str
# True

type(b)
# <class 'int>'

# 判断对象是否是某类的实例
isinstance(b, int)
isinstance(b, (int, float, str))

class C:
    pass
# 获取对象对应的类型
c.__class__
# 获取类型对应的父类类型
C.__bases__

数据类型转换

使用各类型的构造器来作转换

# 整数转字符串
a = 123
str(a)

# 整数转代码形式字符串
repr(123)

# 整数转布尔值
bool(a)
# True
bool(0)
# False

# 字符串转整数
b = "123"
int(b)

# 字符串转浮点数
float(b)
float("+1E6")

# 字符串转布尔值
bool(b)
# True
bool("")
# False

# 字符串转复数
complex("1+2j")

# 字符串转列表
list(b)
# 字符串转元组
tuple(b)
# 字符串转集合
set(b)

# 列表转字典,列表里的元素可以是列表或元组
dict([["name", "Tom"], ["age", "18"]])
# 元组转字典,元组里的元素可以是列表或元组
dict((["name", "Tom"], ["age", "18"]))

# 浮点数转整数,截掉小数部分
int(9.99)
# 9

类型注解

# 变量
a: int = 10
b: list[int] = [1, 2, 3]
c: tuple[str, int, bool] = ("a", 1, True)
d: dict[str, int]  {"a": 1}
stu: Student = Student()

# 函数
def add(x: int, y: int) -> int:
    return x + y

from typing import Union
a: list[Union[str, int]] = [1, "a"]

运算

算术运算

# 除法
2 / 4 
# 0.5

# 除法,结果向下取值
2 // 4 
# 0

# 幂运算
2 ** 3 
pow(2. 3)
# 8

# 幂运算后求模
pow(2, 3, 5)
# 3

# 求模
3 % 2 
# 1

# 除法,结果向下取值与求模
divmod(3, 2)
# (1, 1)

# 绝对值或求复数的模
abs(-10)
# 10

布尔运算

# 与
True and True
# True
3 and 4
# 4

# 或
False or False
# False
3 or 4
# 3

# 非
not True

同一性运算符

判断两个变量是否为同一对象,即对象的ID是否相等

x = "s" 
y = "s"

# 获取对象的ID
id(x)
id(y)

x is y
# True
x is not y
# False

x = [1, 2, 3]
y = [1, 2, 3]
x is y
# False

# 判断是否为空对象
x is None

位运算

# 按位与
3 & 2
# 按位或
3 | 2
# 按位取反
~2
# 按位异或
3 ^ 2
# 左移
8 << 2
# 算术右移,补符号位
8 >> 2

语句结构

条件语句

if a > 0:
    print("large")
elif a == 0:
    print("small")
else:
    print("zero")

# 条件表达式
print("小于10") if age < 10 else print("大于等于10”)
small = a if a < b else b

循环语句

a = 0
while a < 5:
    print(a)
    a += 1
else:
    # 正常循环结束时调用,假如使用break跳出循环,这里将不会被执行
    print("out")

# 跳出循环体
a = 0
while True:
    print(a)
    a += 1
    if a > 5:
        break

# 跳出本轮循环
a = 0  
while a < 5:  
    if a % 2 == 1:  
        a += 1  
        continue  
    print(a)  
    a += 1

# 遍历一个列表
for i in [1, 2, 3]:
    print(i)

# 遍历一个整数序列,包前不包后
for i in range(0, 10):
    # pass为空语句,不干任何事情
    pass

# 省略第一个参数,第一个参数默认为0
for i in range(10):
    psss

# 支持步进
for i in range(10, 5, -2):
    pass

# 遍历字符串里面的每一个字符,每一个字符以字符串的形式
for i in "fish":
    print(i)

# 遍历列表,同时遍历内容和索引
for index, item in enumerate(item_list):  
    print(index)
    print(item)

函数

函数基本使用

# 定义函数
def printSometing():
    print("something")

# 调用函数
# 没有返回值的函数,默认返回值为`None`
printSomething()

# 带位置参数和返回值的函数
def sum(a, b):
    print(a + b)
    return a + b

# 传入位置参数
sum(1, 2)
# 传入关键字参数
sum(b = 2, a = 1)
# 位置参数和关键字参数混用时,位置参数要在关键字参数前面
sum(1, b = 2)

# 将元组或列表解包成位置参数传入
l = [1,2]
sum(*l)
# 将字典解包成关键字参数传入
d = {"a": 1, "b": 2}
sum(**d)

# 使用默认参数,默认参数后面必须都是默认参数,默认值应该为不可变对象
def sum(a = 3, b = 5):
    print(a + b)

# 指定参数中必须使用位置参数的参数,斜杠前的参数必须使用位置参数
def sum(a, /, b):
    return a + b
# 指定参数中必须使用关键字参数的参数,星号后的参数必须使用关键字参数
def sum(a, *, b):
    return a + b

# 收集参数,实际参数是一个元组
def myfunc(*args):
    print(args)

myfunc(1, 2)

# 收集参数后面只能使用关键字参数
def myfunc(*args, b, c):
    print(args, b, c)

myfunc(1, 2, 3, b = 4, c = 5)

# 多返回值,实际使用元组打包
def myfunc():
    return 1, 2, 3

x, y, z = myfunc()

# 字典收集参数
def myfunc(**kwargs):
    print(kwargs)

myfunc(a = 1, b = 2, c = 3)

# 混用位置参数和收集参数
def printAll(a, *args):
    print(a)
    print(args)

abc(100, 200, 300)

# 混用位置参数和字典收集参数
def printAll(a, **kwargs):
    print(a)
    print(b)

abc(100, x = 200, y = 300)

# 混合使用
def printAll(a, b = "b", *args, **kwargs):
    print(a)
    print(b)
    for i in args:
        print i
    for key, value in kwargs.items():
        print(key)
        print(value)

c = (1, 2, 3)
d = {
    "name": "Tom",
    "age": 18
}

printAll("a", "b" *c, **d)

# 函数作为参数
def calculator(compute):
    return compute(1, 2)
def sum(x, y):
    return x + y

calculator(sum)

函数嵌套

def funa():
    x = 1
    def funb():
        x = 2
        print(x)
    funb()
    print(x)

funa()

# 返回嵌套函数
def getFunction():
    def f():
        return 1
    return f

f = getFunction()
f()

变量作用域

优先级 local > enclosing > global > built-in

# 全局变量
y = 1

def myfunc():
    # 局部变量,作用域在函数内
    x = 1
    print(x)

    # 当前作用域找不到的变量,往上层作用域找,这里访问全局变量
    print(y)

    # 定义一个与全局变量同名的局部变量,后续只会访问局部变量
    y = 2
    print(y)

    def myfuncinner():
        # 声明使用上层函数的局部变量
        nonlocal x
        x = 3

    myfuncinner()
    print(x)


def myfunc2():
    # 声明使用全局变量
    global y
    y = 2
    print(y)

# 闭包变量可修改
def outer():
    x = 0
    y = 0
    def inner(x1, y1):
        nonlocal x, y
        x += x1
        y += y1
        print(x, y)
    return inner

move = outer()
move(1, 2)

lamda表达式

# 定义lamda表达式
square = lambda x : x * x

# 作为一个函数参数
mapped = map(lambda x : ord(x) + 10, "abc")

生成器

def fib():
    back1, back2 = 0, 1
    while back1 < 1000:
        yield back1
        back1, back2 = back2, back1 + back2

generator = fib()

# 生成一个值
next(generator)

# 遍历生成的剩余所有值
for i in generator:
    print(i)

# 生成器表达式
generator = (i ** 2 for i in range(10))

函数文档

# 定义函数文档
def fun():
    """
    打印abc
    """
    print("abc")

# 查看函数文档
help(fun)

类型注释

# 冒号后面加上参数的建议类型,->后面为返回值的预期类型
def times(s:str, n:int) -> str:
    return s * n

# 序列或字典中的类型在中括号里面
def times(s:list[int], n:int) -> list[int]:
    return s * n

自省

def times(s:str, n:int) -> str:
     """
    字符串重复
    """
    return s * n

# 获取函数名称
times.__name__
# 获取函数的类型注释
times.__annotations__
# 获取函数文档
times.__doc__

偏函数

固定某一个函数的某参数值,生成新的函数

import functools
square = functools.partial(pow, exp = 2)

square(3)

文件操作

文件读写

# 写模式打开文件,文件不存在则创建,文件存在则原内容会丢失
f = open("C:/Oliver/test.txt", "w", encoding="UTF-8")
f.write("hello")
# 不会自动添加换行符
f.writelines(["hello\n", "hello\n"])
f.flush()
f.close()

# 更新模式打开文件,可读取且可写入
f = open("C:/Oliver/test.txt", "r+", encoding="UTF-8")
f.readable()
# True
f.writeable()
# True

# 文件当前指针的位置
f.tell()
# 重置文件指针的位置
f.seek(0)
# 截取文件内容,范围默认是从起始位置到当前文件指针的位置
f.truncate()
# 指定截取的结束位置
f.truncate(5)

# 读模式打开文件
f = open("C:/Oliver/test.txt", "r", encoding="UTF-8")
# 读取剩余所有字符,直到EOF
f.read()
# 读取指定字符数
f.read(5)
# 读取一行字符串
f.readline()

# 逐行遍历读取文件
for line in f:
    print(line)

# with文件上下文管理,文件使用完后自动关闭,且保证抛异常的时候会关闭
with open("C:/Oliver/test.txt", "r", encoding="UTF-8") as f:
    pass

os

# 生成路径
import os.path

VIDEO_ORIGIN_UPLOAD_PATH = 'C:/traffic/origin/'
save_file_name = 'test.mp4'

update_path = os.path.join(common_config.VIDEO_ORIGIN_UPLOAD_PATH, save_file_name)

# 获取文件大小
size = os.path.getsize(update_path)

# 删除文件
os.remove(update_path)

pathlib

from pathlib import Path
# 获取当前的工作目录
Path.cwd()

# 创建一个路径
p = Path("C:/Oliver")
# 路径拼接
p = p / "test.text"

# 判断路径是否存在
p.exists()
# 判断是否为一个文件夹
p.is_dir()
# 判断是否为一个文件
p.is_file()

# 获取路径最后一部分,即文件名或文件夹名
p.name
# 获取文件名,不包括后缀名
p.stem
# 获取后缀名
p.suffix

# 获取父级路径
p.parent
# 获取所有祖先目录路径
ps = p.parents
# 遍历所有祖先目录路径
for each in ps:
    print(each)
# 使用索引访问
ps[0]

# 拆分路径各部分,使用斜杠作为分割符
p.parts

# 获取路径信息
p.stat()

# 相对路径转绝对路径
p = Path("./doc")
p.resolve()

# 获取当前文件夹下所有文件或文件夹的迭代器
iterator = p.iterdir()
for each in iterator:
    print(each)

# 创建文件夹
p.mkdir()
# 文件夹存在不抛异常,创建不存在的父级文件夹
p.mkdir(exist_ok = True, parents = True)

# 打开文件
p = Path("C:/Oliver/test.txt")
f = p.open("w")

# 重命名,类似剪切粘贴
p.rename("C:/Oliver/test1.txt")
# 替换,类似剪切粘贴
p = Path("C:/Oliver/test.txt")
q = Path("C:/Oliver/test1.txt")
p.replace(q)

# 删除文件
p.unlink()
# 删除文件夹,文件夹不为空则抛异常
p = Path("C:/Oliver")
p.rmdir()

# 查找
p.glob("*.py")
p.glob("*/*.py")
# 任意层级子文件夹下查询
p.glob("**/*.py")

pickle

对象序列化保存到一个文件,再从文件反序列化

x = 1
s = "abc"
l = [3, 4, 5]
with open("C:/Oliver/test.pkl", "wb", encoding="UTF-8") as f:
    pickle.dump(x, f)
    pickle.dump((s, l), f)

with open("C:/Oliver/test.pkl", "rb", encoding="UTF-8") as f:
    # 按存的顺序读取出来
    x = pickle.load(f)
    s = pickle.load(f)
    l = pickle.load(f)

异常

异常处理

# 捕获所有异常
try:
    1 / 0
except:
    print("error")

# 捕获指定异常
try:
    1 / 0
except ZeroDivisionError:
    print("error")

# 捕获指定的多种异常
try:
    1 / 0
except (ZeroDivisionError, TypeError):
    print("error")
except (ValueError):
    print("another error)
        
# 定义没有捕获到异常时的处理,和离开try块时的处理
try:
    f = open("C:/Oliver/no.txt", "r", encoding="UTF-8")
except Exception as e:
    f = open("C:/Oliver/no.txt", "w", encoding="UTF-8")
else:
    pass
finally:
    f.close()

异常处理嵌套

try:
    try:
        1 / 0
    except:
        print("error1")
    1 / 0
except:
    print("error2)

主动抛出异常

raise
# 指定抛出的异常类型
raise ValueError("error")

# 异常链
try:
    1 / 0
except ZeroDivisionError:
    raise ValueError("error") from ZeroDivisionError

断言

调试时使用,断言不成立时,抛出AssertionError

s = "abc"
assert s == "abc"

面向对象

封装

# 定义一个类
class Student:
    # 定义类属性,实例没有定义对应的同名属性会访问到这里
    name = None
    age = 0
    # 定义类私有属性,实例没有对应的同名属性会访问到这里
    __private_attribute = None
    
    # 第一个参数必须是self,指的是当前对象
    # 对象初始化函数
    def __init__(self, name, age, private_attribute):
        self.name = name
        self.age = age
        # __开头的属性在外部无法被直接调用,此属性外部名字改成_Student__private_attribute
        # 对象构造完成后,无法再增加一个私有属性
        self.__private_attribute = private_attribute

    # 定义实例方法
    def print_name(self):
        print self.name
    
    # __开头的函数在外部无法被直接调用,此函数外部名字改成_Student__private_method
    def __private_method(self):
        pass
    
# 创建一个对象
student = Student()
# 定义对象的属性
student.name = "Tom"
student.age = 18
# 增加对象的属性
student.height = 180
# 调用对象的方法
student.print_name()

# 查询对象的属性
student.__dict__
class Student:
        # 限制该类的对象的属性,可降低内存占用量。子类对象的属性不会受父类的__slots__定义限制
    __slots__ = ["name", "age"]
    def __init__(self, name, age):
        self.name = name
        self.age = age

继承

# 继承的父类写在括号里
class SubStudent(Student):
    sex = None

    # super() 依赖MRO顺序,在钻石继承时调用自动去重
    def __init__(self, name, age, sex):
        super().__init__(name, age)
        self.sex = sex

    # 重写父类方法
    def printName(self):
        Student.printName(self)
        super().printName()
        print("Hello")

# 判断是否是某个类的子类
issubclass(SubStudent, Student)

# 多重继承,当多个父类有相同名称的属性和方法时,左边的父类优先
class A:
    x = 1
    def hello(self):
        print("A")

class B:
    x = 2
    def hello(self):
        print("B")

class C(A, B):
    pass

# 查询MRO,继承关系中查找属性或方法的顺序
C.mro()
C.__mro__

多态

不需要继承的支持,不需要检查类型

class A:
    x = 1
    def hello(self):
        print("A")

class B:
    x = 2
    def hello(self):
        print("B")

def sayHello(obj):
    obj.hello()

a = A()
b = B()

sayHello(a)
sayHello(b)

方法解析顺序

方法解析顺序(Method Resolution Order,MRO)通过继承关系确定,子类在顺序的前面,父类在顺序的后面。假如同一层级多继承,则先声明的在前面。

直接通过对象引用调用方法时,使用该对象对应类型的MRO,从头开始往后找,调用找到的第一个方法

通过super()调用方法时,使用self对象对应类型的MRO,从当前代码所在的类开始往后找,调用找到的第一个方法

class Displayer:
    def display(self, message):
        # 3.打印"abc"
        print(message)

class LoggerMixin
    def log(self, message, filename = "logfile.txt"):
        # 6.self参数是subclass,message参数是"abc",filename参数是"subclasslog.txt"
        # 打开subclasslog.txt文件,写入"abc"
        with open(filename, "a") as f:
            f.write(message)
    
    def display(self, message):
        # 2.self参数是subclass,message参数是"abc"
        # super()根据self的类型MySubClass的MRO,再根据LoggerMixin往后找,找到Displayer的display方法
        super().display(message)
        # 4.self参数是subclass,根据MySubClass类的MRO,调用MySubClass重写的log方法
        self.log(message)

class MySubClass(LoggerMixin, Displayer):
    def log(self, message):
        # 5.self参数是subclass,message参数是"abc"
        # uper()根据self的类型MySubClass的MRO,再根据MySubClass往后找,找到LoggerMixin的log方法
        super().log(message, filename = "subclasslog.txt")

subclass = MySubClass()
# 1.根据MySubClass类的MRO,找到LoggerMixin的display方法
subclass.display("abc")

组合

class Bird:
    def sayHello(self):
        print("bird")

class Cat:
    def sayHello(self):
        print("cat")

class Dog:
    def sayHello(self):
        print("dog")

class Garden:
    bird = Bird()
    cat = Cat()
    dog = Dog()

    def sayHello(self):
        self.bird.sayHello()
        self.cat.sayHello()
        self.dog.sayHello()

魔法方法

class CapStr(str):
    # 创建对象,在__init__之前被调用
    def __new__(cls, string):
        string = string.upper()
        return super().__new__(cls, string)

class C:
    # 初始化方法
    def __init__(self, x):
        print("init")
        self.x = x
    # 对象被垃圾回收前被调用的方法
    def __del__(self):
        print("del")

    # +运算符方法重写
    def __add__(self, other):
        return self.x + other.x

    # +=运算符方法重写
    def __iadd__(self, other):
        # 不实现
        return NotImplemented

    # 属性被访问时调用的方法重写
    def __getattribute__(self, attrname):
        print("exist")
        return super().__getattribute__(attrname)

    # 对象不存在的属性被访问时调用的方法重写
    def __getattr__(self, attrname):
        print("not exist")
    # 属性被设置时调用的方法重写
    def __setattr__(self, name, value):
        self.__dict__[name] = value
    # 属性被删除时调用的方法重写
    def __delattr__(self, name):
        del self.__dict__[name]

    # 对象使用[]获取值时调用的方法重写
    def __getitem__(self, index):
        return NotImplemented
    # 对象使用[]设置值时调用的方法重写
    def __setitem__(self, index):
        return NotImplemented

    # 对象被使用for in迭代时被调用的方法重写,未定义时使用__getitem__代偿
    def __iter__(self):
        return NotImplemented
    def __next__(self):
        return NotImplemented

    # 对象被调用in或not in时被调用的方法重写,未定义时使用__iter__和__next__代偿
    def __contains__(self, item):
        return NotImplemented

    # 对象作为参数被调用bool()时被调用的方法重写,未定义时使用__len__代偿
    def __bool__(self):
        return True

    # 对象比较时被调用的方法重写
    def __lt__(self, other):
        return self.x < other.x
    def __le__(self, other):
        return self.x <= other.x
    def __gt__(self, other):
        return self.x > other.x
    def __ge__(self, other):
        return self.x >= other.x
    def __eq__(self, other):
        return self.x == other.x
    def __ne__(self, other):
        return self.x != other.x            

    # 直接使用()调用对象时,被调用的方法重写
    def __call__(self):
        print("call")
    # 带参数
    def __call__(self, *args, **kwargs):
        print("call")

    # 对象作为参数被调用str()时被调用的方法重写,未定义时使用__repr__代偿
    def __str__(self):
        return str(self.x)

    # 对象作为参数被调用repr()时被调用的方法重写
    def __repr__(self):
        return repr(self.x)

属性代理

# x代理_x
class C:
    def __init__(self):
        self._x = 1
    def getx(self):
        return self._x
    def setx(self, value):
        self._x = value
    def delx(self):
        del self._x
    x = property(getx, setx, delx)

c = C()
print(c.x)
c.x = 2
del c.x

# 装饰器写法
class E:
    def __init__(self):
        self._x = 1
    @property
    def x(self):
        return self._x
    @x.setter
    def x(self, value):
        self._x = value
    @x.deleter
    def x(self):
        del self._x

类方法

class C:
    count = 0
    @classmethod
    def get_count(cls):
        print(cls.count)

c = C()
c.get_count()

静态方法

class C:
    count = 0
    @staticmethod
    def get_count():
        print(C.count)

c = C()
c.get_count()

动态创建类

C = type("C", (), {})
c = C()

# 增加继承
D = type("D", (C,) {})
d = D()

# 增加属性和方法
def fun(self):
    pass
E = type("E", (), {x = 1, y = 2, fun = fun})

# 增加给__init_subclass__方法的参数
F = type("F", (), {x = 1, y = 2, fun = fun}, value1 = 1, value2 = 2)

子类初始化方法

class C:
    # 子类初始化时调用,cls后面的参数可选
    def __init_subclass__(cls, value1, value2):
        print("abc")
class D(C, value1 = 1, value2 = 2):
    pass

d = D()
# abc

元类

元类与类的关系,类似类与对象的关系

# 元类继承type
class MetaC(type):
    # 在类创建时执行
    def __new__(mcls, name, bases, attrs):
        # 增加一个对象
        attrs["x"] = 1
        return type.__new__(mcls, name, bases, attrs)
    
    # 在类初始化时执行
    def __init__(cls, name, bases, attrs):
        if not name.istitle():
            raise TypeError("error")
        type.__init__(cls, name, bases, attrs)

    # 在类的构造方法被调用时执行
    def __call__(cls, *args, **kwargs):
        new_args = [each.upper() for each in args if isinstance(each, str)]
        return type.__call__(cls, *new_args, **kwargs)

class C(metaclass = MetaC):
    pass

# 单例
class SingleInstance(type):
    def __init__(cls, *args, **kwargs):
        cls.__instance = None
        type.__init__(cls, *args, **kwargs)
    def __call__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = type.__call__(cls, *args, **kwargs)
        return cls.__instance

class Cat(metaclass=SingleInstance):
    pass

查看对象定义列表

# 查看当前模块的定义,变量、函数、类
dir()
# 增加对象参数
dir(c)

抽象基类

from abc import ABCMeta, abstractmethod
class Animal(metaclass = ABCMeta):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @abstractmethod
    def say(self):
        pass

class Cat(Animal):
    def say(self):
        print("cat")

class Dog(Animal):
    def say(self):
        print("dog")

c = Cat()
d = Dog()

def animal_say(animal):
    animal.say()

animal_say(c)
animal_say(d)

描述符

实现了__set__delete__方法的称为数据描述符,只实现__get__方法的称为非数据描述符

访问数据时,优先级为数据描述符 > 实例对象属性 > 非数据描述符 > 类属性

# 定义描述符,需实现__get__,__set__,__delete__三个方法
class D:
    def __get__(self, instance, owner):
        return instance._x
    def __set__(self, instance, value):
        instance._x = value
    def __delete__(self, instance):
        del instance._x

class C:
    def __init__(self, x):
        self._x = x
    # 使用D描述符去管理属性x,描述符只能用在类属性
    x = D()

c = C(1)
print(c.x)
c.x = 2
del c.x
# Python3.6以后增加__set_name__方法
class D:
    def __set_name__(self, owner, name):
        self.name = name
    def __get__(self, instance, owner):
        return instance.__dict__.get(self.name)
    def __set__(self, instance, value):
        instance._dict__[self.name] = value

class C:
    # 使用D描述符去管理属性x,属性x的名称传递到__set_name__方法
    x = D()

装饰器

函数作为函数的装饰器

def add(func):
    def inner():
        x = func()
        return x + 1
    return inner

def cube(func):
    def inner():
        x = func()
        return x * x * x
    return inner

def square(func):
    def inner():
        x = func()
        return x * x
    return inner

# 靠近方法定义的装饰器先生效
@add
@cube
@square
def test():
    return 2

test()
# 相当于
add(cube(square(test)))()


# 原方法接收参数
def subtract(func):
    def inner(*args, **kwargs):
        x = func(*args, **kwargs)
        return x - 1
    return inner

@subtract
def test(number):
    return number


# 带参数的装饰器
import time

def logger(msg):
    def time_master(func):
        def call_func():
            start = time.time()
            func()
            stop = time.time()
            print(f"[{msg}]-{(stop-start):.2f}")
        return call_func
    return time_master

@logger(msg = "A")
def funA():
    time.sleep(1)
    print("AAA")

# 防止装饰器改变函数的名称
import time
import functools

def time_master(func):
    @functools.wraps(func)
    def call_func():
        start = time.time()
        func()
        stop = time.time()
        print(f"{(stop - start):.2f}")
    return call_func

@time_master
def myfunc():
    print("a")

myfunc.__name__
# myfunc

函数作为类的装饰器

def report(cls):
    def oncall(*args, **kwargs):
        # 实例化前后做操作
        print("1")
        _ = cls(*args, **kwargs)
        print("2")
        return _
    return oncall

@report
class C:
    pass

c = C(1, 2, 3)
# 相当于
report(C)(1,2,3)

类作为函数的装饰器

class Counter:
    def __init__(self, func):
        self.count = 0
        self.func = func
    def __call__(self, *args, **kwargs):
        self.count += 1
        print(self.count)
        return self.func(*args, **kwargs)

@Counter
def say_hi():
    print("hi")

say_hi()
# 相当于
Counter(say_hi)()

模块和包

模块

一个py文件可看作为一个模块,一个模块被引入时,相当于整个模块执行一遍

hello.py

# 控制 from hello import * 导入的内容
__all__ = ["say_hello", "say_hi"]

def say_hello():
    print("hello")

def say_hi():
    print("hi")

def say_what():
    print("what")

class Cat:
    pass

if __name__ == "__main__":
    # 被引入时,此处不执行
    # 只有在本模块作为入口被独立运行时,__name__的值是__main__,否则__name__的值是模块名,如hello。引入时带包,则前面加上包名,如util.hello
    print("abc")

引入整个模块

import hello

hello.say_hello()
hello.say_hi()
hello.say_what()

cat = hello.Cat()

引入整个模块并加上别名

import hello as h

h.say_hello()
h.say_hi()
h.say_what()

cat = h.Cat()

引入模块中的对象或类

from hello import say_hello, say_hi, Cat

say_hello()
say_hi()

cat = Cat()

引入模块中的全部对象,受__all__属性限制。引入的对象名有冲突时,后引入的优先级高

from hello import *

say_hello()
say_hi()

一个包含__init__.py文件和其它模块py文件的文件夹,可看作为一个包,Python3.3以及之前的版本,__init__.py文件是必须的

包文件夹中可以包含子文件夹作为子包,子包不需要__init__.py文件

util/hello.py

def say_hello():
    print("hello")

def say_hi():
    print("hi")

def say_what():
    print("what")

class Cat:
    pass

# 被引入时,此处不执行
# 只有在本模块被独立运行时,__name__的值是__main__,否则__name__的值是模块名
if __name__ == "__main__":
    print("abc")

util/__init__.py

# 包被引入时执行
print("util")

引入包中的某个模块

test.py

import util.hello

util.hello.say_hello()
util.hello.say_hi()
util.hello.say_what()

cat = util.hello.Cat()

引入包中某些模块,如使用*,则受__init__.py中的__all__属性限制

util/__init__.py

# 控制 from util import * 引入的模块
__all__ = ["hello"]

test.py

from util import hello

hello.say_hello()
hello.say_hi()
hello.say_what()

cat = hello.Cat()

test.py

from util import *

hello.say_hello()
hello.say_hi()
hello.say_what()

cat = hello.Cat()

引入包中某模块的某些类和对象

test.py

from util.hello import Cat, say_hello

say_hello()
cat = Cat()

省略模块

util/__init__.py

from .hello import Cat  
from .hello import say_hello

test.py

from util import Cat, say_hello

say_hello()
cat = Cat()

类库

随机数

import random
# 1到10之间随机生成一个整数,前后包含
random.randint(1, 10)

拷贝

import copy
# 浅拷贝
x = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
y = copy.copy(x)

# 深拷贝
z = copy.deepcopy(x)

reduce

import functools
functools.reduce(lambda x, y : x + y, [1, 2, 3 , 4, 5])

JSON

import json
string = json.dumps(data, ensure_ascii = False)
dictionary = json.loads(data)