python函数的嵌套和作用域链

函数的嵌套调用def max2(x,y):

m = x if x > y else y  # 三元运算

return m

def max4(a,b,c,d):

res1 = max2(a,b)

res2 = max2(res1,c)

res3 = max2(res2,d)

print(res1) # 23

print(res2) # 31

print(res3) # 31

max4(23,-7,31,11)

执行结果

23

31

31

例子2def f1():

print("in f1")

def f2():

print("in f2")

f2()

f1()

执行结果

in f1

in f2

例子3def f1():

def f2():

def f3():

print("in f3")

print("in f2")

f3()

print("in f1")

f2()

f1()

执行结果

in f1

in f2

in f3

函数的嵌套无非就是搞清楚函数的执行顺序(不清楚可以看前面的python全栈开发10)

函数的作用域链:小范围作用域可以使用大范围的变量,但是反之不行,它是单向的def f1():

a = 1

def f2():

def f3():

print(a)

f3()

f2()

f1()

执行结果,小范围可以使大范围改变

1

例子2def f1():

a = 1

def f2():

a = 2  # 单向的,小范围可以改变大范围,反之不行

f2()

print('a in f1 :', a)

f1()

执行结果

a in f1 : 1

函数名的本质

函数名本质上就是函数的内存地址

1,可以被引用def func():

print('in func')

f = func

print(f)

执行结果,这里f等于func,而func又是一个函数名,但是后面没有加(),所以上面的func没有被执行,最后打印f,实际上就是打印出func函数名的内存地址

2,可以被当做容器类型的元素def f1():

print('f1')

def f2():

print('f2')

def f3():

print('f3')

l = [f1,f2,f3]

d = {'f1':f1,'f2':f2,'f3':f3}

# 调用

l[0]()

d['f2']()

执行结果,后面的l[0](),实际上就是先取列表l里面的f1,然后就变成了f1(),其实就是执行了f1函数,而d['f2'](),同理,先取出字典'f2'对应的值f2,变成了f2(),函数名加上(),就是执行函数,所以最后的结果就是f1,f2

f1

f2

例2,用for循环批量执行函数def f1():

print(111)

def f2():

print(222)

def f3():

print(333)

def f4():

print(444)

# 如果有100个这样的函数,写100个?使用for循环批量执行函数

l1 = []

for i in range(1, 5):

l1.append('f' + str(i))

for i in l1:

eval(i)()  # eval会去掉引号,后面加个(),执行函数

执行结果

111

222

333

444

3,可以当作函数的参数和返回值

第一类对象(first-class object)指

1,可在运行期创建

2,可用作函数参数或返回值

3,可存入变量的实体

不明白?就当普通变量用,如果后面加(),就执行该函数def fl():

print('f1')   # 4 执行f1函数,打印一次f1

def funcl(argv):  # 2 接收f1参数,所以argv = fl

argv()        # 3 所以变成f1(), 执行f1()函数

return argv   # 5 返回argv,即调用者,也就是funcl(fl)这个整体,等于f1

f = funcl(fl)     # 1 先算等号右边funcl(f1),执行funcl函数,把f1参数,传给argv

# 6 在算等号左边的,也就是 f = f1

f()               # 7 因为f=f1,所以就变成f1(),也就是执行f1函数,

# 所以在打印一次f1,最终结果打印2次f1

执行结果

f1

f1

例2def f1():      # 4 打印 666,最终结果就是666

print(666)

def f2(x):  # 2 接收传过来的实参f1,那么x = f1

x()     # 3 就变成 f1(),执行f1()函数

f2(f1)  # 1执行f2(),把实参f1,传给f2里面的x

执行结果

666

例3def f1():      # 5 打印666,最终结果666

print(666)

def f2(x):    # 2 接收实参f1,所以x = f1

return x  # 3 返回x也就是f1给函数调用者,也就是f2(f1)

f2(f1)()     # 1 执行f2()函数,把实参f1传给f2里面的x

# 4 所以就变成f1(),也就是执行了f1函数

执行结果

666

闭包

例def func():

name = 'hello world'

def inner():

print(name)

