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. Ubuntu下Wine使用教程

    转自:http://blog.csdn.net/wangchangshuai0010/article/details/12057251 用了段时间的Ubuntu,感觉很好!可是工作的时候还是要用到 w ...

  2. 九.Spring Boot JPAHibernateSpring Data

    1.项目结构 2.导入jar包 <!-- 添加Spring-data-jpa依赖. --> <dependency> <groupId>org.springfram ...

  3. 深入分析JavaWeb Item40 -- 文件上传和下载

    在Web应用系统开发中,文件上传和下载功能是很经常使用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传.浏览器在上传的过程中是将文件以流的形式提交到server端的.假设 ...

  4. ylbtech-LanguageSamples-PartialTypes(部分类型)

    ylbtech-Microsoft-CSharpSamples:ylbtech-LanguageSamples-PartialTypes(部分类型) 1.A,示例(Sample) 返回顶部 “分部类型 ...

  5. Objective-C:KVC机制

    KVC:key value coding    键值对的编码 功能:用来给对象属性设置值或者取出对象属性的值.虽然getter和setter方法也是该功能,但是如果类中没有设置属性特性或者重写这两个方 ...

  6. SaltStack–Job管理

    官方文档:https://docs.saltstack.com/en/2016.11/ref/modules/all/salt.modules.saltutil.html 在SaltStack里面执行 ...

  7. vue-resource文档详细解读

    Vue可以构建一个完全不依赖后端服务的应用,同时也可以与服务端进行数据交互来同步界面的动态更新.Vue通过插件的形式实现了基于AJAX,JSPNP等技术的服务端通信. vue-resource是一个通 ...

  8. http://www.cnblogs.com/alipayhutu/archive/2012/08/16/2643098.html

    http://www.cnblogs.com/alipayhutu/archive/2012/08/16/2643098.html

  9. [Python爬虫] 之十四:Selenium +phantomjs抓取媒介360数据

    具体代码如下: # coding=utf-8import osimport refrom selenium import webdriverimport selenium.webdriver.supp ...

  10. java 过滤器(自己的理解)

    filter继承javax.servlet.* 必须实现doFilter方法 chain.doFilter(request, response);这句话必须写在doFilter方法内部(以便调用其他的 ...