生成器
生成器与列表推导式十分类似,将定义的括号由[]改为(),特点是调用一次,运算一次,占用的内存少,可以在for中使用,在处理大数据的时候,可以使用生成器,使用next()方法来生成下一个值,当生成器中的值都完成后,再次调用生成器会出现StopIteration的错误
还可以使用生成器来生成斐波那契数列,使用循环来抛出结果
def fib(times):
n = 0
a, b = 0, 1
while n<times:
yield b
a, b = b, a+b
n += 1
for item in fib(6):
print(item)
使用next来抛出结果,超出范围的仍然会报错
# -*- enoding: utf-8 -*-
def fib(times):
n = 0
a, b = 0, 1
while n<times:
yield b
a, b = b, a+b
n += 1
f = fib(6)
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
迭代器
迭代器,用来访问集合元素的一种方式,只前进不后退,可以使用isinstance来判断一个对象是否可以迭代,使用之前需要先导入判断迭代的工具,然后再进行判断,生成器都可以迭代,迭代器也可以使用next()方法来调用,可迭代的对象要转换成迭代器的话需要使用iter()函数
作用域和闭包
作用域:这个概念在其他语言中变现为命名空间,可以防止命名冲突,一个变量的作用域为,本地变量(局部变量),闭包,全局变量,内建模块
闭包:就是在一个函数内再定义一个函数,内部的函数可以直接使用外部函数的变量,函数的参数为局部变量,闭包的使用可以延长局部变量的使用寿命
装饰器
装饰器:有了以上的两个概念,就可以介绍装饰器,其实装饰器就是一个闭包,把一个函数当做参数传入另一个函数中,增强函数的功能但是不改变原来的函数,相当于一个语法糖,小技巧的东西。装饰器的作用可以由用户来定制,比如引入日志,做程序运行时间统计,执行函数前进行预处理,执行函数后清理,权限校验,缓存。这些操作会将被装饰的函数替换成新的函数,加载模块的时候立即执行。在使用装饰器的时候只需要在原函数的上方加上@装饰器名 就可以使用了。这就是动态语言的优点,为对象动态的添加属性和方法。
装饰器就是将函数作为参数传入,示例
def day2(function):
print("hello,world")
return function
#在被装饰的函数上方加上装饰标识
@day2
def day1():
print("I am a function, named %s"%day1.__name__)
def main():
day1()
if __name__=="__main__":
main()
可以看出在装饰器中的语句也被执行了
做一个装饰器嵌套来观察装饰器代码的运行顺序
#定义装饰器,将传入的函数返回,装饰器必须放在被装饰函数的前面
def decorate_albert(function):
print("start run",decorate_albert.__name__)
#函数嵌套
def wapper():
print("开始运行",wapper.__name__)
print("my name is ",wapper.__name__)
print("结束运行函数")
return wapper
def decorate_albert2(function):
print("start run",decorate_albert2.__name__)
return function
#定义一个函数
#如果是嵌套两层的装饰器,
@decorate_albert
@decorate_albert2
def albert():
print("my name is %s"%albert.__name__)
def main():
albert()
if __name__=="__main__":
main()
可以看出首先执行的是在下方的装饰器,然后向外层冒泡,直到最外一层的装饰器,最后执行被装饰的函数。还可以给装饰器传参数,示例:
#给装饰器函数传参
def deco_func(func):
print("I am a function named %s"%deco_func.__name__)
def wapper(*args,**kw):
print("start to run",wapper.__name__)
print(args,kw)
func(*args,**kw)
print("function end",wapper.__name__)
return wapper
#定义一个函数用来被装饰
@deco_func
def print_name(name,age):
print("I am a function named %s"%print_name.__name__)
print(f"your name is {name},your age is {age}")
def main():
print_name("albert",23)
if __name__=="__main__":
main()
但是在加入装饰器的时候原来函数的名字和参数也会被改变,为了消除这种负面影响,可以通过偏函数wraps来消除,在使用之前需要先从工具中引入
from functools import wraps
#给装饰器传递参数名字,在装饰器定义一个新的函数,然后将参数传入
def deco_para(name):
def deco_func(func):
print("I am a function named %s"%deco_func.__name__)
#解决函数地址改变的方法,加一个偏函数,记住原来函数的名字
@wraps(func)
def wapper(*args,**kw):
print("start to run",wapper.__name__)
print(args,kw)
func(*args,**kw)
print("function end",wapper.__name__)
print("I am a decorate named %s"%name)
return wapper
return deco_func
#定义一个函数用来被装饰
@deco_para("Decorate_name")
def print_name(name,age):
print("I am a function named %s"%print_name.__name__)
print(f"your name is {name},your age is {age}")
def main():
print_name("albert",23)
if __name__=="__main__":
main()
可以看出函数名字还是原来的print_name,然后将这个函数形式改写为类形式,更易读易扩展。
from functools import wraps
class Decorate():
#初始化装饰器类,并命名
def __init__(self,name):
self.name=name
#定义装饰器类的功能,并且传入参数
def __call__(self,func):
@wraps(func)
def wappers(*args,**kw):
print("I am a function named",wappers.__name__)
print(*args,**kw)
func(*args,**kw)
print("end function",wappers.__name__)
print("I am a decorate named %s"%self.name)
return wappers
#实例化装饰器类,创建一个对象
@Decorate("de_albert")
def print_name(name,age):
print("I am a function named %s"%print_name.__name__)
print(f"my name is {name},my age is {age}")
def main():
print_name("albert",23)
if __name__=="__main__":
main()
执行结果与上面的函数一致。接下来利用以上的知识就可以做一些需求了,比如说实现一个记录函数运行的日志,再加上一个登陆的验证
#定义一个装饰器功能,实现记录函数运行日志,登录验证
from functools import wraps
class Decorate(object):
def __init__(self, func_name, file_name='test.log'):
self.func_name = func_name
self.file_name = file_name
def __call__(self,func):
@wraps(func)
def wappers(*args,**kw):
if hasattr(self, self.func_name):
my_func = getattr(self, self.func_name)
if my_func(func):
func(*args,**kw)
return wappers
def write_log(self,func):
str_log = "{} funtion is runing".format(self.write_log.__name__)
with open(self.file_name, 'a', encoding='utf-8') as f:
f.write(str_log+'\n')
return True
def login_check(self,func):
name = input("请输入用户名")
pwd = input("请输入密码")
if name == "albert" and pwd == "123":
print ("log in success")
return True
else:
print ("sorry, wrong username or password")
return False
@Decorate('login_check')
@Decorate('write_log')
def print_func_name():
print("I am a function named %s"%print_func_name.__name__)
def main():
print_func_name()
if __name__ == "__main__":
main()
当输入的用户名和密码与设置的不一致时,告知错误用户名或密码,然后不执行接下来的代码,当输入正确的时候,显示登入成功并且运行接下来的函数,记录运行日志,文件保存为test.log。
还可以做一个记录函数运行时间的装饰器,示例:
#使用装饰器实现 函数计时功能
import time
from functools import wraps
class Func_time(object):
def __init__(self,name):
self.name = name
def __call__(self,func):
@wraps(func)
def wappers():
start_time = time.time()
func()
time_diff = time.time() - start_time
print("%s function run used %d s"%(func.__name__,time_diff))
return wappers
@Func_time("timer")
def run_func():
print("start")
time.sleep(3)
print("end")
def main():
run_func()
if __name__ == "__main__":
main()
单独做一个程序运行日志记录的装饰器,示例:
#使用装饰器做一个日志记录
from functools import wraps
class Decorate():
def __init__(self,file_name):
self.file_name=file_name
def __call__(self,func):
@wraps(func)
def wappers(*args,**kw):
str_log="{} function is run".format(func.__name__)
with open (self.file_name,'a',encoding="utf-8") as f:
print(str_log)
f.write(str_log+'\n')
func(*args,**kw)
return wappers
@Decorate("test.log")
def print_name(name,age):
print("I am a function named %s"%print_name.__name__)
print(f"my name is {name},my age is {age}")
def main():
print_name("albert",23)
if __name__=="__main__":
main()
当运行函数的时候,会自动生成该函数运行的日志。