闭包函数

内部函数包含对外部作用域而非全局作用域变量的引用,该内部函数称为闭包函数

函数内部定义的函数称为内部函数

由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了,如果我们就是想拿怎么办呢?返回呀

我们都知道函数内的变量我们想在函数外部用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢?

是不是直接就把这个函数的名字返回就好了?

这才是闭包函数最常用的用法def func():

name = 'eva'  # 2 定义一个name = 'eva'

def inner():  # 6 执行函数,打印name的值,之前定义了name= 'eva',所以打印eva

print(name)

return inner  # 3 返回inner值给调用者,也就是func()这个整体

f = func()   # 1 先算等号右边,执行func()函数

# 4 在算等号左边,也就是f = inner

f()          # 5 因为f=inner,也就是执行了inner()这个函数

执行结果

eva

判断闭包函数的方法__closure__# 输出的__closure__有cell元素:是闭包函数

def func():

name = 'eva'

def inner():

print(name)

print(inner.__closure__)

return inner

f = func()

f()

执行结果

输出的__closure__有cell 则是闭包函数

例子2name = 'eqon'

def func():

def inner():

print(name)

print(inner.__closure__)

return inner

f2 = func()

f2()

执行结果

输出的__closure__为None,则不是闭包函数

例3def wrapper():

money = 1000

def func():

name = 'eva'

def inner():

print(name, money)

print(inner.__closure__)

return inner

return func

f = wrapper()  # f = func

i = f()   # func()  i = inner

i()  # inner()

执行结果,是闭包函数

例4from urllib.request import urlopen

def index():

url = 'http://www.xiaohua100.cn/index.html'

def get():

return urlopen(url).read()  # decode('utf-8')解码成utf-8

print(get.__closure__)

return get

xiaohua = index() # xiaohua = get

content = xiaohua() # get() content = read.url的内容

print(content) # 打印网站内容

执行结果,有cell则属于闭包函数

闭包函数的好处

闭包:当函数开始执行时,如果遇到了闭包,它有一个机制,它会永远开辟一个内存空间,将闭包中的变量等值放入其中,不会随着函数的执行完毕而消失,上面的例子就是典型。

python装饰器

什么是装饰器?

装饰器本质上就是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。

装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景

装饰器的形成过程

现在有一个需求,我想让你测试这个函数的执行时间,在不改变这个函数代码的情况下:# 装饰器

import time

def funcl():         # 8 执行此函数

print("hello world")  # 9 打印hello world

def timer(f):   # 2 接收传过来的参数funcl,所以f = funcl

def inner():

start_time = time.time()  # 6 计算开始时间

f()                       # 7 f = funcl ,看第二部的值,f加()就是执行了funcl()这个函数

time.sleep(0.3)           # 10 模拟延迟

end_time = time.time()    # 11 计算结束后的时间

print('此函数的执行效率{}'.format(end_time - start_time)) # 12 打印出函数执行的效率(end-start)

return inner  # 3 把inner值返回给调用者,调用者是timer(funcl)这个整体

funcl = timer(funcl)  # 1 执行等号右边的timer()函数,把funcl参数传给timer里面的变量f

# 4 在算等号左边的,所以 funcl = inner

funcl()               # 5 即inner加(),就是执行inner()这个函数

执行结果

hello world

此函数的执行效率0.3008289337158203

但是如果有多个函数,我都想让你测试它们的执行时间,你每次是不是都得func1=timer(funcl)?这样还是有点麻烦,因为这些函数的函数名可能是不相同,有funcl,func2,graph等,所以更简单的方法,python给你提供了,那就是语法糖。import time

def timer(f):

def inner():

start_time = time.time()

f()

time.sleep(0.3)

end_time = time.time()

print("此函数的执行效率{}".format(end_time-start_time))

return inner

@timer # 即 func = timer(func)

def func():

print("大家好,我是渣渣辉!")

func()

执行结果

大家好,我是渣渣辉!

此函数的执行效率0.3001282215118408

想测试谁,前面加@装饰器函数,即可

这就是最简单版本的装饰器

