函数回顾

1.函数可以当做一个参数赋值给另一个函数:

def func():
print("in the func") def foo(x):
x()
foo(func)

输出:

in the func

2.函数可以设置为变量形式,函数可以被当做数据来传递:

def func():
print("in the func") f1 = func
f1()

输出:

in the func

3.返回值可以是函数

def func():
print("in the func") def foo():
return func res = foo() #res = func
res() #res() = func()

输出:

in the func

4.可以做容器类型的元素(列表,元组,字典)

def func():
print("in the func") def abc():
print("in the abc") func_dic={
"func":func,
"abc":abc,
} func_dic["func"]() # func() 通过字典取值的形式执行函数
func_dic["abc"]() # abc()

输出:

in the func
in the abc

嵌套调用

在一个函数的内部调用另外一个函数;

例:比较四个值的大小:

def my_max4(a, b, c, d):
res1 = my_max2(a, b)
res2 = my_max2(res1, c)
res3 = my_max2(res2, d)
return res3 def my_max2(x, y):
if x > y:
return x
else:
return y print(my_max4(100, 5000, -1, 10))

输出:

5000

嵌套定义

在函数的内部,又定义一个函数:

x = 1

def f1():
def f2():
print(x)
return f2
f2 = f1()
f2()

名称空间于作用域

1.名称空间种类

  1. 内置名称空间:在python解释器启动时产生,存放python内置的名字
  2. 全局名称空间:在执行文件时产生,存放文件级别定义的名字(全局变量),程序结束时释放
  3. 局部名称空间:在执行文件的过程中,如果调用了函数,则会产生该函数的名称空间,用来存放该函数内部定义的名字,该函数在函数调用时生效,韩式调用结束后失效。

2.名称空间,加载顺序

内置-->全局-->局部

3.名称空间,取值加载顺序

局部-->全局-->内置

4.作用域即范围

  1. 全局范围:全局存活,全局有效
  2. 局部范围:临时存活,局部有效
  3. 作用域关系是在函数定义阶段以及固定的,与函数的调用位置无关

1.查看局部作用域的名字 locals()

def func():
print("in the func")
a = 1
b = 2
c = 5
def foo():
pass
print(locals()) def foo(x):
x() foo(func)

输出:

{'a': 1, 'c': 5, 'b': 2, 'foo': <function func.<locals>.foo at 0x00000254BFD698C8>}

2.查看全局作用域的名字 globals()

def func():
print("in the func")
a = 1
b = 2
c = 5
def foo():
pass
# print(locals()) def foo(x):
x() foo(func)
print(globals())

输出:

