1、函数的嵌套

函数的嵌套调用:在调用一个函数的过程中,又调用了其它函数

示例1:

def bar():
print('from nbar') def foo():
print('from foo')
bar()
foo()
#执行结果为
C:\Users\Administrator\AppData\Local\Programs\Python\Python36\python.exe C:/Users/Administrator/PycharmProjects/python18/day4/函数嵌套.py
from foo
from nbar

示例2:求函数所带四个参数的最大值

def max2(x,y):
if x > y:
return x
else:
return y def max4(a,b,c,d):
res1=max2(a,b)
res2=max2(res1,c)
res3=max2(res2,d)
return res3
print(max(1,2,3,-1)) #执行结果如下
C:\Users\Administrator\AppData\Local\Programs\Python\Python36\python.exe C:/Users/Administrator/PycharmProjects/python18/day4/函数嵌套.py
3

函数的嵌套定义:在一个函数的内部,又定义另外一个函数

2、名称空间和作用域

名称空间:存放名字的地方,准确的说名称空间是存放名字与变量值绑定关系的地方
名称空间共有三种名称空间既:
  1、内置名称空间:在python解释器启动时产生,存放一些python内置的名字
  2、全局名称空间:在执行文件时产生,存放文件级别定义的名字
  3、局部名称空间:在执行文件的过程中,如果调用了函数,则会产生该函数的局部名称空间,用来存放该函数内定义的名字,该名字在函数调用时生效,在函数调用结束后失效 加载顺序:内置===》全局===》局部 优先掌握一:名字的查找顺序是:局部==》全局===》内置 作用域:作用的范围
全局作用域:全局存货,全局有效:globals() 局部作用域:临时存活,局部生效:locals()
x=11111111111111111111111111111111111111111111

# def f1():
# x=1
# y=2
# def f2():pass
# # print(locals())
# print(globals())
#
# f1()
# print(locals() is globals())
# print(locals())
#
# print(dir(globals()['__builtins__'])) #global nonlocal掌握
# x=1
# def f1():
# global x
# x=2
#
# f1()
# print(x) # l=[]
# def f2():
# l.append('f2')
#
# f2()
# print(l) # x=0
# def f1():
# # x=1
# def f2():
# # x=2
# def f3():
# # global x
# nonlocal x
# x=3
# f3()
# # print(x)
# f2()
# print(x)
# f1()
# print(x)

 

优先掌握二:作用域关系,在函数定义时就已经固定,于调用位置无关,在调用函数时,必须必须必须回到函数原来定义的位置去找作用域关系

x=1
def f1():
def f2():
print(x)
return f2 # func=f1()
# print(func)
# x=10000000
# func()
# x=10000000 def foo(func):
x=300000000
func() #f2()
x=10000000000000000000000 foo(f1())
# x=10000000000000000000000
# foo(f1())

  

3、闭包函数

1. 定义在函数内部的函数
2. 包含对外部作用域名字的引用,而不是对全局作用域名字的引用,那么该内部函数就称为闭包函数

# x=1
# def f1():
# x=11111111111
# def f2():
# print(x)
# return f2
#
# func=f1() # x=1000
# func() # def foo():
# x=12312312312312312312312312312312312313123
# func()
#
#
# foo() # def deco():
# x=123123123123
# def wrapper():
# print(x)
# return wrapper
#
# func=deco() # func()

闭包函数的应用:惰性计算

import requests #pip3 install requests

# def get(url):
# return requests.get(url).text
#
# print(get('https://www.python.org'))
# print(get('https://www.python.org'))
# print(get('https://www.python.org'))
# print(get('https://www.python.org')) # def index(url):
# # url='https://www.python.org'
# def get():
# # return requests.get(url).text
# print(requests.get(url).text)
#
# return get
#
# python_web=index('https://www.python.org')
# baidu_web=index('https://www.baidu.com') # python_web()
# baidu_web() name='egon'
def index(url):
x=1
y=2
def wrapper():
# x
# y
# return requests.get(url).text
print(name)
return wrapper python_web=index('https://www.python.org') # print(python_web.__closure__[0].cell_contents)
print(python_web.__closure__)
# print(python_web.__closure__[0].cell_contents)
# print(python_web.__closure__[1].cell_contents)
# print(python_web.__closure__[2].cell_contents)

4、装饰器 

1、 开放封闭原则:对扩展是开放的,对修改是封闭

2、 装饰器:装饰它人的工具,装饰器本身可以是任意可调用对象,被装饰的对象本身也可以是任意可调用对象
  2.1 装饰器的遵循的原则:

    2.1.1、 不修改被装饰对象的源代码

    2.1.2、 不修改被调用对象的调用方式

装饰器名,必须写在被装饰对象的正上方,并且是单独一行

import time

