1、函数嵌套
函数的嵌套定义:在一个函数的内部,又定义了另外一个函数
函数的嵌套调用:在调用一个函数的过程中,又调用了其他函数
代码:

>>> def f1():
...     def f2():
...         print('from f2')
...         def f3():
...             print('from f3')
...         f3()
...     f2()
...

执行结果:

>>> f1()
from f2
from f3

2、命名空间与作用域:存放名字的地方,确切的是存放的名字与变量值的绑定的关系的空间
名称空间分类:内置名称空间、全局名称空间和局部名称空间
    内置名称空间:Python解释器启动时产生一些内置名字
    全局名称空间:在执行文件时产生的,存放在文件级别(流程控制语句定义、未缩进定义的)定义的名字
    局部名称函数:
    加载顺序:内置---->全局---->局部
    名称查找顺序:局部---->全局---->内置
作用域:作用的范围
    作用域分类:全局作用域和局部作用域
    全局作用域:全局存活,全局有效。查看函数globals(),显示字典类型
    局部作用域:临时存活,局部生效。查看函数locals(),显示字典类型
关键字:global nonlocal
局部修改全局,对于不可变类型需要使用global,可变类型无需使用global
局部修改局部,对于不可变类型需要使用nonlocal,可变类型无需使用nonlocal
注意:尽量避免使用局部修改全局
重点:作用域关系,在函数定义时,函数中名称查找就已经固定和调用位置无关。在调用函数时,必须回到函数原来定义的位置去找作用域关系

x = 1
def f1():def f2():print(x) # x 为全局作用域return f2()
def foo():x = 100f1()
foo()
x = 10
foo()

3、闭包函数
闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。
闭包可以形象的把它理解为一个封闭的包裹,这个包裹就是一个函数,当然还有函数内部对应的逻辑,包裹里面的东西就是自由变量,自由变量可以在随着包裹到处游荡。当然还得有个前提,这个包裹是被创建出来的。
在Python中可以这样理解,一个闭包就是我调用了一个函数A,这个函数A返回了一个函数B给我。这个返回的函数B就叫做闭包。我在调用函数A的时候传递的参数就是自由变量。

1. 定义
python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).这个定义是相对直白的,好理解的,不像其他定义那样学究味道十足(那些学究味道重的解释,在对一个名词的解释过程中又充满了一堆让人抓狂的其他陌生名词,不适合初学者)。下面举一个简单的例子来说明。

>>> def addx(x):
...     def adder(y): return x + y
...     return adder
...
>>> c = addx(8)
>>> type(c)
<class 'function'>
>>> c.__name__
'adder'
>>> c(10)
18

结合这段简单的代码和定义来说明闭包:如果在一个内部函数里:adder(y)就是这个内部函数,对在外部作用域(但不是在全局作用域)的变量进行引用:x就是被引用的变量,x在外部作用域addx里面,但不在全局作用域里,则这个内部函数adder就是一个闭包。
闭包=函数块+定义函数时的环境,adder就是函数块,x就是环境,当然这个环境可以有很多,不止一个简单的x。所以,如果要用一句话说明白闭包函数,那就是:函数内在包含子函数,并最终return子函数。
2. 使用闭包注意事项
2.1 闭包中是不能修改外部作用域的局部变量的

>>> def foo():
...     m = 0
...     def foo1():
...         m = 1
...         print(m)
...     print(m)
...     foo1()
...     print(m)
...
>>> foo()
0
1
0

从执行结果可以看出,虽然在闭包里面也定义了一个变量m,但是其不会改变外部函数中的局部变量m。

2.2 以下这段代码是在python中使用闭包时一段经典的错误代码

>>> def foo():
...     a = 1
...     def bar():
...         a = a + 1
...         return a
...     return bar
...

这段程序的本意是要通过在每次调用闭包函数时都对变量a进行递增的操作。但在实际使用时

>>> c=foo()
>>> print(c())
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "<stdin>", line 4, in bar
UnboundLocalError: local variable 'a' referenced before assignment

这是因为在执行代码c=foo()时,python会导入全部的闭包函数体bar()来分析其的局部变量,python规则指定所有在赋值语句左面的变量都是局部变量,则在闭包bar()中,变量a在赋值符号"="的左面,被python认为是bar()中的局部变量。再接下来执行print c()时,程序运行至a = a + 1时,因为先前已经把a归为bar()中的局部变量,所以python会在bar()中去找在赋值语句右面的a的值,结果找不到,就会报错。解决的方法很简单

def foo():  a = [1]  def bar():  a[0] = a[0] + 1  return a[0]  return bar

只要将a设定为一个容器就可以了。这样使用起来多少有点不爽,所以在python3以后,在a = a + 1 之前,使用语句nonloacal a就可以了,该语句显式的指定a不是闭包的局部变量。

4、装饰器
1. 装饰器其实就是一个以函数作为参数并返回一个替换函数的可执行函数。让我们从简单的开始,直到能写出实用的装饰器。
封闭原则:对扩展是开放的,对修改是封闭的。