利用return制造了一个假象,func()执行,其实是执行了inner(),而func变量名传给了timer里的f,func()已经把原来的func()覆盖了

刚才讨论的装饰器都是不带参数的函数,现在要装饰一个带参数的函数怎么办呢?

例1,装饰一个带参数的函数import time

def timer(f):   # f = func

def inner(a): # a = 1

start_time = time.time()

f(a)

time.sleep(0.5)

end_time = time.time()

print(end_time - start_time)

return inner

@timer # func = timer(func) # inner

def func(a):

print(a) #打印1

func(1)

执行结果

1

0.5007100105285645

例2,装饰一个带两个参数的函数import time

def timer(f):

def inner(a,b):

start_time = time.time()

f(a,b)

time.sleep(0.5)

end_time = time.time()

print("此函数的执行效率{}".format(end_time - start_time))

return inner

@timer # func = timer(func) 实际上就是 func = inner

def func(a, b):

print(a, b)

func('大家好','渣渣辉')

执行结果

大家好 渣渣辉

此函数的执行效率0.500657320022583

可以接收任意参数,动态传参

例子import time

def timer(f):

def inner(*args, **kwargs):

start_time = time.time()

f(*args, **kwargs)

time.sleep(0.4)

end_time = time.time()

print("此函数的执行效率为{}".format(end_time - start_time))

return inner

@timer

def func1(a, b):

print("I am func1")

@timer

def func2(a, b, c):

print("in func2 and get a={},b={},c={}".format(a,b,c))

func1(10, 20)

func2("大家好", "我是", "渣渣辉")

执行结果

I am func1

此函数的执行效率为0.400327205657959

in func2 and get a=大家好,b=我是,c=渣渣辉

此函数的执行效率为0.40012335777282715

面试题,手写装饰器def wrapper(func):

def inner(*args, **kwargs):

'''被装饰函数之前'''

ret = func(*args, **kwargs)

'''被装饰函数之后'''

return ret

return inner()

@wrapper

def func(a, b):

pass

return 123  #写成这样基本就差不多了

练习题

先让用户选择,是登陆还是注册

选择序号完毕之后,运行相应的程序,

验证成功之后,可以让其继续选择,登陆还是注册,还可以选择退出(自己增加一个可修改密码功能)

先在同目录下创建一个user_pwd.txt账号密码文件,代码如下#!/usr/bin/env python

# coding: utf-8

import time

import os

import platform

__author__ = 'www.py3study.com'

'''此函数为装饰器'''

def timer(func):

def inner(*args, **kwargs):

start_time = time.time()

func(*args, **kwargs)

end_time = time.time()

print('|| 此程序执行总时间:{}秒'.format(end_time - start_time))

return inner

'''语法糖,计算程序运行总时长,退出程序时执行'''

@timer

class LandingCertification(object):

def __init__(self, *args, **kwargs):

self.timeout = 3

self.flag = True

self.result = False

self.run = {

'0': self.drop_out,

'1': self.register,

'2': self.landing,

'3': self.account_password,

'4': self.transfer_parameters,

}

self.main()

'''程序入口'''

def main(self, *args, **kwargs):

while True:

self.mainMenu()

op = input(u'|| 输入选项:').strip()

'''map判断输入是否符合条件'''

if op == '0':

return True

elif op in map(str, range(len(self.run))):

self.run.get(op)()

else:

self.Error()

continue

'''此函数用于打印菜单'''

def mainMenu(self, *args, **kwargs):

self.clear()

print(u'='*40)

print(u'|| 0:退出程序')

print(u'|| 1:注册')

print(u'|| 2:登陆')

print(u'|| 3:查看已存在账号')

print(u'|| 4:修改密码(流程:账号名-->老密码-->新密码-->修改成功)')

print(u'='*42)

'''此函数用于清屏'''

def clear(self, *args, **kwargs):

OS = platform.system()

if (OS == u'Windows'):

os.system('cls')

else:

os.system('clear')

'''此函数用于设置延迟'''

def Error(self, *args, **kwargs):

print(u'|| 只能输入0-3的整数,等待{}秒后重新输入'.format(self.timeout))

