- 编译 py_compile
- 编译单个文件
- 编译多个文件
- 通过 Shell 编译
- 创建包
- 迭代器
- `iter(__iterable)`
- `iter(callable, sentinel)`
- 创建类作为迭代器使用
- 无限迭代器
- 生成器 yield
- 简单生成器
- 稍灵活的生成器 send、yield
- 装饰器
- 简单装饰器
- 带参数
- 多层装饰器
- 以类作为装饰器
- 类的装饰器
- 命名空间
- locals()
- globals()
编译 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 时(将类实例当做可迭代对象时)
迭代的将是方法返回的那个对象。
无限迭代器
- 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': }
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <...>, '__spec__': None, '__annotations__': {}, '__builtins__': <...>, '__file__': 'D:\....py', '__cached__': None, 'x': 1, 'y': 2, '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': ,
'glb': {...}
}
删改后的全局变量
{...,
'x': 12,
'doit': ,
'glb': {...}
}
添加后的全局变量
{...,
'x': 12,
'doit': ,
'glb': {...},
'sid': 10010110
}
sid=10010110
'''
返回目录



