函数
2018-01-09 18:56:08 10 举报
AI智能生成
函数篇
作者其他创作
大纲/内容
函数的应用
装饰器
<strong>装饰器的主要功能</strong>
在不改变函数调用方式的基础上在函数的前、后添加功能。
本质
一个闭包函数
<span style="font-size: 16px;"><strong>开放封闭原则</strong></span>
1.对扩展是开放的
我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。
2.对修改是封闭的
就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
<strong>装饰器的固定格式</strong>
def timer(func):<br> def inner(*args,**kwargs):<br> '''执行函数之前要做的'''<br> re = func(*args,**kwargs)<br> '''执行函数之后要做的'''<br> return re<br> return inner<br>@timer<br>装饰器的固定格式
语法糖
<font color="#008000">func2 = timer(func2)</font><br>
被装饰函数名称=装饰器函数名称(被装饰函数名称)
<span style="font-size: 16px;"><strong>带参数的装饰器</strong></span>
三层嵌套函数
<p>def outer(flag):<br> def timer(func):<br> def inner(*args,**kwargs):<br> if flag:<br> print('''执行函数之前要做的''')<br> re = func(*args,**kwargs)<br> if flag:<br> print('''执行函数之后要做的''')<br> return re<br> return inner<br> return timer</p><p><p>@outer(False)<br>def func():<br> print(111)</p><p><p>func()</p><p>带参数的装饰器</p></p></p>
<span style="font-size: 16px;"><strong>多个装饰器装饰同一个函数</strong></span>
执行效果是按照语法糖的上下顺序显示的
被装饰函数执行之前的显示顺序是和语法糖的上下顺序一致,被装饰函数执行之后的显示顺序是和语法糖的上下顺序正好反过来,是个镜面现象
迭代器
for循环本质
<strong>可以被for循环的都是可迭代的</strong>
<strong>for循环其实就是在使用迭代器</strong>
<strong>只有是可迭代对象的时候 才能用 for</strong>
<strong>当我们遇到一个新的变量,不确定能不能for循环的时候,就判断它是否可迭代</strong>
<span style="color: rgb(51, 102, 255);"><strong>可迭代协议</strong></span>
内部实现了__iter__方法,<span style="color: rgb(0, 0, 0);">只要含有__iter__方法的都是可迭代的。</span>
<span style="color: rgb(0, 0, 0);"><strong>迭代器协议</strong></span>
<strong>必须拥有__iter__方法和__next__方法。</strong>
<strong>可迭代的.__iter__()方法就可以得到一个迭代器</strong>
<strong>迭代器中的__next__()方法可以一个一个的获取值</strong>
迭代器的好处
<strong>从容器类型中一个一个的取值,会把所有的值都取到。</strong>
<strong>节省内存空间 #迭代器并不会在内存中再占用一大块内存,</strong><strong>而是随着循环 每次生成一个 </strong>
<strong>每次next只给我一个</strong>
生成器
本质是迭代器
特点是惰性运算,开发者自定义
表现形式
生成器函数
一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
好处
<span style="font-size: 14px;">不会一下子在内存中生成太多数据,节省内存</span>
<strong>send</strong>
<p>send 获取下一个值的效果和next基本一致 </p><p>只是在获取下一个值的时候,给上一yield的位置传递一个数据</p>
使用send的注意事项
第一次使用生成器的时候,是用next获取下一个值; <p> 最后一个yield不能接受外部的值</p>
生成器表达式
例子
g = (i*i <span style="color: rgb(0, 0, 255);">for</span> i <span style="color: rgb(0, 0, 255);">in</span> range(<span style="color: rgb(128, 0, 128);">10</span><span style="color: rgb(0, 0, 0);">))<br></span><span style="color: rgb(0, 0, 255);">for</span> i <span style="color: rgb(0, 0, 255);">in</span><span style="color: rgb(0, 0, 0);"> g :<br> print(i)</span>
g后面是小括号,g是一个生成器,for循环时才能取值,循环一次输出一个值
内置函数
匿名函数
为了解决那些功能很简单的需求而设计的一句话函数。
函数名 = <span style="color: rgb(0, 0, 255);">lambda<span style="color: rgb(0, 0, 0);"> 参数 :返回值</span></span>
格式说明
<span style="color: rgb(0, 128, 0);">#<span style="color: rgb(0, 128, 0);">参数可以有多个,用逗号隔开<span style="color: rgb(0, 128, 0);"><br>#<span style="color: rgb(0, 128, 0);">匿名函数不管逻辑多复杂,只能写一行,且逻辑执行结束后的内容就是返回值<span style="color: rgb(0, 128, 0);"><br>#<span style="color: rgb(0, 128, 0);">返回值和正常的函数一样可以是任意数据类型</span></span></span></span></span></span>
递归函数
在一个函数里再调用这个函数本身
递归深度
Python为了考虑保护内存占用情况,有一个递归深度的限制,默认值是997,超过会报错
递归深度可以人为修改,输出不会报错,但也会有个自动退出的值,这个值适合计算机的自身配置有关,一般情况都是3222,MAC会更大点。
递归的优缺点
优点:会让代码简单
缺点:比较占用内存,如果需要递归次数太多,就不太合适用递归算法来解决问题。
“人理解循环,神理解递归”
经典例子
一、斐波那契数列
<pre style='color: rgb(0, 0, 0); font-family: "宋体"; font-size: 15.6pt; background-color: rgb(255, 255, 255);'><span style="color: rgb(0, 0, 128); font-weight: bold;">def </span>func(n,a=<span style="color: rgb(0, 0, 255);">1</span>,b=<span style="color: rgb(0, 0, 255);">1</span>):<br> <span style="color: rgb(0, 0, 128); font-weight: bold;">if </span>n == <span style="color: rgb(0, 0, 255);">1 </span>:<br> <span style="color: rgb(0, 0, 128); font-weight: bold;">return </span>a<br> <span style="color: rgb(0, 0, 128); font-weight: bold;">return </span>func(n-<span style="color: rgb(0, 0, 255);">1</span>,b,a+b)<br><span style="color: rgb(0, 0, 128);">print</span>(func(<span style="color: rgb(0, 0, 255);">100</span>))</pre>
二、阶乘算法
<pre style='color: rgb(0, 0, 0); font-family: "宋体"; font-size: 13.2pt; background-color: rgb(255, 255, 255);'><span style="color: rgb(0, 0, 128); font-weight: bold;">def </span>fac(n):<br> <span style="color: rgb(0, 0, 128); font-weight: bold;">if </span>n == <span style="color: rgb(0, 0, 255);">1 </span>:<br> <span style="color: rgb(0, 0, 128); font-weight: bold;">return </span><span style="color: rgb(0, 0, 255);">1<br></span><span style="color: rgb(0, 0, 255);"> </span><span style="color: rgb(0, 0, 128); font-weight: bold;">return </span>n * fac(n-<span style="color: rgb(0, 0, 255);">1</span>)<br><span style="color: rgb(0, 0, 128);">print</span>(fac(<span style="color: rgb(0, 0, 255);">10</span>))</pre>
函数的进阶
<strong>命名空间</strong>
<strong>全局命名空间</strong>
代码在运行伊始,创建的存储“变量名与值的关系”的空间
<strong>局部命名空间</strong>
在函数的运行中开辟的临时的空间
<strong>内置命名空间</strong>
Python中内置的,存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用
<strong>三种命名空间之间的加载顺序</strong>
内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
<strong>三种命名空间之间的取值顺序</strong>
在局部调用
局部命名空间->全局命名空间->内置命名空间
在全局调用
全局命名空间->内置命名空间
<strong>作用域</strong>
<span>全局作用域</span>
包含<strong>内置名称空间、全局名称空间</strong>,在整个文件的任意位置都能被引用、全局有效
局部作用域
局部名称空间,只能在局部范围<strong>内</strong>生效
小知识点
global关键字<span style='font-family: "Courier New"; font-size: 12px;'></span>
声明全局变量
对于不可变数据类型 在局部可是查看全局作用域中的变量<br>但是不能直接修改<br>如果想要修改,需要在程序的一开始添加global声明<br>如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效<br>
globals
在全局调用
永远打印全局的名字<br>
locals
<span class="cnblogs_code_collapse">在局部调用,即本地调用</span>
输出什么 ,根据locals所在的位置
函数的嵌套
函数的嵌套调用
函数的嵌套定义
内部函数可以使用外部函数的变量
函数的作用域链
nonlocal关键字
只能用于局部变量 找上层中离当前函数最近一层的局部变量
声明了nonlocal的内部函数的变量修改会影响到 离当前函数最近一层的局部变量
对全局无效
对局部 也只是对 最近的 一层 有影响
函数名的本质
<span style="font-size: 14px;">函数名本质上就是函数的内存地址</span>
可以被引用,被赋值
可以被当作容器类型的元素
可以当作函数的参数和返回值
第一类对象(first-class object)
可在运行期创建
可以当作函数的参数和返回值
可存入变量的实体
闭包
闭包函数
<span style="font-size: 14px;">内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数<br>#函数内部定义的函数称为内部函数</span>
闭包函数最常用的用法
<p>def func():<br> name = 'eva'<br> def inner():<br> print(name)<br> return inner</p><p>f = func()<br>f()</p>
闭包的嵌套
<p>def wrapper():<br> money = 1000<br> def func():<br> name = 'eva'<br> def inner():<br> print(name,money)<br> return inner<br> return func</p><p><p>f = wrapper()<br>i = f()<br>i()</p><p> 闭包嵌套</p><p></p>
判断闭包函数的方法__closure__
<p>#输出的__closure__有cell元素 :是闭包函数<br>def func():<br> name = 'eva'<br> def inner():<br> print(name)<br> print(inner.__closure__)<br> return inner</p><p><p>f = func()<br>f()</p><p><p>#输出的__closure__为None :不是闭包函数<br>name = 'egon'<br>def func2():<br> def inner():<br> print(name)<br> print(inner.__closure__)<br> return inner</p><p>f2 = func2()<br>f2()</p></p></p>
初识函数
函数的定义
<strong>def </strong>关键词开头,空格之后接函数名称和圆括号(),最后还有一个":"。<p> def 是固定的,不能变。</p><p> 空格 为了将def关键字和函数名分开,必须空格。</p><p> 函数名:函数名只能包含字符串、下划线和数字且不能以数字开头。虽然函数名可以随便起,但我们给函数起名字还是要尽量简短,并能表达函数功能</p><p> 括号:是必须加的!</p>
<strong>注释</strong>
每一个函数都应该对功能和参数进行相应的说明,应该写在函数下面第一行。以增强代码的可读性。
函数的<strong>调用</strong>
就是 <strong>函数名()</strong> 要记得加上括号
函数的返回值
关键字是 return
作用
可以返回函数值
可以结束一个函数的继续
没有返回值 —— 返回None
不写return
只写return:结束一个函数的继续
return None —— 不常用
返回1个值
可以返回任何数据类型
只要返回就可以接收到
如果在一个程序中有多个return,那么只执行第一个
返回多个值
用多个变量接收:有多少返回值就用多少变量接收
用一个变量接收: 得到的是一个元组
<a style="text-decoration: none;" href="http://www.cnblogs.com/Eva-J/p/7125925.html#_label4"><span style="color: rgb(0, 0, 0);">函数的参数</span></a>
实参
我们调用函数时,在变量后面的()里加入的参数就是实际参数,简称实参
形参
我们定义函数时,在变量后面的()里加入的参数就是形式参数,简称形参
<strong>默认参数</strong>
将变化比较小的值设置成默认参数
<strong>动态参数</strong>
按位置传值多余的参数都由args统一接收,可以接受任意个参数,保存成一个元组的形式
*args : 接收的是按照位置传参的值,组织成一个元组
**kwargs: 接受的是按照关键字传参的值,组织成一个字典
args必须在kwargs之前
<strong>传递多个参数</strong>
参数可以传递多个,多个参数之间用逗号分割
没有参数 <br> 定义函数和调用函数时括号里都不写内容 <br>有一个参数 <br> 传什么就是什么 <br>有多个参数 <br> 位置参数,按照顺序对应
站在实参角度
按照位置传值
按照关键字传参
混着用可以:但是 必须先按照位置传参,再按照关键字传参数<p> 不能给同一个变量传多个值</p>
站在形参角度
位置参数必须传值
位置参数:必须传,且有几个参数就传几个值
默认参数: 可以不传,如果不传就是用默认的参数,如果传了就用传的
初识函数总结
<span style="color: rgb(0, 128, 128);"><strong>只有调用函数的时候</strong></span>
<strong><font color="#008080">按照位置传 : 直接写参数的值</font></strong>
<strong><font color="#008080">按照关键字: 关键字 = 值</font></strong>
<span style="color: rgb(0, 128, 128);"><strong>定义函数的时候</strong></span>
<strong><font color="#008080">位置参数 : 直接定义参数</font></strong>
<strong><font color="#008080">默认参数,关键字参数 :参数名 = '默认的值' </font></strong>
<strong><font color="#008080">动态参数 : 可以接受任意多个参数</font></strong>
<strong><font color="#008080">参数名之前加*,习惯参数名args</font></strong>
<strong><font color="#008080">参数名之前加**,习惯参数名kwargs </font></strong>
<strong><font color="#008080">顺序:位置参数, *args, 默认参数, **kwargs</font></strong>
0 条评论
下一页