time.sleep(self.timeout)

'''此函数用于文件操作,查询'''

def account_password(self, *args, **kwargs):

with open('user_pwd.txt', encoding='utf-8', mode='r') as f1:

for i in f1:

print('|| {}'.format(i.strip()))

'''此函数用于账号注册'''

def register(self, *args, **kwargs):

while self.flag:

username = input("|| 请输入用户名:").strip()

with open('user_pwd.txt', encoding='utf-8', mode='r') as f2:

for i in f2:

li = i.strip().split()

if username == li[0] or not username.strip():

print('|| (账号名已存在)or(账号名不能为空)')

break

else:

password = input('|| 请输入密码:').strip()

again_password = input('|| 再次输入密码,确认:').strip()

if password == again_password:

with open('user_pwd.txt', encoding='utf-8', mode='a') as f3:

f3.write('\n{} {}'.format(username, password))

print('|| 注册成功')

return self.flag

else:

print("|| 两次密码不一样")

'''此函数用于账号登陆'''

def landing(self, *args, **kwargs):

max = 3

count = 0

while count < max:

count += 1

landing_username = input("|| 输入账号名:").strip()

if not landing_username.strip():

print('|| 账号名不能为空')

else:

landing_password = input("|| 输入密码:").strip()

with open('user_pwd.txt', encoding='utf-8', mode='r') as f4:

for i in f4:

s3 = i.strip().split()

if landing_username == s3[0] and landing_password == s3[1]:

self.result = True

f4.close()

break

else:

self.result = False

if self.result:

print('|| 登陆成功!')

return True

else:

print('|| 账号或者密码错误,还有{}次机会'.format(max - count))

if max - count == 0:

return True

'''此函数用于传参给modify进行密码的修改'''

def transfer_parameters(self, *args, **kwargs):

while True:

transfer_username = input("|| 输入需要更改的账号名:").strip()

if not transfer_username.strip():

print("|| 账号不能为空")

else:

old_password = input("|| 输入老的密码:").strip()

new_password = input('|| 输入新的密码:').strip()

with open("user_pwd.txt", encoding='utf-8', mode='r') as f9:

for i in f9:

s4 = i.strip().split()

if transfer_username == s4[0] and old_password == s4[1]:

self.result = True

f9.close()

self.modify(old_password, new_password)

break

else:

self.result = False

if self.result:

print("|| 密码修改成功!")

return True

else:

print("|| 此账号不存在或密码错误")

'''此函数用于修改密码'''

def modify(self, *args, **kwargs):

with open('user_pwd.txt', encoding='utf-8', mode='r') as f6, \

open('user_pwd.bak', encoding='utf-8',mode='w') as f7:

for i in f6:

new_i = i.replace(*args, **kwargs)

f7.write(new_i)

f6.close()

f7.close()

os.remove('user_pwd.txt')

os.rename('user_pwd.bak', 'user_pwd.txt')

'''此函数用于退出程序'''

def drop_out(self, *args, **kwargs):

print(u"|| Good bye!")

self.main()

return True

if __name__ == '__main__':

LandingCertification()

运行效果

