搭建环境
下载anaconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/?C=M&O=D
安装:https://blog.csdn.net/HowieXue/article/details/118442904
基础语法
查看内置关键字:
import builtins
print(dir(builtins))
输出:print(*objects,sep='',end='\n',file=sys.stdout,flush=False)
with open("./abc.txt",'w') as f:
print(12345,file=f) #把12345直接写入abc.txt文件
print('hello','peter',sep='-and-',end="--end")
#hello-and-peter--end
for i in range(10):
print('.',end='',flush=True)
time.sleep(0.3)
输入:input([prompt])
name = input("input ur name:")
print(name,"nice to meet u",sep=',')
#返回的是字符串
str = input("input nums like 1,2,3").split(',')
标准数据类型
- 数字(Number): 不可变, 非序列
int([x],base=10)
complex([real[,imag]])
- 字符串(String): 不可变, 是序列
- 单行字符串
- 多行字符串: 一对三引号定义
- Raw原始字符串: 取消转义.
print(r"http:\\google.com\n")
其中的"\" "\n"不进行转义 - 字符串格式化_%: %s, %d, %f, %e, %c, %o, %x, %g
print("%s,%d,%f" % ("str",123,1.23))
- 字符串格式化_format:
{name}.format(name=" ")
- 字符串格式化_f-string:
print(f"{name}")
- 字符串类方法: replace, endswith, split, join(iterable), find, …
- 列表(List): 可变,是序列
- list([iterable])
- 对象方法: append(单元素), expend(iterable), sort, sorted(iterable,[fun],reverse=False), reverse
- 元组(Tuple): 不可变, 序列
- 括号可加可不加
- tuple不可变,但其中的列表是可变的
- 元组对象方法: count(x), index
- 字典(Dictionary): 可变,不是序列
- 键和值都为不可变类型
- {}创建空字典
- 字典的迭代只返回 键
- 方法: keys, values, 注意
list(d.keys())
, get(key,default=None), update([other]) - 遍历方式
dic = {'a':123,'b':23,'c':56}
total = 0
#方式1
for k in dic: #默认遍历键
v = dic[k]
if type(v) in (int,float,bool,complex): #判断是否为数值类型
total += v #累加
print(total)
#方式2
for k,v in dic.items():
k,v
- 集合(Set): 可变, 非序列
- 无序,不重复
- 元素必须为不可变类型
- frozenset 不可变的set
- 集合的符号运算: 包含于<=, 差集-, 并集|, 交集&, 外集^
- 方法: issubset, issuperset, union, intersection, difference, symmetric_difference, add, discard
- 序列的索引和切片:
- 切片: [起始索引: 结束索引: 步长]
- 若步长为负,则从后面开始切片,索引依次做减法. [::-1]
- 索引会降维,切片不会降维
- del 语句
- del 删除变量时,不直接删除数据,而是解除变量对数据的引用,当数据引用计数为0时,则系统回收他.
a = [1,2,3,4]
del a[0]
print(a) #[2,3,4]
赋值&拷贝
- 赋值:
- id(object): 返回object的唯一标识符(内存地址)
- 当执行
a=99
时,内存先开辟空间存放99,然后定义变量名a来指定这个空间的内存地址. python中的赋值语句不复制对象,只是建立引用关联. - 小整数对象池: 为优化速度,范围在[-5,256]之间的数字是预存的
- 一个值可以被多个变量名引用,当变量值的引用计数为0时便会被回收.
- 当一个可变类型的数据被多个变量名引用时,如果对该原数据进行修改,那么它的所有引用都会改变
- 浅拷贝
- 浅层拷贝只考虑最外层的数据类型
- 如果最外层的数据类型是可变的(比如列表),则(最外层)发生拷贝
- 如果最外层的数据类型是不可变的(比如元组),则不发生拷贝
- 深拷贝
- 如果判断的该数据本身不可变,且包含的所有数据都不可变,则该数据不发生拷贝
- 如果判断的该数据本身可变,或者包含的数据存在可变,则该数据(可变的数据)发生拷贝
运算符
- 算数运算符: +, -, *, /, %, **幂, //向下取整
- 比较运算符
- 赋值运算符:
- 海象赋值运算符’:=’ 可在表达式内部为变量赋值
- 增强赋值: 如可变类型的追加赋值+=
- 序列赋值: a,b = 3,4
- 多目标赋值: a = b = c = [1,2,3]
- 逻辑运算符: 优先级: not > and > or
all(iterable)
:如果iterable的所有元素全为真值或iterable为空则返回Trueany(iterable)
:任一元素为真则True, 若可迭代对象为空,则返回False如any([False,None,0])
- 短路原则: 如果前面的部分已经计算出整个表达式的结果,则后面的部分不再计算.
- 成员运算符: in, not in, 判断对象中是否存在某个元素
- 身份运算符: is, is not, 判断两个标识符是不是引用同个或不同对象 如
id(a)==id(b)
- 位运算符
- 运算符优先级
- 连接操作 : 可以对字符串,列表,元组进行连接操作
- +: 合并成新序列
- +=: 原地合并
- *n: 重复n次
条件,循环,推导式
- 三元表达式:
True值 if 条件 else False值
- while … else … : while执行完毕执行else,注意在break后else不执行
count = 0
while count<10:
count+=1
if(count>5):
break #若break执行则else语句不执行
pass
print(count)
else:
print('count>10')
- 确定次数用for循环,不确定次数则使用while循环
- for循环:
- for 变量 in 可迭代对象(或迭代器):
- 遍历获取元素:
for i in list
- 遍历获取索引:
range(len(list))
- 遍历获取元素和索引(枚举)
enumerate(iterable,start=0)
: 将索引和元素组成一个元组,返回的是迭代器。注意用list迭代第二次会出来空列表。 - 循环确定次数:
for _ in range(num)
- 遍历获取元素:
- for … in … else: else后的东西在for循环结束后执行 若当中break则不执行
- 注意for循环中不可以用来删除元素或添加元素,不能改变列表大小
- for 变量 in 可迭代对象(或迭代器):
list1 = [1,2,3,4]
new_list = list1.copy() #list1[:],list(list1)
for i in new_list:
list1.remove(i)
- 字典和集合遍历删除问题:
d = {'name':'Tony','age':28,'height':180}
for k in d:
print(d.pop(k))
print(d)
#一定要保证在迭代期间,字典和集合的size不变,不然则报错
new_d = d.copy()
#d.[:]不可以, d.keys()不可以视图同原字典改变, list(d)获取新的键列表
for k in new_d:
print(d.pop(k))
- 推导式
- 列表推导式
- [ 含参表达式 for 子句 其他多个for子句或if子句]
- 嵌套列表推导式: [ [列表推导式] for 子句 其他多个for子句或if子句]
- 列表推导式
list1 = [i**2 for i in range(6) if i%2]
print(list1)
#全等于
list2 = []
for i in range(6):
if i%2: #当为奇数时
list2.append(i**2)
print(list2)
'''
[1, 9, 25]
[1, 9, 25]
'''
#嵌套列表
mat = [ [1,2,3,4],
[5,6,7,8],
[9,10,11,12] ]
print(mat)
#不利用推导式进行转置
res=[]
for index in range(len(mat[0])):
list1=[]
for i in mat:
list1.append(i[index])
res.append(list1)
print(res)
#利用推导式进行转置
#根据上面对比一下
res1 = [[i[index] for i in mat] for index in range(len(mat[0]))]
print(res1)
- 字典推导式
{k: v for 子句 其他多个for子句或if子句}
- 注意键不能重复,重复则覆盖最后一个值
dic = {x:y for x in range(6) for y in range(7,9)}
print(dic)
'''
{0: 8, 1: 8, 2: 8, 3: 8, 4: 8, 5: 8}
'''
- 集合推导式:
- 注意重复项
- 不能嵌套,因为不能添加可变元素
s = {i+j for x in range(4,0,-1) for y in range(4)}
print(s)
'''
{1, 2, 3, 4, 5, 6, 7}
'''
函数
- 函数文档注释和帮助
- 在函数中写入详细描述注释 以 三个单双引号对 括起来
- 可以使用函数的
__doc__
属性和内置函数help([object])
打印查看
def my_abs(x):
"""Return the absolute value of the argument."""
return x if x > 0 else -x
# 文档注释存放在 __doc__ 属性中
print(my_abs.__doc__)
print()
help(my_abs)
'''
Return the absolute value of the argument.
Help on function my_abs in module __main__:
my_abs(x)
Return the absolute value of the argument.
'''
- 类型标注
- 参数内标注 以冒号+类型表达,函数的返回值标注,以
->
类型 表达 - 标注以字典的形式存放在函数的
__annotations
属性中 - 函数作为参数的类型标注为
Callable[[函数参数], 返回类型]
- 参数内标注 以冒号+类型表达,函数的返回值标注,以
def func(a: int, b: str, c: list, d: tuple, e: dict, f:
set) -> tuple:
return a, b, c, d, e, f
print(func(1, 2, 3, 4, 5, 6))
print(func(1, "2", [3], (4, ), {5: 5}, {6}))
print(func.__annotations__)
'''
(1, 2, 3, 4, 5, 6)
(1, '2', [3], (4,), {5: 5}, {6})
{'a': <class 'int'>, 'b': <class 'str'>, 'c': <class 'list'>, 'd': <class 'tuple'>, 'e': <class 'dict'>, 'f': <class 'set'>, 'return': <class 'tuple'>}
'''
#多种类型
def func(a: Union[str,list,set]):
pass
#函数参数
def my_sort(a: list, f: Callable[[int], int], c: bool):
return sorted(a, key=f, reverse=c)
print(my_sort([1, -3, 2], abs, True))
- 参数分类
- 位置参数
- 关键字参数
- 默认参数
- 不定长参数
*args
:将参数打包成元组给函数体调用,没有值传给它,就是个空元组**kwargs
:将参数打包成字典给函数体调用,没有值传给它,就是个空字典- 参数顺序固定:当必需参数,*arg参数,**kwargs参数同时存在时,它们的顺序是固定的,否则报错(位置参数 -> *arg参数 -> **kwargs参数),除非必需参数在传参的时候使用了关键字参数
- 特殊参数:可以使用
/
和*
来限制参数的传递形式/
为仅限位置参数,限制在它之前的形参必须以位置参数的形式传入,而不能用关键字参数*
为仅限关键字参数,限制在它之后的形参必须以关键字参数的形式传入- 这两个特殊参数只是为了限制参数的传递形式,不需要为它们传入实参
def func(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
pass
func(1, 2, 3, kwd1=4, kwd2=5)
- 匿名函数
- 格式:
lambda [arg1 [, arg2, ... argN]] : expression
- 格式:
- 封包、解包
- 封包:将多个值赋值给一个变量时,Python 会自动将这些值封装成元组,这个特性称之为封包
- 解包:可迭代对象都支持解包,解包符号为星号
- 赋值过程中的解包:
a,*b=(1,2,3) #a=1,b=[2,3]
在其中一个变量前面加星号,代表可以接收多个元素,并组成列表来赋值。注意不允许多个带星号的变量 - 在可迭代对象前面加一个星号(*),在字典对象前面加双星(**),这种解包方式主要运用在函数传参的过程中
- 可以结合 json 使用
- 赋值过程中的解包:
def func(a, b, c, d=None):
print(a, b, c, d)
# 在可迭代对象前面加一个星号(*),使其以位置参数的形式传入函数
tup = (1, 2, 3, 4)
dic = {'name': "Tom", 'age': 18, 'height': 188}
func(*tup) # 等效于 func(1, 2, 3, 4)
func(*dic) # 等效于 func('name', 'age', 'height')
# 在字典对象前面加双星(**),使其以关键字参数的形式传入函数
dic = {'a': "Tom", 'b': 18, 'c': 188, 'd': True}
func(**dic) # 等效于 func(a="Tom", b=18, c=188, d=True)
dict(**dic) # 等效于 dict(a="Tom", b=18, c=188, d=True)
#使用json传递值
import json
jsonData = """
{
"a": "Tom",
"b": 18,
"c": 188,
"d": "True"
}
"""
text = json.loads(jsonData)
func(**text)
- 命名空间
- 内置命名空间
- builtins 查看
dir([object])
返回object的属性、方法列表的字符串数组locals() globals()
返回 变量名 和 变量值 的字典
- 全局命名空间:包含模块中定义的名称,记录了模块的变量、函数、类、其它导入的模块等,在模块被读入时创建,持续到解释器退出
- 局部命名空间:包含函数中定义的名称,记录了函数的变量、参数等。一个函数的局部命名空间在这个函数被调用时创建,持续到函数结束
- 命名空间查找顺序:局部命名空间 -> 全局命名空间 -> 内置命名空间
eval(expression[, globals[, locals]])
,exec(object[, globals[, locals]])
- eval() 和 exec() 函数的功能相似,都可以执行一个字符串形式的Python 代码
- 区别:eval()函数只能执行单个表达式,并返回执行的结果;而exec()函数还可以执行代码块,无返回值(return None)
- 内置命名空间
obj = "print(abs(-3))"
exec(obj)
obj = """
a = -3
if a < 0:
print(-a)
else:
print(a)
"""
exec(obj)
- 作用域
- 说明:只有 模块、类、函数 才会引入新的作用域
- 规则:在当前作用域如果找不到对应名称,则去更大一级作用域去找,直到最后找不到就会报错。 L - E - G - B 作用域依次增大
- 局部作用域 (Local) - L :函数、匿名函数中
- 闭包外的函数中 (Enclosing) - E :闭包外的函数中
- 全局作用域 (Global) - G
- 内建作用域 (Built-in) - B :在 builtins 模块中
- global 和 nonlocal
- 当内部作用域想要给外部作用域的变量重新赋值时,可以用 global 或 nonlocal 关键字
def outer():
global a, b # 声明当前作用域的a,b为全局变量
a, b, c, d = 3, 4, 5, 6
print(a, b)
def inner():
global a, b # 声明当前作用域的a,b为全局变量
nonlocal c, d # 声明当前作用域的c,d为Enclosing变量
a, b, c, d = 7, 8, 9, 0
inner()
print(a, b)
print(c, d)
a, b = 1, 2
outer()
print(a, b)
- 内置函数
- 常用高阶函数:参数或返回值为其他函数的函数
filter(function, iterable)
: 将 iterable 中每个元素作为参数传递给函数,根据函数的返回结果进行判断 True 或 False,将判断为 True 的 iterable 中的元素构建新的迭代器并返回map(func,*iterables)
: 用 iterables 中的每个元素作为函数的参数来调用函数,以迭代器形式返回所有结果。当有多个 iterables 对象时,最短的 iterables 耗尽则函数停止reduce(function, iterable[, initial])
:在指定 initial 参数时,先把 initial 值和 iterable 的第一个元素作为参数调用函数,把这次函数的结果以及 iterable 的下一个元素又作为参数再调用函数,以此类推
from functools import reduce
def add(m, n):
s = m + n
print(s)
return s # 如果改为 print(s) 会怎样?
# 过程:[(1+2)+3]+4 = 10
result = reduce(add, [1, 2, 3, 4])
print(result)
'''
3
6
10
10
'''
闭包 和 装饰器
- 闭包:
- 在函数嵌套(函数里面再定义函数)的前提下
- 内部函数使用了外部函数的变量(参数)
- 外部函数的返回值是内部函数的引用
- 一般来说,如果一个函数结束,函数内部的变量、参数会被释放掉;而闭包则不同,它在外部函数结束时,会把内部函数中用到的外部函数的变量、参数保存到内部函数的__closure__属性中,以提供给内部函数使用
- 装饰器:顾名思义就是起装饰作用的,不改变原来函数作用的,只是在原来函数上增加些额外的功能
- 多层装饰器,查看执行顺序
#多层装饰器
import time
def deco(func):
print("in wrapper1")
#闭包函数
def wrapper1(*args):
print("start wrapper1")
res = func(*args)
print("end wrapper1")
return res
print("out wrapper1")
return wrapper1
def timer(func):
print("in wrapper2")
def wrapper2(*args):
print("start wrapper2")
start_time = time.time()
res = func(*args)
end_time = time.time()
print("函数耗时:{}".format(end_time-start_time))
print("end wrapper2")
return res
print("out wrapper2")
return wrapper2
@deco
@timer
def add(*args):
print("start add")
time.sleep(2)
print("end add")
return sum(args)
print(add(3, 4, 5))
#add其实是变化的函数的主体,deco和timer定义了这个变化函数周围固定的上下文作用,
#比如画不同的圆、方块、其他图形,可能载入的上下文都一样,就这个绘制部分的函数不一样,则可以使用装饰器
in wrapper2
out wrapper2
in wrapper1
out wrapper1
start wrapper1
start wrapper2
start add
end add
函数耗时:2.0025978088378906
end wrapper2
end wrapper1
12
- 类中特殊的装饰器
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
@property
def adult_age_p(self):
return 18
def adult_age(self):
return 18
@staticmethod
def adult_age_static(): #静态函数参数中不添加self
return 30
@classmethod
def adult_age_class(cls,param): #class函数中注意添加cls参数
return param
@property
def adult_flag(self):
return self.age >= self.adult_age_p
stu = Student("张三", 18)
print(stu.adult_age()) # 没有加@property, 必须使用正常的调用方法的形式, 在后面加()
print(stu.adult_age_p) # 加了@property, 用调用属性的形式来调用方法, 后面不需要加()
print(stu.adult_flag) # True
print(Student.adult_age_static())
#print(Student.adult_age()) 不是静态函数不可直接使用
print(Student.adult_age_class(29))
stu.age = 17 # 可以修改stu对象的age属性
# stu.adult_age_p = 19 # 报错:@property将方法装饰为只读属性, 不能修改
print(stu.adult_flag) # False
18
18
True
30
29
False
魔法方法
Python常用魔术方法
定义:类中的魔术方法是官方定义好的,以两个下划线开头且以两个下划线结尾来命名的方法。在特定情况下,它会被自动调用,不需要我们主动调用该方法。
- init(self[,…]) : 构造函数
- call(self[,…]) :当实例对象像函数那样被“调用”时,会调用该方法
#__init__和__call__区别
class test:
def __init__(self):
print('__init__')
def __call__(self):
print('__call__')
test()
a = test()
a()
'''
__init__
__init__
__call__
'''
- getitem(self,key) : 当执行 self[key] 操作时,会调用该方法
- len(self) : 对实例对象求长度len()时,会调用该方法,要求必需返回整数类型
class Ex:
def __getitem__(self, key):
print(f"__getitem__被调用, key: {key}")
print(["a", "b", "c"][key])
print({0: "零", 1: "壹", 2: "贰"}[key])
def __len__(self):
return 1234
e = Ex()
e[2]
print(len(e))
'''
__getitem__被调用, key: 2
c
贰
1234
'''
- _repr(self) / str(self) : 实例对象转字符串时,会调用该方法,要求必需返回字符串类型
- __repr__正式,str 非正式。
- __str__主要由 str(),format()和print()三个方法调用。__repr__由repr()调用
- 若定义了__repr__没有定义__str__,那么本该由__str__展示的字符串会由__repr__代替。
- __repr__主要用于调试和开发,而__str__用于为最终用户创建输出。
- 可以看出repr()更能显示出对象的类型、值等信息,对象描述清晰的。 而str()能够让我们最快速了解到对象的内容,可读性较高。
import datetime
s = 'hello'
d = datetime.datetime.now()
print(str(s))
print(repr(s))
print(str(d))
print(repr(d))
'''
hello
'hello'
2018-11-29 22:39:18.014587
datetime.datetime(2018, 11, 29, 22, 39, 18, 14587)
'''
- 运算符重载:
- add(self, other), radd(self, other):add为self+other, radd为other+self,以下同,每个运算操作符有左右两个,可能为了有矩阵这样的
- sub(self, other), rsub(self, other)
- mul(self, other), rmul(self, other)
- truediv(self, other), rtruediv(self, other)
- neg(self, other)
文件读写
open(file, mode='r', encoding=None)
- file:文件路径(相对路径或绝对路径)
- mode:文件打开的模式,默认为 ‘r’ 模式,常用r(只读),w(写入),x(只创),a(追加),+(读写),b(二进制)
- encoding:编码方式(只用在文本模式下),默认依赖平台,通常设置为 ‘UTF-8’
- 打开 file 对应的文件,返回一个文件对象;如果该文件不能被打开,则引发 OSError
- with 语句
- 常用open写法有一个潜在问题,如果在调用 write 的过程中出现了异常,则会导致 close 方法无法被正常调用,导致资源占用的浪费。
- with 语句 会自动创建
__enter__
__exit__
,在结束 with 语句体后会自动close文件
with open(r'./t01.txt', mode='w') as file:
file.write('hello world')
- json 读写
import json
info = {'name': 'Tom', 'age': 18, 1: 'one'}
print(type(info), info)
with open("info.json", mode="w") as f:
info_str = json.dumps(info) # 序列化
print(type(info_str), info_str)
f.write(info_str)
with open("info.json") as f:
content = f.read()
print(type(content), content)
res = json.loads(content) # 反序列化
print(type(res), res)
模块、包
- 模块
- 模块是一个包含Python定义和语句的文件,文件名就是模块名后跟文件后缀 .py
- 一个模块被另一个程序导入时,会执行该模块
- 一个模块只会被另一个程序导入一次
__name__
属性:- 每个模块都有一个__name__属性,当其值是 ‘main’ 时,说明该模块自身在运行,否则说明该模块被导入,其值为模块名
- 在完成一个模块的编写之前,我们一般会对模块中的功能进行测试,看看各项功能是否正常运行。对于这些测试的代码,我们希望只在直接运行这个py文件的时候执行,而在用其他的程序导入这个模块的时候不要执行。这个时候就可以借助__name__属性来实现
print('在该模块自身运行时会执行')
print('在该模块被导入时也会执行')
if __name__ == '__main__':
print('在if语句下的程序块仅在该模块自身运行时才执行')
else:
print('在else子句下的程序块在该模块自身运行时不会执行')
print('但是在被导入时, 会执行')
- 包
- Python包实际上就是一个文件夹,只是该文件夹里面一定包含__init__.py 模块。和文件夹一样,包里面还可以装其他的包
- 避免相同命名冲突: 如果在同一个包里,是不允许两个模块命名相同的,但是如果不在同一个包里,是可以的
- 模块分区: 把不同功能的模块归类到不同的包里,方便查询和修改。在比较大型的项目中常常需要编写大量的模块,此时我们可以使用包来对这些模块进行管理