>>> def outer(some_func):
...     def inner():
...         print("hello world!")
...         ret = some_func() # 1
...         return ret + 1
...     return inner
...
>>> def foo():
...     return 1
...
>>> decorated = outer(foo) #2
>>> decorated()
hello world!

请仔细看这个装饰器示例。首先,定义了一个带单个参数some_func的名为outer的函数。然后在outer内部定义了一个内嵌函数inner.inner 函数将打印一行字符串然后调用some_func,并在 #1 处获取其返回值。在每次 outer 被调用时,some_func 的值可能都会不同,但不论 some_func 是什么函数,都将调用它。最后,inner 返回 some_func() 的返回值加 1。在 #2 处可以看到,当调用赋值给 decorated 的返回函数时,得到的是一行文本输出和返回值 2,而非期望的调用 foo 的返回值 1。

我们可以说变量decorated是foo的装饰版——即foo加上一些东西。事实上,如果写了一个实用的装饰器,可能会想用装饰版来代替foo,这样就总能得到“附带其他东西”的foo版本。用不着学习任何新的语法,通过将包含函数的变量重新赋值就能轻松做到这一点:

>>> foo = outer(foo)
>>> foo
<function outer.<locals>.inner at 0x000000F47F5CBA60>

现在任意调用foo()都不会得到原来的foo,而是新的装饰器版!明白了吗?来写一个更实用的装饰器。

2. 函数装饰器@符号的应用

import time
def timemer(func):def wrapper(*args,**kwargs):start = time.time()RETURN=func()stop = time.time()print("run time is: %s" % (stop-start))return RETURNreturn wrapper
如果定义了一个函数,可以用 @ 符号来装饰函数,如下:
@timemer
def index():time.sleep(2)print("welcome to index")
index()

值得注意的是,这种方式和简单的使用index函数的返回值来替换原始变量的做法没有什么不同——Python只是添加了一些语法来使之看起来更加明确。
使用装饰器很简单!虽说写类似staticmethod或者classmethod的实用装饰器比较难,但用起来仅仅需要在函数前添加@装饰器名 即可!
3. *args和*kwargs
上面我们写了一个实用的装饰器,但它是硬编码的,只适用于特定类型的函数——带有两个参数的函数。内部函数checker接收两个参数,然后继续将参数传给闭包中的函数。如果我们想要一个能适用任何函数的装饰器呢?让我们来实现一个为每次被装饰函数的调用添加一个计数器的装饰器,但不改变被装饰函数。这意味着这个装饰器必须接收它所装饰的任何函数的调用信息,并且在调用这些函数时将传递给该装饰器的任何参数都传递给它们。

import time
def timemer(func):def wrapper(*args,**kwargs):start = time.time()RETURN=func(*args,**kwargs)stop = time.time()print("run time is: %s" % (stop-start))return RETURNreturn wrapper

如果定义了一个函数,可以用 @ 符号来装饰函数,如下:

@timemer
def index(name):time.sleep(2)print("welcome %s to index" %name)
index("name")

同时使用*args和*kwargs使得装饰器更加的通用

4. 无参装饰器

current_usr={"user":None}
def auth(func):info = {"xuanwei": {"password": "123123", "number": 0},"linglong": {"password": "123123", "number": 0}}def wrapper(*args,**kwargs):if current_usr["user"]:return func(*args, **kwargs)else:while True:username = input("请输入用户名: ")if username in info:password = input("请输入密码: ")if info[username]["number"] > 1:print("%s 用户已收锁定" % username)exit()if password == info[username]["password"]:current_usr["user"] = usernameRETURN = func(*args, **kwargs)return RETURNelse:print("用户密码错误")info[username]["number"] += 1else:print("%s 用户不存在" % username)return wrapper
@auth
def index1():print("welcome to index1")return 123
def index2():print("welcome to index1")return 123
index1()
index2()

5. 有参装饰器

def auth(auth_type = "dict"):def deco(func):current_usr = {"user": None}def wrapper(*args,**kwargs):if current_usr["user"]:return func(*args, **kwargs)else:if auth_type == "file":with open("db.txt", "r", encoding="utf-8") as read_f:info = eval(read_f.read())else :info = {"xuanwei": {"password": "123123", "number": 0},}while True:username = input("请输入用户名: ")if username in info:password = input("请输入密码: ")if info[username]["number"] > 1:print("%s 用户已收锁定" % username)exit()if password == info[username]["password"]:current_usr["user"] = usernameRETURN = func(*args, **kwargs)return RETURNelse:print("用户密码错误")info[username]["number"] += 1else:print("%s 用户不存在" % username)return wrapperreturn deco
@auth()
def index():print("welcome to index")return 123
index()

5、迭代器
    迭代:是一个重复的过程,每一次重复,都是基于上一次的结果而来
    什么是迭代器对象
        有__iter__和__next__方法,并且执行__iter__得到仍是迭代器本身
    迭代器对象的优点
        1. 提供了一种统一(不依赖索引)的迭代方式
        2. 迭代器本身,比起其他数据类型更少内存,next()在内存中只有1个值
    迭代器对象的缺点
        1. 取值不灵活。只能往后走,不能回退,没有索引取值灵活
        2. 无法预知取值结束,即无法预知长度
    判断可迭代器对象与迭代器对象
        from collections import Iterator
        判断是否是可迭代器对象
        print(isinstance(对象,Iterator))