python函数装饰嵌套_python3--函数名本质,函数嵌套,闭包,装饰器相关推荐

  1. python常用函数的用法_python3 文件操作常用函数用法示例

    1. file.close() 关闭文件.关闭后文件不能再进行读写操作,需要重新打开才能进行读写.f = open('demo.text' , 'r') # 使用只读方式打开文本 print(f.re ...

  2. python输入名字显示姓和名_Python函数返回名字和姓氏中常用字母的列表

    问题:不要在函数中使用集合:使用列表返回名字和姓氏(交叉点)中的常用字母列表提示用户输入名字和姓氏,并调用以名字和姓氏为参数的函数并打印返回的列表. 我不明白为什么我的程序只是打印"没有匹配 ...

  3. python高阶函数闭包装饰器_Python_基础_(装饰器,*args,**kwargs,高阶函数,函数闭包,函数嵌套)...

    一,装饰器 装饰器:本质就是函数,功能是为其它的函数动态添加附加的功能 原则:对修改关闭对扩展开放 1.不修改被修饰函数的源代码 2.不修改被修改函数的调用方式 装饰器实现的知识储备:高阶函数,函数嵌 ...

  4. python带参数装饰器 函数名_python 全栈开发,Day11(函数名应用,闭包,装饰器初识,带参数以及带返回值的装饰器)...

    一.函数名应用 函数名是什么?函数名是函数的名字,本质:变量,特殊的变量. 函数名(),执行此函数. python 规范写法 1. #后面加一个空格,再写内容,就没有波浪线了. 2.一行代码写完,下面 ...

  5. python高阶函数闭包装饰器_5.初识python装饰器 高阶函数+闭包+函数嵌套=装饰器...

    一.什么是装饰器? 实际上装饰器就是个函数,这个函数可以为其他函数提供附加的功能. 装饰器在给其他函数添加功能时,不会修改原函数的源代码,不会修改原函数的调用方式. 高阶函数+函数嵌套+闭包 = 装饰 ...

  6. python高阶函数闭包装饰器_Python自学从入门到就业之高阶函数、嵌套函数、闭包、装饰器...

    高阶函数 在Python中,函数其实也是一种数据类型. def test(): return 'hello world' print(type(test)) # 函数对应的数据类型是 function ...

  7. Python基础教程:函数名本质

    函数名的本质 函数名实质上就是函数的内存地址 def wrapper():passprint(wrapper) 1.引用是什么? 当我们定义a=1的时候,系统会开辟一块内存空间来保存1,然后用a变量名 ...

  8. day20 Python 高阶函数,函数,嵌套,闭包 装饰器

    高阶函数定义 1.函数接收的参数是一个函数名 2.函数的返回值是一个函数名 3.满足上述条件任意一个都可以称之为高阶函数 一.函数的接收参数是一个函数名 import time def foo():t ...

  9. 8月30日学习内容整理:命名空间,作用域,函数名本质,闭包

    补充: 三元运算:c= a if a>b else b  相当于:  if  a>b: c=a else: c=b 结构;  if条件成立的结果  if  条件  else  if条件不成 ...

最新文章

  1. c++ 继承机制易犯的错误
  2. php登陆框_PHP 登录完成跳转上一访问页面
  3. Codeforces 864E Fire(背包DP)
  4. js 带笔锋 签字版_年轻人的第一支签字笔? ——米家签字笔评测
  5. (王道408考研操作系统)第二章进程管理-第一节4:进程通信(配合Linux)
  6. C语言——判断是该年的第几天
  7. 华为机试——字符串反转
  8. [置顶] 有关ListIterator接口的add与remove方法探究
  9. c语言中sizeof是一个标准库函数,对C语言中的sizeof的介绍分析
  10. 做生意失败是一种什么体验?创业中有哪些雷区需要注意?
  11. java工具类_非常实用的Java工具类,拿走不谢(一)
  12. 【Unity优化】怎样实现Unity编辑器中的协程
  13. Linux中service命令和/etc/init.d/的关系
  14. Entity Framework 异常档案
  15. simulink积分器报错
  16. FPGA布局及资源优化
  17. 江苏省泰州市谷歌高清卫星地图下载
  18. 微信连wifi 电脑怎么连接到服务器,微信连wifi怎么用 微信连Wi-Fi开通使用教程-电脑教程...
  19. 开源工业缺陷数据集汇总,持续更新中(已更新28个)
  20. Remove WebCakeDesktop

热门文章

  1. JZOJ 1237. 餐桌
  2. 使用celery执行Django串行异步任务
  3. 服务消费和负载(Feign)
  4. 转lua解析脚本过程中的关键数据结构介绍
  5. kafka学习总结之集群部署和zookeeper
  6. delphi idtcpclient和idtcpserver的心跳包
  7. 关注健康,从现在开始(视力篇)
  8. 微信小程序背景音乐官方实例代码无效问题解决及音乐src获取方法
  9. Html中解决点击 a 标签刷新的问题,实现点击时不刷新
  10. 【干货】数字经济时代的新思考:企业如何进行数字化转型及如何称为数据驱动型企业?...