本文将为您提供关于如何更改函数行为,但不更改python-装饰器中的函数?的详细介绍,我们还将为您解释python中修改函数的相关知识,同时,我们还将为您提供关于49Python-装饰器函数定义装饰器
本文将为您提供关于如何更改函数行为,但不更改 python - 装饰器中的函数?的详细介绍,我们还将为您解释python中修改函数的相关知识,同时,我们还将为您提供关于49 Python - 装饰器 函数定义装饰器、< Python全景系列-9 > Python 装饰器:优雅地增强你的函数和类、GitHub如何更改URL,但不更改重新加载?、python 全栈开发,Day12(函数的有用信息,带参数的装饰器,多个装饰器装饰一个函数)的实用信息。
本文目录一览:- 如何更改函数行为,但不更改 python - 装饰器中的函数?(python中修改函数)
- 49 Python - 装饰器 函数定义装饰器
- < Python全景系列-9 > Python 装饰器:优雅地增强你的函数和类
- GitHub如何更改URL,但不更改重新加载?
- python 全栈开发,Day12(函数的有用信息,带参数的装饰器,多个装饰器装饰一个函数)
如何更改函数行为,但不更改 python - 装饰器中的函数?(python中修改函数)
如何解决如何更改函数行为,但不更改 python - 装饰器中的函数??
我想修改现有函数 (original_function
),但此函数用于代码库中的其他函数。所以我的小组建议不要直接编辑函数,而是使用装饰器之类的东西。
这是一个最小的例子:
def original_function(x,is_download = false):
info = getInfo(x)
if is_download:
download_function(info,download_location = path1,is_download = true)
return info
else:
return x
我想改变以下两点:
- 将下载路径从
path1
更改为path2
- 不管
is_download
是什么,返回info
(只有在is_download
设置true
时才返回)
def new_function(x,is_download = false):
info = getInfo(x)
download_function(info,download_location = path2,is_download = false)
return info
有人知道如何解决这个问题吗?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)
49 Python - 装饰器 函数定义装饰器
03 函数定义装饰器
前面讲解了装饰器的一些概念和装饰器会用到的函数的知识,接下来讲解装饰器的定义,有两种方式可以定义装饰器一种是通过函数定义,一种是通过类定义。
001函数定义装饰器
(1)装饰器定义
如何定义
装饰器名称本身是一个函数,定义时候类似函数一样定义
装饰器需要修饰另外一个函数,所以装饰器需要一个传入一个函数作为参数
装饰器内部再定义一个函数用于对传递进来的函数进行装饰的,定义一个函数wrapper(*args, **kwargs)——相当于任何函数任何参数都可以通配,函数wrapper()就是对传入装饰器的func函数进行修改或者封装
装饰器内部函数返回装饰后的结果
装饰器本身返回内部函数对象(因为没有括号,所以不是内部函数执行结果),函数p_decorator()返回的是函数的对象wrapper不是wrapper的结果
(2)装饰器应用:用到某个函数上面
有两种方式:一种是用@方式,一种是类似函数调用方式,建议用第一种
该装饰器需求是:在返回字符串外面加一个p标签
方式一:
方式二:了解
(3)另一个例子:文本变大写
< Python全景系列-9 > Python 装饰器:优雅地增强你的函数和类
欢迎来到我们的系列博客《Python全景系列》第九篇!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高级话题,帮助你掌握这门强大而灵活的编程语法。无论你是编程新手,还是有一定基础的开发者,这个系列都将提供你需要的知识和技能。
装饰器在 Python 中扮演了重要的角色,这是一种精巧的语言特性,让我们能够修改或增强函数和类的行为,无需修改它们的源代码。这篇文章将深入探讨装饰器的所有相关主题,包括装饰器的基础知识、实现与使用、工作原理,以及通过实际例子学习装饰器的独特用法。
Python 装饰器深入探讨
在 Python 中,装饰器提供了一种简洁的方式,用来修改或增强函数和类的行为。装饰器在语法上表现为一个前置于函数或类定义之前的特殊标记:
@simple_decorator
def hello_world():
print("Hello, world!")
在这个例子中,simple_decorator
是一个装饰器,它作用于下方的 hello_world
函数。装饰器在概念上就像一个包装器,它可以在被装饰的函数执行前后插入任意的代码,进而改变被装饰函数的行为。
参数化装饰器
我们还可以进一步将装饰器参数化,这让装饰器的行为更具灵活性。比如,我们可以定义一个装饰器,让它在函数执行前后打印自定义的消息:
def message_decorator(before_message, after_message):
def decorator(func):
def wrapper(*args, **kwargs):
print(before_message)
result = func(*args, **kwargs)
print(after_message)
return result
return wrapper
return decorator
@message_decorator("Start", "End")
def hello_world():
print("Hello, world!")
在这个例子中,message_decorator
是一个参数化装饰器,它接受两个参数,分别代表函数执行前后要打印的消息。
理解装饰器的工作原理
在 Python 中,函数是第一类对象。这意味着函数和其他对象一样,可以作为变量进行赋值,可以作为参数传给其他函数,可以作为其他函数的返回值,甚至可以在一个函数里面定义另一个函数。这个特性是实现装饰器的基础。
def decorator(func):
def wrapper():
print(''Before function execution'')
func()
print(''After function execution'')
return wrapper
def hello_world():
print(''Hello, world!'')
decorated_hello = decorator(hello_world)
decorated_hello()
在这个例子中,decorator
函数接收一个函数 hello_world
作为参数,并返回了一个新的函数 wrapped_func
。这个新函数在 hello_world
函数执行前后分别打印一条消息。我们可以看到,装饰器实际上是一个返回函数的函数。
函数签名保持
默认情况下,装饰器会“掩盖”掉原函数的名字和文档字符串。这是因为在装饰器内部,我们返回了一个全新的函数。我们可以使用 functools.wraps
来解决这个问题:
import functools
def decorator(func):
@functools.wraps(func)
def wrapper():
print(''Before function execution'')
func()
print(''After function execution'')
return wrapper
@decorator
def hello_world():
"Prints ''Hello, world!''"
print(''Hello, world!'')
print(hello_world.__name__)
print(hello_world.__doc__)
这样,使用装饰器后的函数名和文档字符串能够保持不变。
Python 装饰器的应用实例
装饰器在实际的 Python 编程中有许多应用场景,比如日志记录、性能测试、事务处理、缓存、权限校验等。
一个常见的应用就是使用装饰器进行日志记录:
import logging
def log_decorator(func):
logging.basicConfig(level=logging.INFO)
def wrapper(*args, **kwargs):
logging.info(f''Running "{func.__name__}" with arguments {args} and kwargs {kwargs}'')
result = func(*args, **kwargs)
logging.info(f''Finished "{func.__name__}" with result {result}'')
return result
return wrapper
@log_decorator
def add(x, y):
return x + y
这个装饰器记录了函数的名称,函数调用的参数,以及函数返回的结果。
装饰器链
Python 允许我们将多个装饰器应用到一个函数上,形成一个装饰器链。例如,我们可以同时应用日志装饰器和性能测试装饰器:
import time
import logging
from functools import wraps
def log_decorator(func):
logging.basicConfig(level=logging.INFO)
@wraps(func)
def wrapper(*args, **kwargs):
logging.info(f''Running "{func.__name__}" with arguments {args} and kwargs {kwargs}'')
result = func(*args, **kwargs)
logging.info(f''Finished "{func.__name__}" with result {result}'')
return result
return wrapper
def timer_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f''Function "{func.__name__}" took {end_time - start_time} seconds to run.'')
return result
return wrapper
@log_decorator
@timer_decorator
def add(x, y):
time.sleep(2)
return x + y
在这个例子中,@log_decorator
和 @timer_decorator
两个装饰器被同时应用到 add
函数上,它们分别负责记录日志和测量函数运行时间。
One More Thing: 自动注册装饰器
一个有趣的装饰器应用是自动注册。这个装饰器会在装饰函数时自动将函数添加到一个列表或字典中,这样我们就可以在程序的其他地方访问到这个列表或字典,知道有哪些函数被装饰过。
# 装饰器将函数注册到一个列表中
def register_decorator(func_list):
def decorator(func):
func_list.append(func)
return func
return decorator
# 自动注册函数
registered_functions = []
@register_decorator(registered_functions)
def foo():
pass
@register_decorator(registered_functions)
def bar():
pass
print(registered_functions) # 输出: [<function foo at 0x10d38d160>, <function bar at 0x10d38d1f0>]
这个装饰器可以用于自动注册路由、插件系统、命令行参数处理等场景,能够大大提高代码的灵活性和可扩展性。
总结
Python 装饰器是一种强大的工具,它可以让我们更有效地管理和组织代码。希望通过这篇文章,你能够更深入地理解装饰器的工作原理和用法,从而在你的项目中更好地使用装饰器。
如有帮助,请多关注
个人微信公众号:【Python全视角】
TeahLead_KrisChang,10+年的互联网和人工智能从业经验,10年+技术和业务团队管理经验,同济软件工程本科,复旦工程管理硕士,阿里云认证云服务资深架构师,上亿营收AI产品业务负责人。
GitHub如何更改URL,但不更改重新加载?
嘿,我注意到在浏览GitHub存储库时,它使用AJAX加载每个文件夹/文件。
我了解所有这些,我只是想知道他们如何更改URL。您可以使用JavaScript获取并设置URL吗?如果是这样,对于将基于JavaScript的网站的一部分添加为书签可能非常有用。(其中的几页,通过JavaScript在其中移动)
谢谢。
答案1
小编典典它在历史记录操作API中使用了新的push/ pop状态功能。
python 全栈开发,Day12(函数的有用信息,带参数的装饰器,多个装饰器装饰一个函数)
函数的执行时,*打散。
函数的定义时,*聚合。
from functools import wraps
def wrapper(f): # f = func1
@wraps(f)
def inner(*args,**kwargs): #聚合
#args (1,2,3)
''''''执行函数之前的相关操作''''''
ret = f(*args,**kwargs) # 打散 1,2,3
''''''执行函数之后的相关操作''''''
return ret
return inner
@wrapper # func1 = wrapper(func1) func1 = inner
def func1(*args): #args (1,2,3) 聚合
print(666)
return args
print(func1(*[1,2,3])) # inner(3,5) 打散
执行输出:
666
(1, 2, 3)
一、函数的有用信息
1.函数名 使用__name__方法获取
2.函数的解释 使用__doc___方法获取
举个例子
def func1():
"""
此函数是完成登陆的功能,参数分别是...作用。
:return: 返回值是登陆成功与否(True,False)
"""
print(666)
# print(func1.__name__)
# print(func1.__doc__)
return True
func1()
print(func1.__name__) #获取函数名
print(func1.__doc__) #获取函数名注释说明
执行输出:
666
func1
此函数是完成登陆的功能,参数分别是...作用。
:return: 返回值是登陆成功与否(True,False)
这个有什么用呢?比如日志功能,需要打印出谁在什么时间,调用了什么函数,函数是干啥的,花费了多次时间,这个时候,就需要获取函数的有用信息了
带装饰器的函数
def wrapper(f): # f = func1
def inner(*args,**kwargs): #聚合
#args (1,2,3)
''''''执行函数之前的相关操作''''''
ret = f(*args,**kwargs) # 打散 1,2,3
''''''执行函数之后的相关操作''''''
return ret
return inner
@wrapper
def func1():
"""
此函数是完成登陆的功能,参数分别是...作用。
:return: 返回值是登陆成功与否(True,False)
"""
print(666)
return True
func1()
print(func1.__name__)
print(func1.__doc__)
执行输出:
666
inner
执行函数之前的相关操作
咦?为什么输出了inner,我要的是func1啊。因为函数装饰之后,相当于执行了inner函数,所以输出inner
为了解决这个问题,需要调用一个模块wraps
wraps将 被修饰的函数(wrapped) 的一些属性值赋值给 修饰器函数(wrapper) ,最终让属性的显示更符合我们的直觉
完整代码如下:
from functools import wraps
def wrapper(f): # f = func1
@wraps(f) #f是被装饰的函数
def inner(*args,**kwargs): #聚合
#args (1,2,3)
''''''执行函数之前的相关操作''''''
ret = f(*args,**kwargs) # 打散 1,2,3
''''''执行函数之后的相关操作''''''
return ret
return inner
@wrapper
def func1():
"""
此函数是完成登陆的功能,参数分别是...作用。
:return: 返回值是登陆成功与否(True,False)
"""
print(666)
return True
func1()
print(func1.__name__)
print(func1.__doc__)
执行输出:
666
func1
此函数是完成登陆的功能,参数分别是...作用。
:return: 返回值是登陆成功与否(True,False)
二、带参数的装饰器
import time
def timmer(*args,**kwargs):
def wrapper(f):
print(args, kwargs) #接收第1步的值
def inner(*args,**kwargs):
if flag:
start_time = time.time()
ret = f(*args,**kwargs)
time.sleep(0.3)
end_time = time.time()
print(''此函数的执行效率%f'' % (end_time-start_time))
else:
ret = f(*args, **kwargs)
return ret
return inner
return wrapper
flag = True
@timmer(flag,2,3) # 两步:1,timmer(flag,2,3) 相当于执行wrapper 2.@wrapper 装饰器 func1 = wrapper(func1)
def func1(*args,**kwargs):
return 666
print(func1())
执行输出:
(True, 2, 3) {}
此函数的执行效率0.300183
666
代码分析
import time #1.加载模块
def timmer(*args,**kwargs): #2.加载变量 5.接收参数True,2,3
def wrapper(f): #6.加载变量 8.f = func1
print(args, kwargs) #9.接收timmer函数的值True,2,3
def inner(*args,**kwargs): #10.加载变量. 13.执行函数inner
if flag: #14 flag = True
start_time = time.time() #15 获取当前时间
ret = f(*args,**kwargs) #16 执行func1
time.sleep(0.3) #19 等待0.3秒
end_time = time.time() #20 获取当前时间
print(''此函数的执行效率%f'' % (end_time-start_time)) #21 打印差值
else:
ret = f(*args, **kwargs)
return ret #22 返回给函数调用者func1()
return inner #11 返回给函数调用者wrapper
return wrapper #7.返回给函数调用timmer(flag,2,3)
flag = True #3 加载变量
@timmer(flag,2,3) # 4.执行函数timmer(flag,2,3) 17.执行函数func1 两步:1,timmer(flag,2,3) 相当于执行wrapper 2.@wrapper 装饰器 func1 = wrapper(func1)
def func1(*args,**kwargs):
return 666 #18 返回给函数调用者f(*args,**kwargs)
print(func1()) #12 执行函数
假定现在有100个函数,都加上了装饰器,增加了显示函数执行时间的功能,现在需要去掉!
怎能办?一行行代码去删除吗?太low了。
这个时候,直接在装饰器函数加一个参数即可。
import time
flag = True
def wrapper(f):
def inner(*args,**kwargs):
if flag:
start_time = time.time()
ret = f(*args,**kwargs)
time.sleep(0.3)
end_time = time.time()
print(''此函数的执行效率%f'' % (end_time-start_time))
else:
ret = f(*args, **kwargs)
return ret
return inner
@wrapper
def func1(*args,**kwargs):
print(args,kwargs)
return 666
print(func1())
执行输出:
此函数的执行效率0.300431
666
现在需要关闭显示执行时间
直接将flag改成false
import time
flag = False
def wrapper(f):
def inner(*args,**kwargs):
if flag:
start_time = time.time()
ret = f(*args,**kwargs)
time.sleep(0.3)
end_time = time.time()
print(''此函数的执行效率%f'' % (end_time-start_time))
else:
ret = f(*args, **kwargs)
return ret
return inner
@wrapper
def func1(*args,**kwargs):
print(args,kwargs)
return 666
print(func1())
执行输出:
() {}
666
这样,所有调用的地方,就全部关闭了,非常方便
写装饰器,一般嵌套3层就可以了
a = 5
def func1():
a += 1
print(a)
func1()
执行报错
这里函数对全局变量做了改变,是不允许操作的。
函数内部可以引用全局变量,不能修改。如果要修改,必须要global一下
a = 5
def func1():
global a
a += 1
print(a)
func1()
执行输出6
三、多个装饰器,装饰一个函数
def wrapper1(func): # func == f函数名
def inner1():
print(''wrapper1 ,before func'') # 2
func()
print(''wrapper1 ,after func'') # 4
return inner1
def wrapper2(func): # func == inner1
def inner2():
print(''wrapper2 ,before func'') # 1
func()
print(''wrapper2 ,after func'') # 5
return inner2
@wrapper2 # f = wrapper2(f) 里面的f==inner1 外面的f == inner2
@wrapper1 # f = wrapper1(f) 里面的f==函数名f 外面的f == inner1
def f(): # 3
print(''in f'')
f() # inner2()
执行输出:
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
哪个离函数近,哪个先计算
最底下的先执行
执行顺序如下图:
多个装饰器,都是按照上图的顺序来的
今日作业:
1.写函数,返回一个扑克牌列表,里面有52项,每一项是一个元组
例如:[(''红心'',2),(''草花'',2), …(''黑桃'',''A'')]
2.写函数,传入n个数,返回字典{''max'':最大值,''min'':最小值}
例如:min_max(2,5,7,8,4)
返回:{''max'':8,''min'':2}
3.写函数,专门计算图形的面积
其中嵌套函数,计算圆的面积,正方形的面积和长方形的面积
调用函数area(''圆形'',圆半径) 返回圆的面积
调用函数area(''正方形'',边长) 返回正方形的面积
调用函数area(''长方形'',长,宽) 返回长方形的面积
def area():
def 计算长方形面积():
pass
def 计算正方形面积():
pass
def 计算圆形面积():
pass
4.写函数,传入一个参数n,返回n的阶乘
例如:cal(7)
计算7*6*5*4*3*2*1
5、编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果(升级题)
5.1.为题目3编写装饰器,实现缓存网页内容的功能:(升级题)
具体:实现下载的页面存放于文件中,如果网页有对应的缓存文件,就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
6给每个函数写一个记录日志的功能,
功能要求:每一次调用函数之前,要将函数名称,时间节点记录到log的日志中。
所需模块:
import time
struct_time = time.localtime()
print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time))
7、编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
8,在编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码。这个作业之上进行升级操作:
设置两套密码,一套为京东账号密码,一套为淘宝账号密码保存在文件中。
设置四个函数,分别代表 京东首页,京东超市,淘宝首页,淘宝超市。
循环打印四个选项:东首页,京东超市,淘宝首页,淘宝超市。
供用户选择,用户输入选项后,执行该函数,四个函数都加上认证功能,只要登陆成功一次,在选择其他函数,后续都无需输入用户名和密码。
相关提示:用带参数的装饰器。装饰器内部加入判断,验证不同的账户密码。
答案:
1.写函数,返回一个扑克牌列表,里面有52项,每一项是一个元组
例如:[(''红心'',2),(''草花'',2), …(''黑桃'',''A'')]
1.1准备基础数据
#颜色
colour = [''黑桃♠'',''红心♥'',''梅花♣'',''方块♦'']
#牌面的值
card = list(range(2,11))+[''A'',''J'',''Q'',''K'']
1.2使用for循环遍历
#颜色
colour = [''黑桃♠'',''红心♥'',''梅花♣'',''方块♦'']
#牌面的值
card = list(range(2,11))+[''A'',''J'',''Q'',''K'']
for i in card:
for j in colour:
print((j,i))
执行输出:
(''黑桃♠'', 2)
(''红心♥'', 2)
(''梅花♣'', 2)
...
1.3 封装成函数
#颜色
colour = [''黑桃♠'',''红心♥'',''梅花♣'',''方块♦'']
#牌面的值
card = list(range(2,11))+[''A'',''J'',''Q'',''K'']
def poker(*args,**kwargs):
show_card = []
for i in kwargs[''card'']:
for j in kwargs[''colour'']:
show_card.append((j, i))
return show_card
print(poker(colour=colour,card=card))
执行输出:
[(''黑桃♠'', 2), (''红心♥'', 2), (''梅花♣'', 2),...]
老师的代码:
def func(li):
l = []
for i in li:
#用1~13表示13张牌
for j in range(1,14):
l.append((i,j))
return l
print(func([''草花'', ''黑桃'', ''红桃'', ''方片'']))
思考题,在上述代码的基础上修改一下
A用1表示,2~10表示数字牌,JQK分别表示11,12,13
代码如下:
def func(li):
l = []
for i in li:
#A用1表示,2~10表示数字牌,JQK分别表示11,12,13
for j in range(1,14):
if j == 1:
j = ''A''
elif j == 11:
j = ''J''
elif j == 12:
j = ''Q''
elif j == 13:
j = ''K''
l.append((i,j))
return l
print(func([''草花'', ''黑桃'', ''红桃'', ''方片'']))
2.写函数,传入n个数,返回字典{''max'':最大值,''min'':最小值}
例如:min_max(2,5,7,8,4)
返回:{''max'':8,''min'':2}
2.1使用内置函数,可以得出最大和最小值
a = (1,2,3)
b = {''k1'':1,''k2'':2}
print(max(a))
print(min(b.values()))
执行输出:
3
1
2.2封装成函数
def min_max(*args,**kwargs):
dic = {''max'':None,''min'':None}
number = []
#循环位置变量
for i in args:
for j in i:
number.append(j)
# 循环关键字变量
for k in kwargs.values():
number.append(k)
#最大值和最小值
dic[''max''] = max(number)
dic[''min''] = min(number)
return dic
print(min_max([2,6,7,8,3,7,678,3,432,6547],a=1))
执行输出:
{''min'': 1, ''max'': 6547}
老师的代码:
def func2(*args):
return {''max'':max(args), ''min'':min(args)}
print(func2(1,2,3,4,5))
3.写函数,专门计算图形的面积
其中嵌套函数,计算圆的面积,正方形的面积和长方形的面积
调用函数area(''圆形'',圆半径) 返回圆的面积
调用函数area(''正方形'',边长) 返回正方形的面积
调用函数area(''长方形'',长,宽) 返回长方形的面积
def area():
def 计算长方形面积():
pass
def 计算正方形面积():
pass
def 计算圆形面积():
pass
先找出公式
长方形面积公式
S = ab
公式描述:公式中a,b分别为长方形的长和宽,S为长方形的面积。
正方形面积公式
S = a²
公式描述:公式中a为正方形边长,S为正方形面积。
圆的面积公式
S = πr²
公式描述:公式中r为圆的半径,π用3.14表示
写函数雏形
def area(*args,**kwargs):
#计算长方形面积
def rectangle(*args,**kwargs):
pass
#计算正方形面积
def square(*args,**kwargs):
pass
#计算圆形面积
def circular(*args,**kwargs):
pass
print(args)
ret = area(''长方形'', ''长'',''宽'')
print(ret)
执行输出:
(''长方形'', ''长'', ''宽'')
None
填补函数
def area(*args,**kwargs):
#计算长方形面积
def rectangle(*args,**kwargs):
#print(args)
return args[0] * args[1]
#计算正方形面积
def square(*args,**kwargs):
return args[0] ** 2
#计算圆形面积
def circular(*args,**kwargs):
return 3.14 * (args[0] ** 2)
#判断参数
if args[0].strip() == ''长方形'':
return rectangle(args[1],args[2])
elif args[0].strip() == ''正方形'':
return square(args[1])
elif args[0].strip() == ''圆形'':
return circular(args[1])
else:
return ''参数不正确!''
ret1 = area(''长方形'',3,4)
ret2 = area(''正方形'',5)
ret3 = area(''圆形'',6)
print(ret1)
print(ret2)
print(ret3)
执行输出:
12
25
113.04
老师的代码:
def area(*args):
#判断参数
if args[0] == ''长方形'':
def 计算长方形面积():
s = args[1]*args[2]
return s
return 计算长方形面积()
elif args[0] == ''正方形'':
def 计算正方形面积():
s = args[1] ** 2
return s
return 计算正方形面积()
elif args[0] == ''圆形'':
def 计算圆形面积():
s = 3.14 * (args[1] ** 2)
return s
return 计算圆形面积()
print(area(''长方形'',2,3))
print(area(''正方形'',5))
print(area(''圆形'',6))
4.写函数,传入一个参数n,返回n的阶乘
例如:cal(7)
计算7*6*5*4*3*2*1
4.1先用range输出倒序的数字
range(开始,结束,步长)
默认步长为1,如果为-1,表示倒序
for i in range(7,0,-1):
print(i)
执行输出:
7
6
5
4
3
2
1
4.2封装函数
def cal(*args,**kwargs):
ret = 1
for i in range(args[0],0,-1):
ret *= i
return ret
print(cal(7))
执行输出:
5040
老师的代码:
def func3(n):
count = 1
for i in range(n,0,-1):
count = count * i
return count
print(func3(7))
5、编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果(升级题)
5.1.为题目3编写装饰器,实现缓存网页内容的功能:(升级题)
具体:实现下载的页面存放于文件中,如果网页有对应的缓存文件,就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
import urllib.request
import os
import time
def download_index(*args, **kwargs):
flag = False
def inner():
if os.path.isfile(''download.txt'') == flag:
for i in args:
url = ''https://'' + str(i)
response = urllib.request.urlopen(url).read().decode(''utf-8'')
time.sleep(1)
with open(''download.txt'', encoding=''utf-8'', mode=''w'') as f2:
f2.write(response)
return response
else:
with open(''download.txt'', encoding=''utf-8'', mode=''r'') as f3:
#print(inner.__closure__)
return f3.read()
return inner
print(download_index(''www.baidu.com'')())
执行输出:
<html>
<head>
<script>
...
</html>
6.给每个函数写一个记录日志的功能,
功能要求:每一次调用函数之前,要将函数名称,时间节点记录到log的日志中。
所需模块:
import time
struct_time = time.localtime()
print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time))
6.1准备示例函数
import time
def func1():
"""
此函数是测试的
:return:
"""
print(666)
time.sleep(0.3)
return True
func1()
print(func1.__name__)
print(func1.__doc__)
执行输出:
666
func1
此函数是测试的
:return:
准备装饰器模板
def wrapper(f):
def inner(*args,**kwargs):
''''''被装饰函数之前''''''
ret = f(*args,**kwargs)
''''''被装饰函数之后''''''
return ret
return inner
补充装饰器,完整代码如下:
import time
def wrapper(f):
def inner(*args,**kwargs):
''''''被装饰函数之前''''''
ret = f(*args,**kwargs)
''''''被装饰函数之后''''''
#标准时间
struct_time = time.localtime()
standard_time = time.strftime("%Y-%m-%d %H:%M:%S",struct_time)
print(''函数名称:{} 时间节点:{}\n''.format(f.__name__,standard_time))
return ret
return inner
@wrapper
def func1():
"""
此函数是测试的
:return:
"""
print(666)
time.sleep(0.3)
return True
func1()
执行输出:
666
函数名称:func1 时间节点:2018-04-02 16:25:05
增加写入日志功能
import time
def wrapper(f):
def inner(*args,**kwargs):
''''''被装饰函数之前''''''
ret = f(*args,**kwargs)
''''''被装饰函数之后''''''
#标准时间
struct_time = time.localtime()
standard_time = time.strftime("%Y-%m-%d %H:%M:%S",struct_time)
#写入日志
with open(''function_log.txt'',encoding=''utf-8'',mode=''a+'') as f1:
f1.write(''函数名称:{} 时间节点:{}\n''.format(f.__name__,standard_time))
return ret
return inner
@wrapper
def func1():
"""
此函数是测试的
:return:
"""
print(666)
time.sleep(0.3)
return True
func1()
多执行几次程序,查看日志文件function_log.txt
老师的代码:
def wrapper(func):
def inner(*args, **kwargs):
struct_time = time.localtime()
time_now = time.strftime("%Y-%m-%d %H:%M:%S", struct_time)
with open(''log'', encoding=''utf-8'', mode=''a'') as f1:
f1.write(''在时间是%s,执行了%s函数\n'' % (time_now, func.__name__))
ret = func(*args, **kwargs)
''''''函数执行之后操作''''''
return ret
return inner
@wrapper
def func1():
time.sleep(1)
print(555)
@wrapper
def func2():
time.sleep(2)
print(666)
func1()
func2()
思考题
执行func1和func2必须登录,才能执行。函数执行之后,记录日志
时间: xx年xx月xx日 xx 执行了 xx 函数
代码如下:
import time
dic = {
''username'':None,
''status'':False,
}
#错误次数
i = 0
def wrapper(func):
def inner(*args, **kwargs):
# 判断登录状态是否为True
if dic[''status'']:
# 执行被装饰行函数
ret = func(*args, **kwargs)
return ret
else:
# 这里需要修改全局变量,要global一下
global i
while i < 3:
username = input(''请输入用户名:'').strip()
password = input(''请输入密码:'').strip()
with open(''register_msg'', encoding=''utf-8'') as f1:
for j in f1:
j_li = j.strip().split() # [''张三'',''123'']
if username == j_li[0] and password == j_li[1]:
# 修改全局变量
dic[''username''] = username
dic[''status''] = True
struct_time = time.localtime()
time_now = time.strftime("%Y-%m-%d %H:%M:%S", struct_time)
with open(''log'', encoding=''utf-8'', mode=''a'') as f1:
f1.write(''时间:%s %s执行了 %s函数\n'' % (time_now,username,func.__name__))
ret = func(*args, **kwargs)
return ret
else:
print(''账号或者密码错误,请重新输入%s机会'' % (2 - i))
i += 1
''''''函数执行之后操作''''''
#return ret
return inner
@wrapper
def func1():
time.sleep(0.4)
print(555)
@wrapper
def func2():
time.sleep(0.5)
print(666)
func1()
func2()
执行输出:
查看日志
7、编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
7.1 准备函数雏形
def check_login(func): #检查登陆的装饰器
def inner(*args,**kwargs):
''''''函数被装饰之前''''''
ret = func(*args,**kwargs)
''''''函数被装饰之后''''''
return ret
return inner
def index():
print("welcome to index page")
@check_login
def home(): #用户主页
print("welcome to home page")
@check_login
def bbs(): #bbs页面
print("welcome to bbs page")
填补代码,完整代码如下:
import os
#文件名
file_name = ''user_list.txt''
#用户状态
user_status = {''username'':None,''status'':False}
def check_login(func): #检查登陆的装饰器
def inner(*args,**kwargs):
#print(user_status[''status''])
if user_status[''status'']:
r = func(*args,**kwargs)
return r
else:
print("\033[41;1m请先登录!\033[0m")
#返回首页
index()
return inner
#首页
def index():
print("welcome to index page")
global user_status
while True:
username = input("username:").strip()
password = input("password:").strip()
# 判断文件是否存在
if os.path.exists(file_name) == False:
with open(file_name, encoding=''utf-8'', mode=''w'') as mk:
mk.write(''xiao 123'')
with open(file_name, encoding=''utf-8'', mode=''r'') as f1:
for i in f1:
# 去空格,以空格切割,转换为列表
li = i.strip().split() # [张三,123]
# 判断用户名和密码是否匹配
if username == li[0] and password == li[1]:
result = True
# 当找到匹配时,跳出循环
break
else:
result = False
# 当整个用户列表遍历完成之后,再判断result
if result:
#更改全局变量
user_status[''username''] = username
user_status[''status''] = True
break
else:
print(''用户名和密码不正确,请重新输入'')
@check_login
def home(): #用户主页
print("welcome to home page")
@check_login
def bbs(): #bbs页面
print("welcome to bbs page")
index()
home()
bbs()
执行输出:
老师的代码:
必须提前创建好文件register_msg,默认内容为''张三 123''
#全局变量,用户状态
dic = {
''username'':None,
''status'':False,
}
#错误次数
i = 0
def wrapper(func):
def inner(*args, **kwargs):
#判断登录状态是否为True
if dic[''status'']:
#执行被装饰行函数
ret = func(*args, **kwargs)
return ret
else:
#这里需要修改全局变量,要global一下
global i
while i < 3:
username = input(''请输入用户名:'').strip()
password = input(''请输入密码:'').strip()
with open(''register_msg'',encoding=''utf-8'') as f1:
for j in f1:
j_li = j.strip().split() # [''张三'',''123'']
if username == j_li[0] and password == j_li[1]:
#修改全局变量
dic[''username''] = username
dic[''status''] = True
ret = func(*args, **kwargs)
return ret
else:
print(''账号或者密码错误,请重新输入%s机会'' % (2-i))
i += 1
return inner
@wrapper
def article():
print(''文章'')
@wrapper
def diary():
print(''日记'')
@wrapper
def comment():
print(''评论'')
@wrapper
def file():
print(''文件'')
article()
diary()
comment()
file()
8,在编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码。这个作业之上进行升级操作:
设置两套密码,一套为京东账号密码,一套为淘宝账号密码保存在文件中。
设置四个函数,分别代表 京东首页,京东超市,淘宝首页,淘宝超市。
循环打印四个选项:东首页,京东超市,淘宝首页,淘宝超市。
供用户选择,用户输入选项后,执行该函数,四个函数都加上认证功能,只要登陆成功一次,在选择其他函数,后续都无需输入用户名和密码。
相关提示:用带参数的装饰器。装饰器内部加入判断,验证不同的账户密码。
不废话,直接贴代码
# -*- coding: utf-8 -*-
import os
#文件名
file_jd = ''jd.txt''
file_taobao = ''taobao.txt''
#用户状态
user_status = {''username'':None,''status'':False,''user_type'':None}
def username_password(file_name,username,password):
''''''
#判断用户名和密码是否匹配
:param username: 用户名
:param password: 密码
:return: True 匹配成功 False 匹配失败
''''''
if username == '''' or password == '''':
return ''用户名或者密码不能为空!''
with open(file_name, encoding=''utf-8'', mode=''r'') as f3:
for i in f3:
# print(i)
# 去空格,以空格切割,转换为列表
li = i.strip().split() # [张三,123]
# 判断用户名和密码是否匹配
if username == li[0] and password == li[1]:
result = True
#result = {''msg'':True,''level'':li[2]}
# 当找到匹配时,跳出循环
break
else:
result = False
#result = {''msg'': False, ''level'': li[2]}
# 当整个用户列表遍历完成之后,再return
return result
def check_login(func): #检查登陆的装饰器
def inner(*args,**kwargs):
if user_status[''status'']:
r = func(*args,**kwargs)
return r
else:
print("\033[41;1m请先登录!\033[0m")
#返回首页
login()
func(*args, **kwargs)
return inner
def login(): #登录程序
global user_status
while True:
print(''请选择用户类型\n1.京东帐户\n2.淘宝账户\n'')
user_type = input(''请输入编号: '').strip()
if user_type == ''1'' or user_type == ''2'':
break
else:
print("\033[41;1m输入错误,请重新输入!\033[0m")
while True:
username = input(''请输入用户名,或输入q返回主页:'').strip()
if username.upper() == ''Q'':
index()
if username == '''':
print("\033[41;1m用户名不能为空!\033[0m")
password = input(''请输入密码:'').strip()
if password == '''':
print("\033[41;1m密码不能为空!\033[0m")
if username != '''' and password != '''':
#break
# 判断文件是否存在
if os.path.exists(file_jd) == False or os.path.exists(file_taobao) == False:
with open(file_jd, encoding=''utf-8'', mode=''w'') as f_jd:
f_jd.write(''xiao 123'')
with open(file_taobao, encoding=''utf-8'', mode=''w'') as f_taobao:
f_taobao.write(''tao 123'')
if user_type == ''1'':
file_name = file_jd
user_type = ''京东帐户''
else:
file_name = file_taobao
user_type = ''淘宝帐户''
# 执行验证用户名和密码函数
#print(file_name,username, password)
result = username_password(file_name,username, password)
if result:
print(''登陆成功!\n'')
user_status[''username''] = username
user_status[''status''] = True
user_status[''user_type''] = user_type
index()
else:
print("\033[41;1m用户名或密码错误!\033[0m")
#首页
def index():
menu = [''京东首页'',''京东超市'',''淘宝首页'',''淘宝超市'',''退出'']
#菜单函数名对照表
menu_func = [''jd_index'',''jd_supermarket'',''taobao_index'',''taobao_supermarket'',''exit'']
print("꧁欢迎访问购物商城꧂".center(30,''❀''))
status = ''在线'' if user_status[''status''] == True else ''未登录''
info = ''\n当前登陆用户:{} 状态: {} 用户类型:{}\n''.format(user_status[''username''], status, user_status[''user_type''])
print(info.rjust(15))
for i in range(len(menu)):
print(''{}\t{}''.format(i + 1, menu[i]))
print("".center(35, ''☪''))
while True:
number = input("请输入序号:").strip()
if number.isdigit():
number = int(number)
if number > 0 and number <= len(menu):
#执行菜单函数
eval(menu_func[number-1])()
else:
print(''输入错误,请重新输入!'')
@check_login
def jd_index(): #京东首页
#print("欢迎访问 京东首页")
print("\033[32m欢迎访问 京东首页\033[0m")
@check_login
def jd_supermarket(): #京东超市
#print("欢迎访问 京东超市")
print("\033[32m欢迎访问 京东超市\033[0m")
@check_login
def taobao_index(): #淘宝首页
#print("欢迎访问 淘宝首页")
print("\033[32m欢迎访问 淘宝首页\033[0m")
@check_login
def taobao_supermarket(): #淘宝超市
#print("欢迎访问 淘宝超市")
print("\033[32m欢迎访问 淘宝超市\033[0m")
#执行函数
if __name__ == ''__main__'':
index()
执行输出:
老师的代码:
dic = {
''username'':None,
''status'':False,
}
i = 0
def login(flag):
def wrapper(func):
def inner(*args, **kwargs):
#判断用户状态是否为True
if dic[''status'']:
ret = func(*args, **kwargs)
return ret
else:
global i
while i < 3:
username = input(''请输入用户名(用%s账号):'' % flag).strip()
password = input(''请输入密码:'').strip()
with open(''user_pwd'',encoding=''utf-8'') as f1:
#读取一行,因为文件只有一行内容
msg_dic = eval(f1.readline())
# {''微信'': {''password'': ''123'', ''username'': ''老男孩''}, ''qq'': {''password'': ''123'', ''username'': ''老男孩1''}}
if username == msg_dic[flag][''username''] and password == msg_dic[flag][''password'']:
#修改全局变量,这里不用global,因为它是可变类型
dic[''username''] = username
dic[''status''] = True
#执行被装饰的函数
ret = func(*args, **kwargs)
return ret
else:
print(''您输入的用户或者密码错误,请重新输入,还有%s次机会'' % (2-i))
i += 1
return inner
return wrapper
@login(''微信'')
def taobao_home():
print(''淘宝首页'')
@login(''微信'')
def taobao_shop():
print(''淘宝超市'')
@login(''qq'')
def jingdong_home():
print(''京东首页'')
@login(''qq'')
def jingdong_shop():
print(''京东超市'')
#菜单列表,建议使用此方式
choice_dict = {
#序号:函数名
1: taobao_home,
2: taobao_shop,
3: jingdong_home,
4: jingdong_shop,
5: exit,
}
while True:
print(''1 淘宝首页\n2 淘宝超市\n3 京东首页\n4 京东超市\n5 退出'')
choice_num = input(''请选择输入的序号:'').strip()
if choice_num.isdigit():
choice_num = int(choice_num)
#判断数字范围
if 0 < choice_num <= len(choice_dict):
#执行函数
choice_dict[choice_num]()
else:
print(''请输入范围内的序号'')
else:
print(''您输入的有非法字符,请重新输入'')
执行输出:
关于如何更改函数行为,但不更改 python - 装饰器中的函数?和python中修改函数的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于49 Python - 装饰器 函数定义装饰器、< Python全景系列-9 > Python 装饰器:优雅地增强你的函数和类、GitHub如何更改URL,但不更改重新加载?、python 全栈开发,Day12(函数的有用信息,带参数的装饰器,多个装饰器装饰一个函数)的相关知识,请在本站寻找。
本文标签: