1 函数初步
#普通函数定义与调用
def hi(name="nihao"):
return "hi" +name
print(hi())
"""hinihao"""
#我们可以将函数名赋给一个变量,传递的是引用
greet = hi
print(greet())
"""hinihao"""
#函数无返回值时输出None
def hi(name="nihao"):
print( "hi" +name)
print(hi())
2 函数形参调用顺序
a,接收单个参数
*args接收元组型参数
**kwargs接收字典型参数
def func(a,*args,**kwargs):
"""不管如何调用func()函数,第一个参数a是必需的,否则报错typeerror"""
print(a,end=">>")
print(args,end=">>")
print(kwargs)
func(3,4,5,6)
#输出结果:3>>(4, 5, 6)>>{}
func(3,text="你好")
#输出结果:3>>()>>{'text': '你好'}
func(text="你好")
#func() missing 1 required positional argument: 'a'
嵌套函数
def hi(name="nihao"):
"""嵌套的函数"""
print("你好,中国")
def greet():
print("你好世界")
def welcome():
print("欢迎来北京")
print(greet()) #greet()函数无返回值,故print函数输出None
print(welcome()) #无返回值,输出None
print(hi()) #无返回值,输出None
"""
你好,中国
你好世界
None
欢迎来北京
None
None
"""
def hi(name="nihao"):
print("你好,中国")
def greet():
return "你好世界"
def welcome():
return "欢迎来北京"
print(greet())
print(welcome())
print(hi())
greet() #显示语法错误,并不能在嵌套函数外部访问到内部的函数
"""
你好,中国
你好世界
欢迎来北京
None
"""
3 从函数中返回函数
#从函数中返回函数
def hi(name="zhang"):
def greet():
return "now you are in greet func"
def welcome():
return "now you are in welcome"
if name == "zhang":
return greet
else:
return welcome
a = hi() #执行hi()函数,返回greet方法的引用
print(hi())
print(a) #返回的只是函数名greet,也就是说a指向了greet()函数的函数名所在地址,并不会发生函数调用
print(a()) #a()调用方法
"""
<function hi.<locals>.greet at 0x0000028138E57B88>
<function hi.<locals>.greet at 0x0000028138E57D38>
now you are in greet func
"""
4 函数作为参数传递
#将函数作为参数传递给另一个函数
def hi():
return "中国"
def hello(func):
print("正在做一些准备工作")
print(func())
hello(hi) #传递hi函数的引用
"""
正在做一些准备工作
中国
"""
5 闭包-不改变外部函数参数
#闭包:在一个外层函数中定义了一个内部函数,内部函数使用了外部函数的临时变量,并且外部函数的返回值是内部函数
"""闭包:
1.嵌套
2.内部使用了外部变量
3.返回的是内部函数"""
#第一个装饰器
def a_new_decorator(a_func):
a = 10
def wrap_the_func():
print("a的值",a)
print("在执行a_func()之前做一些工作")
a_func() #闭包:内部函数引用了外部函数的参数a_func
print("在执行a_func()之后做一些工作")
return wrap_the_func #返回函数引用
"""函数a_new_decorator()中有临时变量:a_func以及wrap_the_func;后者指向函数的地址"""
def func1():
print("我是一个需要装饰器的函数")
func1 = a_new_decorator(func1) #把函数wrap_the_func的引用传递给了func1
func1()
"""
a的值 10
在执行a_func()之前做一些工作
我是一个需要装饰器的函数
在执行a_func()之后做一些工作
"""
6 闭包-改变外部函数参数-nonlocal
#内部函数改变外部函数的参数的值,需要在内部函数中声明变量nonlocal
def a_new_decorator(a_func):
"""nonlocal"""
a = 10
def wrap_the_func():
nonlocal a
a += 10
print("a的值",a)
print("在执行a_func()之前做一些工作")
a_func()
print("在执行a_func()之后做一些工作")
return wrap_the_func
def func1():
print("我是一个需要装饰器的函数")
func1 = a_new_decorator(func1)
func1()
7 装饰器
#可以看到,装饰器对函数进行封装,并且能修改被封装函数的行为
"""开放(与那函数功能更加强大)、封闭(不能改变原函数)"""
def a_new_decorator(a_func): #装饰器函数
print("-------->1")
print("被装饰函数的地址",a_func)
def wrap_the_func():
print("在执行a_func()之前做一些工作")
#调用被装饰函数
a_func()
print("在执行a_func()之后做一些工作")
print("-------->2")
return wrap_the_func
@a_new_decorator #所以@a_new_decorator等同于func1 = a_new_decorator(func1)
def func1(): #被装饰函数
print("我是一个需要装饰器的函数")
print("-------->3")
func1()
print("-------->4")
print(func1.__name__)
#使用装饰器,把装饰函数的引用传递给被装饰器函数,在执行函数时自动调用装饰器函数而不能更改被装饰函数
#从输出来看,@a_new_decorator相当于进行了一次传参调用
"""
-------->1
被装饰函数的地址 <function func1 at 0x000001BC7822ECA8>
-------->2
-------->3
在执行a_func()之前做一些工作
我是一个需要装饰器的函数
在执行a_func()之后做一些工作
-------->4
wrap_the_func
"""
8 登陆验证
"""使用装饰器在进行支付之检查登录状态"""
import time
is_login = False
def login_required(func):
"""被装饰函数含有参数,内部参数也应定义相应数量的参数"""
def wrapper(goods):
if is_login:
#执行付款操作
func(goods)
else:
print("请先登录")
login_status = login()
if login_status:
func(goods)
else:
print("用户名或密码错误")
login()
return wrapper
@login_required
def pay(goods):
total_price = 0
if isinstance(goods,dict):
print("所有商品列表如下")
for grocery,price in goods.items():
print("商品%s价格%f" % (grocery,price))
total_price += price
print("一共需支付%f" % total_price)
print("付款中")
time.sleep(2)
def login():
username = input("请输入用户名")
passwd = input("请输入密码")
if username == "admin" and passwd == "1234":
print("登录成功")
is_login = True
else:
print("登陆失败")
return is_login
goods = {"三只松鼠":46.58,"蓝月亮":35,"Martin":5668}
pay(goods)
9 装饰器装饰多个函数
def decorator(func):
"""装饰器装饰多个函数,接收不定参数使用形参*args,**kwargs"""
def wrapper(*args):
print("----->1")
#func(args)
#test1() missing 1 required positional argument: 'b'
func(*args)
print("----->2")
return wrapper
@decorator
def test1(a,b,c=10):
print("和为",a+b+c)
@decorator
def test2():
print("你好")
test1(6,8)
test2()
10 装饰器带返回值
"""
定义装饰器一般格式:
def decorator(func):
def wrapper(*args,**kwargs):
...
...
func(*args,**kwargs)
...
return wrapper
返回值的通用性:
def decorator(func):
def wrapper(*args,**kwargs):
...
...
return func(*args,**kwargs)
return wrapper
或者:
def decorator(func):
def wrapper(*args,**kwargs):
...
result = func(*args,**kwargs)
return result
return wrapper
"""
def decorator(func):
def wrapper(*args,**kwargs):
print("你好")
result = func(*args,**kwargs)
return result
return wrapper
@decorator
def test(a,b):
print(a+b)
return "世界"
f = test(2,3)
print(f)
11 装饰器带参数
"""
装饰器带参数
"""
def decorator(args1):
def wrapper_outer(func):
def wrapper(*args,**kwargs):
print("---装饰前",args1)
if args1 == "AA":
func(*args,**kwargs)
print("----->进入AA家")
elif args1 == "BB":
func(*args,**kwargs)
print("----->进入BB家")
else:
func(*args,**kwargs)
print("路由错误")
print("---装饰后",args1)
return wrapper
return wrapper_outer
@decorator("AA")
def test1():
print("------>test1")
def test(a):
print("------>test",a)
return 'hello'
test1()
"""
---装饰前 AA
------>test1
---装饰后 AA
"""
12 多层装饰器
"""
多层装饰器
装饰顺序按就被装饰函数近的原则进行装饰
装饰后的最外层装饰器的函数引用指向被装饰函数
"""
def decorator(args1):
def wrapper_outer(func):
def wrapper_butterfly(*args,**kwargs):
print("---装饰前",args1)
func(*args,**kwargs) #func = wrapper_paper
print("---装饰后",args1)
return wrapper_butterfly
return wrapper_outer
def decorator2(args1):
def wrapper_outer(func):
def wrapper_paper(*args,**kwargs):
print("---装饰前",args1)
func(*args,**kwargs)
print("---装饰后",args1)
return wrapper_paper
return wrapper_outer
"""根据就近原则,先运行装饰器@decorator("包装纸"),返回一个wrapper_paper引用给外层装饰器,
也就是说装饰器@decorator2("蝴蝶结")装饰的对象是wrapper_paper,最后返回wrapper_butterfly
的引用给test1"""
@decorator2("蝴蝶结")
@decorator("包装纸")
def test1(): #test1 = wrapper_butterfly
print("------>test1")
test1()
"""
---装饰前 蝴蝶结
---装饰前 包装纸
------>test1
---装饰后 包装纸
---装饰后 蝴蝶结
"""
13 @property
1.修饰方法,使方法可以像属性一样访问。
class DataSet(object):
@property
def method_with_property(self): ##含有@property
return 15
def method_without_property(self): ##不含@property
return 15
l = DataSet()
print(l.method_with_property) # 加了@property后,可以用调用属性的形式来调用方法,
#后面不需要加()
print(l.method_without_property()) #没有加@property , 必须使用正常的调用方法的形式,
#即在后面加()
2.与所定义的属性配合使用,这样可以防止属性被修改
class DataSet(object):
def __init__(self):
self._images = 1
self._labels = 2 #定义属性的名称
@property
def images(self): #方法加入@property后,这个方法相当于一个属性,这个属性可以让用户
#进行使用,而且用户没办法随意修改。
return self._images
@property
def labels(self):
return self._labels
l = DataSet()
#用户进行属性调用的时候,直接调用images即可,而不用知道属性名_images,因此用户无法更改属
#性,从而保护了类的属性。
print(l.images) # 加了@property后,可以用调用属性的形式来调用方法,后面不需要加()
14总结
"""
装饰器函数不带参数:
def decorator(func):
def wrapper():
...
...
func()
...
return wrapper
装饰器函数带不变参数:
def decorator(func):
def wrapper(参数个数与被装饰函数保持一致):
...
...
func()
...
return wrapper
装饰器函数带可变参数的装饰器,可实现一个装饰器装饰多个函数:
def decorator(func):
def wrapper(*args,**kwargs):
...
...
func(*args,**kwargs)
...
return wrapper
装饰器函数带有返回值的通用性:
def decorator(func):
def wrapper(*args,**kwargs):
...
...
return func(*args,**kwargs)
return wrapper
或者对返回值进行加工:
def decorator(func):
def wrapper(*args,**kwargs):
...
result = func(*args,**kwargs)
return result
return wrapper
装饰器的使用步骤:
1.定义装饰器
闭包 + 参数
2.使用
@装饰器名字
def 被装饰函数():
...
3.函数调用:A()
@装饰器的后台执行:
1.将被装饰函数作为参数传递给装饰器
2.执行装饰器
3.将装饰器的返回值赋给被装饰函数
开发时的使用:
1.登录验证
2.flask中的路由就是通过装饰器完成
3.日志文件
"""
参考:https://zhuanlan.zhihu.com/p/64487092 python @property的介绍与使用