{'__package__': None, '__spec__': None, '__doc__': None, 'func': <function func at 0x00000254BFD696A8>, '__builtins__': <module 'builtins' (built-in)>, 'foo': <function foo at 0x00000254BFD69840>, '__name__': '__main__', '__cached__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000254BFD07AC8>, '__file__': 'C:/Users/PycharmProjects/Py/da/笔记/作用域.py'}

5.局部内修改全局变量值global (尽量不要在局部中修改全局变量值)

x = 1
def f1():
global x
x =10
f1()
print(x)

输出:

10

6.作用域关系,在函数定义时就已经固定,于调用位置无关

1.在第一次打印x值时取值为定义时固定的 x = 1,第二次时全局的x已经被修改为500所以值为500;

x=1
def f1():
def f2():
print(x)
return f2 func = f1() def foo(func):
x = 1000
func() foo(f1())
x = 500
foo(f1())

输出

1
500

闭包函数

在内部函数当中,有对外部函数名字的引用;(对外部作用域,不是全局作用域)

1.将x = 1 隐藏在了函数f2中,只有在调用执行时才会被引用;且不受全局变量的影响

x = 1000             # 全局作用域
def f1():
x = 1 # 外部作用域 (关键的闭包值)
def f2():
print(x)
return f2
f = f1()
f()

输出:

1

2.将baidu的网页爬下来,先存储起来使用的时候,直接调用baidu()即可:

import requests
##导入模块页面爬取request def page(url):
# url = http://www.baidu.com
def get():
print(requests.get(url).text)
return get baidu = page("http://www.baidu.com")
baidu()
print(baidu.__closure__[0].cell_contents) # 查看闭包函数包过的值(http://www.baidu.com)

装饰器实现原则

1.一定不能修改源代码

2.不能修改调用方式

3.装饰器本身也是一个函数

4.遵循开放封闭原则

装饰器的语法是:

在你需要装饰的函数正上方一行使用@符号写上装饰器的名字;

被装饰者"a",装饰器名字为 timer函数

1.在index函数和home函数上面添加一个计算程序运行时间的计算,但是不改变index的调用方式

import time
def times(func): # 运行times(func)函数
def f1():
start = time.time()
func()
stop = time.time()
print(stop-start)
return f1 # 将times得到的值 f1() 返回给 index @times
def home():
time.sleep(2)
print("from in home!") @times # index = times(index) 运行times()函数,并把 index()函数值传入进去
def index():
time.sleep(3)
print("from in index") home()
index()

输出:

from in home!
2.000453233718872
from in index
3.0009102821350098

2.有参装饰器当index函数有调用方式的时候,@timer函数需要使用不定长参数来表示(*args, **kwargs);

def timer(index):
def abc(*args, **kwargs):
print("in the abc")
index(*args, **kwargs)
return abc @timer # index = timer(index)
def index(user, age):
print("in the index %s %s" % (user, age)) index("tom", age="19")

3.返回值装饰器当home函数有返回值时,@times函数内部同时需要返回home的返回值

import time

def times(func):
def f1(*args,**kwargs): # 因为会将值传到 f1函数来接收所以使用 *args,**kwargs 接收
start = time.time()
res = func(*args,**kwargs) # 并将接收到的参数,全部转发给 func() 函数
stop = time.time()
print(stop-start)
return res # 将的到的返回值返回给 home函数
return f1 @times
def home(name): # home()函数有返回值
time.sleep(2)
print("from %s in home!" % name) @times
def index():
time.sleep(3)
print("from in index") home("lin") # 在这里在执行home("lin") 函数是,就是在执行 f1(*args,**kwargs)
index()

输出:

from lin in home!
2.0006303787231445
from in index
3.0005226135253906

4.让用户输入用户密码,如果用户密码正确,方可执行调用函数:

user_l = {"user":None}                                    # 定义一个空字典,用来存放已登录的用户,如果有值,无需在次登录

def auth(func):
def f1(*args, **kwargs):
if user_l["user"]: # 判断user_l字典中是否有值
res = func(*args,**kwargs)
return res
name = input("输入你的名字:")
pwd = input("输入你的密码:")
with open("db.txt","r",encoding="utf-8") as f: # 从文件db.txt 读取用户信息
date_dic = eval(f.read()) # 将用户信息转为字典格式
if name in date_dic and pwd == date_dic[name]: # 判断用户输入内容和字典取值是否相同
res = func(*args,**kwargs)
user_l["user"]=name
return res
else:
print("用户或密码ERROR")
return f1 @auth
def home(name):
print("from %s in home" % name) @auth
def index():
print("from in index!") index()
home("lin")

db.txt内容

{"zhangsan":"123","wangwu":"456","zhaoliu":"789"}

输出:

输入你的名字:zhangsan
输入你的密码:123
from in index!
from lin in home

有参装饰器

1.当用户输入指定登录时,使用什么方式验证;不同的验证参数使用不同的验证方法;

判断用户如果选择“file”方式登录,需要让用户输入用户密码,如果选择“ldap”方式登录直接登录!

user_l = {"user":None}

def canshu(auth_type="file"):                    # 在最外层包过一个用户传来的验证方式,默认为“file”
def auth(func):
# func = index
def f1(*args,**kwargs):
if auth_type == "file": # 获取用户传入的auth_type 参数 判断是否为 file
if user_l["user"]:
res = func(*args,**kwargs)
return res
name = input("输入你的名字:")
pwd = input("输入你的秘密:") with open("db.txt","r",encoding="utf-8") as f:
data_dic = eval(f.read())
if name in data_dic and pwd == data_dic[name]:
res = func(*args,**kwargs)
user_l["user"] = name
return res
else:
print("用户名或密码ERROR!")
elif auth_type == "mysql":
print("auth mysql!")
elif auth_type == "ldap":
print("auth ldap")
else:
print("auth ERROR")
return f1
return auth @canshu(auth_type="file") # canshu(file) --->@auth -- > f1()
def home(name):
print("from %s in home" % name) home("lin") # 最终执行 f1()

db.txt内容

{"zhangsan":"123","wangwu":"456","zhaoliu":"789"}

输出:

输入你的名字:zhangsan
输入你的秘密:123
from lin in homepython

使用装饰器时,显示源函数调用方式的帮助信息

import time
import functools # 用于使用装饰器时,展示源函数的 帮助信息 def times(func):
@functools.wraps(func) # 在最装饰器最内层的函数 上面加上 @functools.wraps(func) 并把 func 传进来
def f1(*args,**kwargs):
start = time.time()
func(*args,**kwargs)
stop = time.time()
print(stop-start)
return f1 @times
def home(name):
'''
这是home的帮助信息!
:return:
'''
time.sleep(3)
print("from %s in home" % name) print(home.__doc__) # 打印函数的注释信息
home("lin")

输出:

    这是home的帮助信息!
:return: from lin in home
3.0001637935638428

装饰器上面在套用装饰器,达到多次装饰的目的

1.在计算程序运行时间的装饰器上,在加一个验证装饰器

import time
import functools # 用于使用装饰器时,展示源函数的 帮助信息
user_l = {"user":None} def times(func):
@functools.wraps(func) # 在每个最装饰器最内层的函数 上面加上 @functools.wraps(func) 并把 func 传进来
def f1(*args,**kwargs):
start = time.time()
func(*args,**kwargs)
stop = time.time()
print(stop-start)
return f1 def canshu(auth_type="file"):
def auth(func):
@functools.wraps(func) # 在每个最装饰器最内层的函数 上面加上 @functools.wraps(func) 并把 func 传进来
def f1(*args, **kwargs):
if auth_type == "file":
if user_l["user"]:
res = func(*args,**kwargs)
return res
name = input("输入你的名字:")
pwd = input("输入你的密码:")
with open("db.txt","r",encoding="utf-8") as f:
date_dic = eval(f.read())
if name in date_dic and pwd == date_dic[name]:
res = func(*args,**kwargs)
user_l["user"]=name
return res
else:
print("用户或密码ERROR")
elif auth_type == "mysql":
print("mysql auth") elif auth_type == "ldap":
print("ldap auth")
else:
print("auth ERROR")
return f1
return auth @canshu() # 哪个装饰器写在上面先运行哪个装饰器 先运行验证装饰器
@times # 后运行计时装饰器
def home(name):
'''
这是home的帮助信息!
:return:
'''
time.sleep(3)
print("from %s in home" % name) print(home.__doc__) # 打印函数的注释信息
home("lin")

输出:


这是home的帮助信息!
:return: 输入你的名字:zhangsan
输入你的密码:123
from lin in home
3.000636339187622

装饰器练习(巩固加深)

1.编写日志装饰器,实现功能如:一旦函数index执行,则将消息2017-07-24 22:11:17 index run写入到日志文件中,日志文件路径可以指定(装饰器2017-07-24.log)

import os, time

def logger(logfile):
def deco(func):
if not os.path.exists(logfile): # 判断 日志文件 “装饰器2017-07-24.log” 是否存在
with open(logfile, "w"): pass # 不存在创建 文件 def f1(*args, **kwargs):
res = func(*args, **kwargs)
with open(logfile, "a", encoding="utf-8") as f:
f.write("%s %s run\n" % (time.strftime("%Y-%m-%d %X"), func.__name__)) # 将当前时间 文件名记录到文件中
return res
return f1
return deco time_date = time.strftime('%Y-%m-%d') @logger(logfile="装饰器" + time_date + ".log") # 传入日志文件名 日期格式 “装饰器2017-07-24.log”
def index():
print("index") index()

2.将爬取的站点,存入依照URL的md5值命名的文件中用于缓存,下次用户在访问时,可以从文件中直接读取数据返回。

import requests, os, hashlib

settings = {                                # 定义字典格式的 缓存 存放格式 选择
"file": {"dirname": "./db", # db 目录需要提前创建
},
"mysql": {
"host": "127.0.0.1",
"port": 3306,
"user": "root",
"password": "123",
},
"redis": {
"host": "127.0.0.1",
"port": 6379,
"user": "root",
"password": "123",
}
} def make_cache(cache_file="file"): # 接收用户选择 存储缓存的方式
if cache_file not in settings: # 如果选择缓存的方式不再 settings 字典中
raise TypeError("cache_file not valid!") # raise 自定义一个异常抛给用户 def deco(func):
def f1(url):
if cache_file == "file":
m = hashlib.md5(url.encode("utf-8")) # 获取一个 URL 转换的 hash对象 "<md5 HASH object @ 0x0000025C7ED35300>"
cache_filename = m.hexdigest() # 取出这个md5的hash值 "e1d84f4301e444a3db82c908f29947b1"
cache_filepath = r"%s/%s" % (settings["file"]["dirname"], cache_filename) # 拼接一个文件路径 ./db/e1d84f4301e444a3db82c908f29947b1 if os.path.exists(cache_filepath) and os.path.getsize(cache_filepath): # 如果md5后的url文件存在并且里面有值
return open(cache_filepath, encoding="utf-8").read() # 直接将结果返回给用户
res = func(url)
with open(cache_filepath, "w", encoding="utf-8") as f: # 否则依照 url 的md5值为文件名创建文件
f.write(res) # 将爬取的 页面内容存入 url 的md5值为文件名中
return res # 并返回 爬取的数据
elif settings == "mysql":
pass
elif settings == "redis":
pass
else:
pass return f1 return deco @make_cache(cache_file="file")
def get(url):
return requests.get(url).text print(get("https://www.python.org"))
print(get("https://www.jd.com"))

007-Python函数-装饰器的更多相关文章

  1. Python函数装饰器原理与用法详解《摘》

    本文实例讲述了Python函数装饰器原理与用法.分享给大家供大家参考,具体如下: 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值 ...

  2. python函数-装饰器

    python函数-装饰器 1.装饰器的原则--开放封闭原则 开放:对于添加新功能是开放的 封闭:对于修改原功能是封闭的 2.装饰器的作用 在不更改原函数调用方式的前提下对原函数添加新功能 3.装饰器的 ...

  3. Python函数装饰器高级用法

    在了解了Python函数装饰器基础知识和闭包之后,开始正式学习函数装饰器. 典型的函数装饰器 以下示例定义了一个装饰器,输出函数的运行时间: 函数装饰器和闭包紧密结合,入参func代表被装饰函数,通过 ...

  4. Python 函数装饰器

    首次接触到装饰器的概念,太菜啦! Python 装饰器可以大大节省代码的编写量,提升代码的重复使用率.函数装饰器其本质也是一个函数,我们可以把它理解为函数中定义了一个子函数. 例如我们有这么一个需求, ...

  5. Python @函数装饰器及用法

    1.函数装饰器的工作原理 函数装饰器的工作原理是怎样的呢?假设用 funA() 函数装饰器去装饰 funB() 函数,如下所示: #funA 作为装饰器函数 def funA(fn): #... fn ...

  6. Python @函数装饰器及用法(超级详细)

    函数装饰器的工作原理是怎样的呢?假设用 funA() 函数装饰器去装饰 funB() 函数,如下所示: #funA 作为装饰器函数 def funA(fn): #... fn() # 执行传入的fn参 ...

  7. Python高手之路【四】python函数装饰器

    def outer(func): def inner(): print('hello') print('hello') print('hello') r = func() print('end') p ...

  8. python 函数 装饰器 内置函数

    函数 装饰器 内置函数 一.命名空间和作用域 二.装饰器 1.无参数 2.函数有参数 3.函数动态参数 4.装饰器参数 三.内置函数 salaries={ 'egon':3000, 'alex':10 ...

  9. Python 函数装饰器简明教程

    定义类的静态方法时,就使用了装饰器.其实面向对象中的静态方法都是使用了装饰器. @staticmethod def jump(): print(" 3 meters high") ...

  10. Python高手之路【四】python函数装饰器,迭代器

    def outer(func): def inner(): print('hello') print('hello') print('hello') r = func() print('end') p ...

随机推荐

  1. android SeekBar设置背景无法被填充满的bug

    在做一个播放进度的时候,用到了SeekBar,调用布局如下: <SeekBar android:id="@+id/example_audio_bar" android:lay ...

  2. 【转】Python标准模块--importlib

    [转]Python标准模块--importlib 作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 1 模块简介 P ...

  3. ppp 完全理解(二)【转】

    转自:https://blog.csdn.net/tianruxishui/article/details/44057717 ppp 完全理解(二) pppd 协议及代码分析 作者:李圳均 日期:20 ...

  4. host, nslookup, dig、whois

    一.host命令:DNS 查找使用程序 选项与参数: -a :代表列出该主机所有的相关信息,包括 IP.TTL 与除错讯息等等 -l :若后面接的那个 domain 设定允许 allow-transf ...

  5. git与eclipse集成之代码冲突与解决

    1.1. 代码冲突与解决 目前使用git管理代码,产生冲突的原因,主要是当多个人向特性分支提交代码时,如果两个人修改了同一个文件,第二个人提交代码时就可能会冲突. 举例说明: 创建远程特性分支.远程个 ...

  6. hibernate框架学习之数据抓取(加载)策略

    Hibernate获取数据方式 lHibernate提供了多种方式获取数据 •load方法获取数据 •get方法获取数据 •Query/ Criteria对象获取数据 lHibernate获取的数据分 ...

  7. hibernate框架学习之多表查询helloworld

    package cn.itcast.h3.hql; import java.util.List; import org.hibernate.Query; import org.hibernate.Se ...

  8. HTML5 播放器

    之前一个前端群里 大牛 做了一个自适应的HMLT5播放器 最近根据其思路做了一个相对单一移动端的demo,demo用的图片和歌曲json的数据设计 都是群里大牛做的,在这谢谢~: 同时借鉴的几篇文章: ...

  9. $Django setting.py配置 ,GET、POST深入理解,三件套,orm对象关系映射简介

    1 django中app的概念: 大学:----------------- 项目  信息学院 ----------app01  物理学院-----------app02 ****强调***:创建的每一 ...

  10. node ,npm和nvm 版本的管理

    node npm :node 的包管理 nvm :node 的版本管理 node -v ---->查看node 的版本  (v---->version) npm -v ----->n ...