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))

第四篇: python函数续的更多相关文章

  1. 第四篇.python的基础

    目录 第四篇.python基础01 1. 变量 2. 常量 3. python变量内存管理 4. 变量的三个特征 5. 花式赋值 6. 注释 7. 数据类型基础 8. 数字类型 9. 字符串类型 10 ...

  2. Python之路【第四篇】: 函数、递归、内置函数

    一. 背景提要 现在老板让你写一个监控程序,监控服务器的系统状况,当cpu\memory\disk等指标的使用量超过阀值时即发邮件报警,你掏空了所有的知识量,写出了以下代码 while True: i ...

  3. Python系列:四、Python函数--技术流ken

    Python函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也可 ...

  4. 【Python之路】第四篇--Python基础之函数

    三元运算 三元运算(三目运算),是对简单的条件语句的缩写 # 书写格式 result = 值1 if 条件 else 值2 # 如果条件成立,那么将 “值1” 赋值给result变量,否则,将“值2” ...

  5. Python开发【第四篇】函数

    函数的作用 函数可以让编程逻辑结构化以及模块化 无论是C.C++,Java还是Python,函数是必不可少的知识点,也是很重要的知识点,函数是完成一个功能的代码块,使用函数可以使逻辑结构变得更加清晰以 ...

  6. Python【第四篇】函数、内置函数、递归、装饰器、生成器和迭代器

    一.函数 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 特性: 减少重复代码 使程序变的可扩展 使程序变得易维护 1.定义 def 函数名(参数): ...

  7. python开发第四篇:函数(1)

    函数 阅读目录 一 函数知识体系 二 函数基础 三 函数对象.函数嵌套.名称空间与作用域.装饰器 四 迭代器.生成器.面向过程编程 五 三元表达式.列表推导式.生成器表达式.递归.匿名函数.内置函数 ...

  8. Python进阶【第四篇】函数

    一.变量 变量是记录一系列状态变化的量 1.变量分为可变类型与不可变类型——可变 与不可变是根据变量在内存中占据的位置 可变类型:列表list[ ].字典dicta{ } 不可变类型:字符串str.数 ...

  9. 四年级--python函数基础用法

    一.函数的定义,调用和返回值 1.1 语法 def 函数(参数一,参数二...): ''' 文档注释 ''' 代码逻辑一 代码逻辑二 .... return 返回值 1.2 定义函数的三种形式 说明: ...

随机推荐

  1. BOOST 实用手册(摘录自校友博客)

    1. 序言 现在学的东西很容易忘记,写这篇文章的目的是能让我在需要时快速找回当时的感觉.  Let's BOOST THE WORLD . 2. 编译:VC2005注意 在 属性->C/C++- ...

  2. select标签中option内容加链接

    1.Html页面代码 <select name="select" id="select" style="height: 25px; width: ...

  3. SQL 备份还原单个表

    如果只想备份或恢复单个表而不想备份或恢复整个数据库的话,往往有以下方法: 1.在Sql server2000 中可以使用DTS来将该表的数据导出成另外的文件格式.当需要恢复时,可以将该文件中数据再通过 ...

  4. Windows安装和配置Tomcat

    1 从http://tomcat.apache.org下载Tomcat压缩包,我这里下的版本是7.0.67.   2 将Tomcat压缩包解压缩到任意路径下,我这里的解压缩路径为E:\tomcat-7 ...

  5. cglib Demo

    转载自:http://huihai.iteye.com/blog/858524 http://www.cnblogs.com/shijiaqi1066/p/3429691.html

  6. (转)nio 字符集

    字符集 概述 根据 Sun 的文档,一个 Charset 是“十六位 Unicode 字符序列与字节序列之间的一个命名的映射”.实际上,一个 Charset 允许您以尽可能最具可移植性的方式读写字符序 ...

  7. PHP基础知识(一)

    The Basics Comparison operators Comparison operators are an often overlooked aspect of PHP, which ca ...

  8. Java程序的结构

    1.由一个或多个独立的类组成: 2.最多一个公有类 3.源代码文件名必须与类名相同 4.类由一个或多个方法组成,其中公有类中的main()方法作为程序的入口. 注:javaSE中一定有main方法. ...

  9. html 接收GET请求参数

       function GetQueryString(name)   {        var reg = new RegExp("(^|&)"+ name +" ...

  10. 【VBA编程】06.控制语句

    [IF...THEN...语句] If condition Then [statements1] else [statements2] end if condition 为一个逻辑表达式,表示做选择时 ...