6、生成器:在函数内存包含yield关键字,那么该函数执行的结果是生成器,并且生成器就是迭代器
关键字yield的功能:
(1) 包函数的结果做出迭代器,以一种优雅的方式封装好__iter__,__next__方法
(2) 函数暂停与再继续运行的状态是有yield保存的
return 和 yield的区别:
(1) 功能相同:都能返回值
(2) 不同:return只能执行一次

转载于:https://blog.51cto.com/xuanwei/1951593

Python自动化运维之函数进阶相关推荐

  1. 如何做好python自动化运维,python在运维中的应用

    这篇文章主要介绍了一个有趣的事情,具有一定借鉴价值,需要的朋友可以参考下.希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下. 1.如何做好python自动化运维 随着移动互联网的普及, ...

  2. Python自动化运维-丁志文-专题视频课程

    Python自动化运维-4561人已学习 课程介绍         本职业规划路线是专门为从事运维开发的同学准备的,并且是严格按照企业需求的标准定制的学习路线.路线中包含python基础和进阶,lin ...

  3. 云计算开发教程:Python自动化运维开发实战流程控制

    今天这篇文章是给大家分享一些云计算开发教程,今天讲解的是:Python自动化运维开发实战流程控制. Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. P ...

  4. 基于python技术的自动化运维是干嘛的_《Python自动化运维 技术与最佳实践》.pdf...

    [实例简介]Python自动化运维 技术与最佳实践 [刘天斯著][机械工业出版社][2014.12][291页].pdf [实例截图] [核心代码] 目 录 本书赞誉 前 言 第一部分 基础篇 第1章 ...

  5. python executemany执行延迟_运维架构师-Python 自动化运维开发-031

    *运维架构师-Python 自动化运维开发-031 十九.Python3 操作数据库 1.Python3 操作 MySQL 1.基本介绍 Python3 操作 MySQL 数据库 可以使用的模块是 p ...

  6. python运维开发培训_运维架构师-Python 自动化运维开发-014

    运维架构师-Python 自动化运维开发-014 九.标准数据类型 1.为什么编程语言中要有类型 类型有以下几个重要角色:对机器而言,类型描述了内存中的电荷是怎么解释的. 对编译器或者解释器而言,类型 ...

  7. python 自动运维架构师_运维架构师-Python 自动化运维开发-031

    *运维架构师-Python 自动化运维开发-031 十九.Python3 操作数据库 1.Python3 操作 MySQL 1.基本介绍Python3 操作 MySQL 数据库 可以使用的模块是 py ...

  8. python自动化运维之路~DAY6

    python自动化运维之路~DAY6 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.  如果你想开发一款游戏,会存在角色的混搭的情况,这个时候"面向对象过程"就出 ...

  9. python cs架构 运维_运维架构师-Python 自动化运维开发-005

    *运维架构师-Python 自动化运维开发-005 四.Ipython 交互式解释器 1.Ipython 简介 IPython外加一个文本编辑器 Windows系统下是IPython加notepad+ ...

最新文章

  1. linux下远程传输文件命令scp使用注解
  2. SpriteBuilder中如何平均拉伸精灵帧动画的距离
  3. ## *将以下学生成绩数据,存放在Hdfs上,使用Spark读取完成下面分析**
  4. 训练数据集如何划分验证测试集?train/test(val/dev) set和交叉验证(cross validation)
  5. 软件开发人员标准薪金 人月_软件产品测试周期
  6. 湖北大学 计算机考研,湖北大学考研难吗?一般要什么水平才可以进入?
  7. maccmsv10 苹果cms10 站群扩展 自用版
  8. limit offset
  9. python分布式编程_python分布式爬虫中的rules有什么用
  10. mba案例分析_2020年(第八届)MBA企业案例分析实践课程暨大赛完美收官!
  11. linux cacti 搭建,linux下搭建cacti监控(示例代码)
  12. MySQL8新增管理端口
  13. 拉格朗日乘子法 那些年学过的高数
  14. 40行代码的人脸识别实践
  15. 自然数学-自然常数e
  16. 从阿里云购买、域名购买、SSL免费购买到SSL集成开发(网络编程安全三)
  17. 金融魔方创始人兼CEO刘嘉:金融SaaS为中小企业赋能的机遇与挑战
  18. MySql delete多表关联删除的使用方法
  19. 水声数字语音通信系统
  20. flash文件系统实现原理

热门文章

  1. Android之AsyncTask源码解析
  2. Swfit 常用特性(Attribute)关键字
  3. UITableView 顶部空白总结
  4. iOS进阶之协议Protocol(13)
  5. iOS架构-静态库.a的脚本化打包及使用(3)
  6. 祈澈菇凉的高端知识资源分享星球开通
  7. Linux中source命令的用法
  8. Ubuntu 使用国内apt源
  9. 使用liner、feather、multiband对已经拼接的数据进行融合(下)
  10. vc 工程下的.ncb文件的作用