def timmer(func):
# func=index
def wrapper():
start=time.time()
func()
stop=time.time()
print('run time is %s' %(stop-start))
return wrapper @timmer # index=timmer(index)
def index():
time.sleep(3)
print('welcome to index')
@timmer # home=timmer(home)
def home():
time.sleep(2)
print('welcome to home page') index()
home()  

装饰器补充

#补充一:wraps

# import time
# from functools import wraps
#
# def timmer(func):
# @wraps(func)
# def wrapper(*args,**kwargs):
# start=time.time()
# res=func(*args,**kwargs)
# stop=time.time()
# print('run time is %s' %(stop-start))
# return res
# return wrapper
#
#
# @timmer # index=timmer(index)
# def index():
# '''这是index函数'''
# time.sleep(3)
# print('welcome to index')
# return 123
#
# print(index.__doc__)
# # print(help(index))

#补充二:一个函数头顶上可以多个装饰器
import time
from functools import wraps
current_user={'user':None} def timmer(func):
@wraps(func)
def wrapper(*args,**kwargs):
start=time.time()
res=func(*args,**kwargs)
stop=time.time()
print('run time is %s' %(stop-start))
return res
return wrapper
def auth(auth_type='file'):
def deco(func):
def wrapper(*args, **kwargs):
if auth_type == 'file':
if current_user['user']:
return func(*args, **kwargs)
name = input('name: ').strip()
password = input('password: ').strip() with open('db.txt', encoding='utf-8') as f:
user_dic = eval(f.read())
if name in user_dic and password == user_dic[name]:
res = func(*args, **kwargs)
current_user['user'] = name
return res
else:
print('user or password error')
elif auth_type == 'mysql':
print('mysql') elif auth_type == 'ldap':
print('ldap')
else:
print('not valid auth_type')
return wrapper
return deco @timmer #index=timmer(wrapper)
@auth() # @deco #index=deco(index) #wrapper
def index():
'''这是index函数'''
time.sleep(3)
print('welcome to index')
return 123 # print(index.__doc__)
# print(help(index)) index()

  

5、生成器

学习生成器之前,我们先来看看什么是列表生成式

#列表生成式
b = [ i*2 for i in range(10)]
print(b) ###########打印输出###########
#[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,还需要花费很长时间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种调用时才会生成相应数据的机制,称为生成器:generator

要创建一个generator,有很多种方法,第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个生成器

#生成器
l = [ i*2 for i in range(10)]
print(l) g = (i*2 for i in range(10))
print(g) ###########打印输出###########
#[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
#<generator object <genexpr> at 0x0064AAE0>

print(g) 打印出来的信息显示g是一个生成器,创建lg的区别仅在于最外层的[]()l是一个list,而g是一个generator;我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值

#生成器next打印
print(next(g))
#......... 不断next 打印10次
#..........
print(next(g)) ###########打印输出###########
#0
#........
#18
#Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
#StopIteration

我们讲过,generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象,所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误

#生成器for调用
g = (i*2 for i in range(10)) #不用担心出现StopIteration错误
for i in g:
print(i) ###########打印输出###########
# 0
# 2
# 4
# 6
# 8
# 10
# 12
# 14
# 16
# 18

generator非常强大。如果推算的算法比较复杂,用列表生成式转换的生成器无法去实现时,我们还可以用函数来实现。比如,著名的斐波拉契数列(Fibonacci)  

#函数表示斐波拉契数列
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n += 1
return 'done' fib(5)
###########打印输出###########
# 1
# 1
# 2
# 3
# 5

仔细观察,可以看出,fib函数实际上是定义了斐波那契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator;也就是说,上面的函数和generator仅一步之遥,那我们能不能把上面的函数变成一个生成器呢?  

#斐波拉契数列转换为generator
def fib(max):
n, a, b = 0, 0, 1
while n < max:
#print(b)
yield b
a, b = b, a + b
n += 1
return 'done' print(type(fib(5))) #打印fib(5)的类型
for i in fib(5): #for循环去调用
print(i)
###########打印输出###########
# <class 'generator'>
# 1
# 1
# 2
# 3
# 5

要把fib函数变成generator,只需要把print(b)改为yield b就可以了,这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator

但是用for循环调用generator时,会发现拿不到generator的return语句的返回值,也就是return的值没有打印出来,现在我们来看看怎么去打印generator的返回值

#获取generator的返回值
def fib(max):
n, a, b = 0, 0, 1
while n < max:
#print(b)
yield b
a, b = b, a + b
n += 1
return 'done' g = fib(5)
while True:
try:
x = next(g)
print( x)
except StopIteration as e:
print(e.value)
break
###########打印输出###########
# 1
# 1
# 2
# 3
# 5
# done

