文章目录
编译 py_compile
编译单个文件
import py_compile as pyc
source_path = 'test.py'
pyc_path = 'test.pyc'
pyc.compile(source_path, pyc_path)
编译多个文件
import compileall
my_dir = r'd:/python_code/test'
compileall.compile_dir(my_dir)
通过 Shell 编译
python -O -m py_compile test.py
python -m pu_compile test.py
生成的pyc文件默认在当前目录 __pycatch__
路径下
-O
字节码优化-OO
优化程度大,编译后脚本更小,容易出错
创建包
- 在目录下创建
__init__.py
-
import package
后,__init__.py
中的代码得以调用执行,同时导入其中的变量和函数
迭代器
iter(__iterable)
next(iter)
lst = list(range(10))
liter = iter(lst)
for i in liter:
print(i)
print(liter.__next__())
print(next(liter))
iter(callable, sentinel)
callbale
: 可调用类型,一般为函数sentinel
:返回值等于第二个参数时,迭代便利会停止
class Test:
x = 0
t = Test()
def cable():
t.x += 2
return t.x
for i in iter(cable, 12):
print(i)
创建类作为迭代器使用
# ------------------------------------
# 功能:从start 开始,每次返回值 加per
# 当返回值 大于max,停止
# ------------------------------------
class Tem:
def __init__(self, per=2, max_num=20, start=0):
self.__per = per
self.__max = max_num
self.__value = start
def __iter__(self):
return self
def __next__(self):
# 值每次加 per,如果 per==0,则每次加 1
self.__value += self.__per if self.__per else 1
# 如果还未超过 阈值 max 则返回值
if self.__value <= self.__max:
return self.__value
# 否则 引发异常
else:
raise StopIteration
__init__
- 初始化
__next__
- 构造迭代规则。(构造并返回下一次的返回值)
- 说明迭代停止条件。(停止时
raise StopIteration
)
__iter__
- 定义迭代器协议方法
- 返回类的自身。
- 如果返回的是其他可迭代对象。
当for i in TemClass
时(将类实例当做可迭代对象时)
迭代的将是方法返回的那个对象。
无限迭代器
- 依赖
itertools
-
count(start=0,step=1)
start
开始,step
为步长
-
cycle(iterable)
- 循环迭代器
-
repeat(object[, times])
- 重复生成
object
,times
指定重复次数数
- 重复生成
生成器 yield
简单生成器
yield
可以看做return
- 可以
next(generator)
- 也可以
generator.__next__()
- 还可以
for one in generator:
# 无线循环生成
# 循环返回 string 字符串中的字符
def word_generator(string):
index = 0
while 1:
yield string[index % len(string)]
index += 1
st = "我们要坚强坚强坚强"
words = word_generator(st)
for i in range(80):
if i and not i % 10:
print()
print(next(words), end='')
输出:
我们要坚强坚强坚强我
们要坚强坚强坚强我们
要坚强坚强坚强我们要
坚强坚强坚强我们要坚
强坚强坚强我们要坚强
坚强坚强我们要坚强坚
强坚强我们要坚强坚强
坚强我们要坚强坚强坚
稍灵活的生成器 send、yield
- 函数包含
yield
语句则识别为生成器 - 函数在
next
时运行到yield
处停止,下一次next
时接着从这运行 send
会从上一次next
停止处运行,完成赋值操作send
包含一次next
# ------------------------------------------
# 从 n 开始,返回值每次加 5,直到返回值大于 max_ 停止
# rcv 用于接收 send 值
# 通过判断 rcv 是否收到值,收到则将值赋给 n
# 为了方便察看输出结果,生成器返回值做了一些修改
# 改为:
# tada : n
# ------
# ------------------------------------------
def generator(n, max_=20):
while n < max_:
rcv = yield f'tada : {n}\n------'
n += 5
if rcv:
print("rcv: ", rcv)
n = rcv
gen = generator(2)
print(next(gen))
print(gen.send(10))
print(gen.__next__())
输出:
tada : 2
------
rcv: 10
tada : 10
------
tada : 15
------
- 分析
- 第一次
返回值n=2
(初值) - 第二次
send(10)
后,rcv
先接收到值,
而后包含一次next
:- 继续运行到
yiled
处【包括完成n
重新赋值 和yield n
= 10】
- 继续运行到
- 第三次
返回值n=15
(n
被重新赋值)
装饰器
- 用于扩展原函数功能
- 返回值也是一个函数,可以理解为返回重新包装后的函数
- 之前所用的
@classmethod
@staticmethod
@property
就是装饰器
简单装饰器
import time
def timer(func):
def wrapper():
start = time.time()
func()
end = time.time()
m_sec = (end - start) * 1e3
print(f'花费 {m_sec} ms')
return wrapper
@timer
def fun():
print("Start!")
time.sleep(2)
print("End")
fun()
# Output:
'''
Start!
End
花费 2000.082015991211 ms
'''
带参数
def timer2(func):
def wrap(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
ms = (time.time() - start) * 1e3
print(f'耗时:{ms}ms')
return wrap
@timer2
def fun2(a, b, **kw):
print("Start!")
print(f'{a=}, {b=}, {kw["Key"]=}')
time.sleep(2)
print("End")
fun2(12, 'None_value', Key='就是玩')
# Output
'''
Start!
a=12, b='None_value', kw["Key"]='就是玩'
End
耗时:2000.049352645874ms
'''
多层装饰器
- 从最后一个开始执行。【以下边为例】
- 可以理解为
first(second(test))
second
为第一层包装,first
为最外层包装- 执行的时候自然是从最外层开始
def first(func):
def wrap():
print('第一层开始')
func()
print('第一层结束')
return wrap
def second(func):
def wrap():
print('第二层开始')
func()
print('第二层结束')
return wrap
@first
@second
def test():
print('原函数开始')
print('原函数结束')
test()
# Output
'''
第一层开始
第二层开始
原函数开始
原函数结束
第二层结束
第一层结束
'''
以类作为装饰器
- 流程
__init__(self, fun)
-->__call__(*args, **kwargs)
1.无参数的话
可以在__init__
或者 __call__
中运行函数
class lala:
def __init__(self, fun):
print("__init__")
self.fun = fun
# self.fun() // 无参数的话
def __call__(self, *args, **kwargs):
print("__call__")
self.fun(*args, **kwargs)
@lala
def doit(a, b):
print(f'Doit result = {a+b}')
doit(12, 11)
# Output
'''
__init__
__call__
Doit result = 23
'''
类的装饰器
def clsdec(class_):
class Inner:
def __init__(self, name, *args, **kwargs):
self.name = name
self.class_ = class_(*args, **kwargs)
def doit(self):
print(self.class_.x + self.class_.y)
@property
def get_name(self):
return self.name
return Inner
@clsdec
class Test:
def __init__(self, x, y):
self.x = x
self.y = y
def get_name(self):
return None
test = Test('Fry', 12, 3)
test.doit()
print(test.get_name)
# print(test.x) // 报错,Inner 类没有 x 属性
# Output
'''
15
Fry
'''
- 上述,只是将要装饰的类作为 装饰器 构造类的
属性
来进行包装。也就避免了一些滥用问题。 - 此时的类其实已经包装成了
Inner
,而不是Test
。
如果想要获取到Test
类的其他属性、方法时,就只能通过test.class_
属性来访问,或者在Inner
内进行“继承”
或重写
。
- 如果想要完整保留原Test类的所有属性方法,使得被装饰后依旧可以调用,就可以在装饰器内部类 中继承该类。
- 吐槽这个,跟直接写个子类继承也不是不行。可能是我还没悟到 类的装饰器 使用场景
def clsdec(class_):
class Inner(class_):
def __init__(self, name, *args, **kwargs):
self.name = name
super().__init__(*args, **kwargs)
def doit(self):
print(self.x+self.y)
@property
def get_name(self):
return self.name
return Inner
@clsdec
class Test:
def __init__(self, x, y):
self.x = x
self.y = y
def get_name(self):
return None
命名空间
locals()
---- 局部globals()
---- 全局- 返回值为字典型
x = 1
y = 2
def doit():
z = 12
lt = [2, 4]
print(locals())
print(locals())
print(globals()) # 跟上边输出一致
doit()
# Output
'''
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <...>, '__spec__': None, '__annotations__': {}, '__builtins__': <...>, '__file__': 'D:\\....py', '__cached__': None, 'x': 1, 'y': 2, 'doit': <function doit...>}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <...>, '__spec__': None, '__annotations__': {}, '__builtins__': <...>, '__file__': 'D:\\....py', '__cached__': None, 'x': 1, 'y': 2, 'doit': <function doit...>}
{'z': 12, 'lt': [2, 4]}
'''
locals()
- 不可删改
- 但是可以添加
locals()['key'] = value
- !! 可以删除 通过上面方法添加的变量
del lcals['key']
或者del locals()['key']
lcals.pop('key')
或者locals().pop('key')
lcals.clear()
或者locals.clear()
def doit():
z = 12
lt = [2, 4]
print(locals())
lcals = locals()
lcals['name'] = 'Fry'
# del lcals['lt']
del locals()['lt']
lcals['z'] = 999
print(locals())
locals()['z'] = 988
print(locals())
lcals.pop('name')
print(locals())
doit()
# Output
'''
{'z': 12, 'lt': [2, 4]}
{'z': 12, 'name': 'Fry', 'lcals': {...}, 'lt': [2, 4]}
{'z': 12, 'name': 'Fry', 'lcals': {...}, 'lt': [2, 4]}
{'z': 12, 'lcals': {...}, 'lt': [2, 4]}
'''
globals()
- 可以增、删、改 !!
x = 1
y = 2
def doit():
z = 12
lt = [2, 4]
print(locals())
glb = globals()
print('原全局变量')
print(glb)
# 修改 x, 删去 y
glb['x'] = 12
glb.pop('y')
print(f'删改后的全局变量 \n {globals()}')
# 增加 sid
glb['sid'] = 10010110
print(f'添加后的全局变量 \n {globals()}')
print(f'{sid=}')
# Output_simplify
'''
原全局变量
{...,
'x': 1,
'y': 2,
'doit': <function doit..>,
'glb': {...}
}
删改后的全局变量
{...,
'x': 12,
'doit': <function doit..>,
'glb': {...}
}
添加后的全局变量
{...,
'x': 12,
'doit': <function doit..>,
'glb': {...},
'sid': 10010110
}
sid=10010110
'''