Python小记 面向对象(编译、迭代器、生成器、装饰器、命名空间)



编译 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])
    • 重复生成objecttimes指定重复次数数

返回目录


生成器 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=15n 被重新赋值)

返回目录

装饰器

  • 用于扩展原函数功能
  • 返回值也是一个函数,可以理解为返回重新包装后的函数
  • 之前所用的 @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
'''

返回目录

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛定谔的壳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值