如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIterationvalue中,关于如何捕获错误,后面的错误处理还会详细讲解。 

还可通过yield实现在单线程的情况下实现并发运算的效果

import time
def consumer(name):
print("%s 准备吃包子啦!" %name)
while True:
baozi = yield print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) def producer(name):
c = consumer('A')
c2 = consumer('B')
c.__next__()        #c.__next__()等同于next(c)
c2.__next__()
print("老子开始准备做包子啦!")
for i in range(10):
time.sleep(1)
print("%s做了2个包子!"%(name))
c.send(i)
c2.send(i) producer("lzl")

  

6、迭代器  

迭代:是一个重复的过程,每一次重复,都是基于上一次的结果而来  

# while True: #单纯的重复
# print('你瞅啥') # l=['a','b','c','d']
# count=0
# while count < len(l):
# print(l[count])
# count+=1 dic={'name':'egon','sex':'m',"age":18} #上述按照索引的取值方式,不适于没有索引的数据类型

迭代器:
可迭代对象iterable:凡是对象下有__iter__方法:对象.__iter__,该对象就是可迭代对象

# s='hello'
# l=['a','b','c','d']
# t=('a','b','c','d')
# dic={'name':'egon','sex':'m',"age":18}
# set1={1,2,3}
# f=open('db.txt') # s.__iter__()
# l.__iter__()
# t.__iter__()
# dic.__iter__()
# set1.__iter__()
# f.__iter__()

迭代器对象:可迭代对象执行内置的__iter__方法,得到的结果就是迭代器对象  

# dic={'name':'egon','sex':'m',"age":18}
#
# i=dic.__iter__()
# # print(i) #iterator迭代器
#
# # i.__next__() #next(i)
# print(next(i))
# print(next(i))
# print(next(i))
# print(next(i)) #StopIteration
#
# l=['a','b','c','d']
#
# i=l.__iter__()
# print(next(i))
# print(next(i))
# print(next(i))
# print(next(i))
# print(next(i)) #StopIteration

不依赖于索引的取值方式  

# l=['a','b','c','d']
# dic={'name':'egon','sex':'m',"age":18}
# iter_l=iter(l)
# iter_dic=iter(dic)
# while True:
# try:
# # print(next(iter_l))
# k=next(iter_dic)
# print(k,dic[k])
# except StopIteration:
# break

什么是迭代器对象:
1 有__iter__,执行得到仍然是迭代本身
2 有__next__

  

迭代器对象的优点
1:提供了一种统一的(不依赖于索引的)迭代方式
2:迭代器本身,比起其他数据类型更省内存

# l=['a','b','c','d']
# i=iter(l) # dic={'a':1,'b':2}
# x=dic.keys()
# print(x)
# i=x.__iter__()
#
# with open('a.txt') as f:
# # print(next(f))
# # print(next(f))
# # print(next(f))
# f.read()

迭代器对象的缺点
1:一次性,只能往后走,不能回退,不如索引取值灵活
2:无法预知什么时候取值结束,即无法预知长度

# l=['a','b','c','d']
# i=iter(l)
# print(next(i))
# print(next(i))
# print(next(i))

最新文章

  1. 在终端terminal运行ReactNative程序经常出现的问题
  2. Surface在C++层的创建源码解析
  3. mytatis将Integer等于0识别成空字符串
  4. SQLSERVER如何获取一个数据库中的所有表的名称、一个表中所有字段的名称
  5. mysql数据库的基本操作
  6. 【JAVA并发编程实战】2、对象的组合
  7. Netty Client重连实现
  8. Python脚本运行出现语法错误:IndentationError: unindent does not match any outer indentation level
  9. zookeeper安装配置
  10. 实现图片的2次缩放后再进行candy边缘检测
  11. Drools规则加载变量冲突问题分析
  12. 英语学习APP—百词斩
  13. 遇见NodeJS:JavaScript的贵人
  14. HDU 3446 daizhenyang&#39;s chess
  15. ui原则
  16. 两年前实习时的文档——Platform学习总结
  17. A框架 第二部 实例化接收到的get类,调用父类抽象方法,自动执行方法call_user_func_array()
  18. 滚动条实现RGB颜色的调制(窗体程序)--JAVA基础
  19. OS X10.10下HomeBrew的安装提示
  20. 网址导航18B

热门文章

  1. appium+python自动化44-appium命令行模式
  2. Lua-简洁、轻量、可扩展的脚本语言
  3. WebLogic Operator初试
  4. python部署工具fabric
  5. SQL通过身份证获取信息
  6. 让所有窗体都从DevExpress.XtraEditors.XtraForm继承
  7. TestNG 六 测试结果
  8. Java 8 Stream 教程
  9. java中的初始化块
  10. mysql 创建函数或者存储过程,定义变量报错