前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python学习笔记整理(十二)

Python学习笔记整理(十二)

作者头像
py3study
发布2020-01-09 19:00:47
6630
发布2020-01-09 19:00:47
举报
文章被收录于专栏:python3python3

一、函数基础 函数可以计算出一个返回值。作用:最大化代码重用,最小化代码冗余,流程的分解 1、函数相关的语句和表达式 语句        例子 Calls        myfunc(‘diege','eggs',meat=lit) #使用函数 def,return,yield      def adder(a,b=1,*c):                           return a+b+c[0] global        changer():                 global x;x='new' lambda        Funcs=[lambad x:x**2,lambad x:x*3] 2、编写函数 def是可执行的代码,实时执行的,Python中所有语句都是实时执行的,if,while,def可嵌套,可以出现在任何地方,但往往包含在模块文件中, 并早模块导入时运行,函数还可以通过嵌套到if语句中去实现不同的函数定义。 def创建了一个对象并将其赋值给某一个变量名。 return将一个结果对象发送给调用者。 函数是通过赋值(对象引用)传递的。

参数通过赋值传递给函数。 global声明了一个模块级的变量并被赋值。 参数,返回值以及变量并不是声明 def语句 def语句将创建一个函数对象并将其赋值给一个变量名。一般格式如下: def <name>(arg1,age2,...,agrN):     <statements>      return <value> 函数主体往往都包含了一个return语句(不是必须的),如果它没有出现,那么函数将会在控制流执行完函数主体时结束,技术上,没有返回值的函数自动返回了none对象。 return可以在函数主体中的任何地方出现。它表示函数调用的结束,并将结果返回至函数调用处。 函数通过嵌套到if语句中去实现不同的函数定义的格式: if test:     def func():         ... else:     def func() func()    #call 3、例子1 定义 >>> def Dtest(x,y): ...     return x*y 使用(call) >>> Dtest(3,5) 15 >>> Dtest(3.14,3) 9.42 >>> Dtest('A',4)     'AAAA' 这里又看到Python中的多态了 Dtest函数中的表达式x*y的意义完全取决于x和y的对象类型。 类似的多态操作还包括:print,index,*操作符 >>> Dtest('A','A') #会报错,但不要尝试判断传入参数的对象类型,这样实质上破坏了函数的灵活性,把函数限制在特定的类型上。任何支持函数所预期的结果的对象都能用。(结果一词是指函数所执行的一组方法和表达式运算符) 4、例子2 寻找序列的交集 定义 >>> def Intersect(seq1,seq2): ...     res=[] ...     for x in seq1: ...             if x in seq2: ...                     res.append(x) ...     return res 调用 >>> Intersect([1,3,5,6,7,9],[2,4,5,7,8,10]) [5, 7] >>> s1='SPAM' >>> s2='sCaM' >>> Intersect(s1,s2)                         ['M'] 重访多态,这些编写这个函数是多态,它可以支持多种类型 >>> Intersect([1,3,5,6,7,9],(1,4))              [1] 技术上讲,文件也可以做为该函数的第1个参数,但不能作为第2个参数。在一个文件中搜索2个参数 >>> Intersect(open('/etc/rc.conf').read(),'apache') 5、本地变量 例子2中.res变量在python中称为本地变量,这个变量只是在def内的函数中是可见的,并且仅在函数运行时是存在的。所有函数内部进行赋值的变量名 都默认为本地变量,。 *req是明显被赋值过的,所以它是一个本地变量 *参数也是通过赋值被传入的,所以seq1和seq2也是本地变量。 *for循环将元素赋值给了一个变量,所以变量x也是本地 二、作用域和参数 (一)作用域 python作用域:变量定义以及查找的地方 参数传递:传递给函数作为其输入对象的方式 1、作用域法则 Python创建,改变或者查找变量名都是在所谓的命名空间(一个保存变量名的地方)中进行。作用域这个术语指的就是命名空间。 也就说,在代码中变量名被赋值的位置决定了这个变量名能被访问到的范围 一个函数所有变量名都与函数的命名空间相关联。 *def内定义变量名def内使用 *def之中的变量名与def之外的变量名不发生冲突,使用别处相同的变量名也没问题。 x=99 def func()     x=88 函数定义了本地作用域,而模块定义了全局作用域。两作用域关系。 *内嵌的模块是全局作用域:对于外部的全局变量就成为了一个模块对象的属性。 *全局作用域的作用范围仅限单个文件:不要被全局迷惑,这里的全局是一个文件的顶层的变量名,仅对这个文件内部的代码而言是全局。 Python中,没有一个无所不包的情景文件作用域。替代的方法是,变量名由模块文件隔开,必须精准地导入一个模块文件才能偶使用这文件中 定义的变量名, *每次对函数的调用都创建了一个新的本地作用域。 *赋值的变量名废除声明为全局变量,否则均为本地变量。 *所用的变量名都可以归纳为本地,全局,或者内置。(内置:ptyhon预定义的__builtin__模块提供的) 2、变量名解析:LEGB原则 对一个def语句 *变量名引用分为三个作用域进行查找:首先查找本地,然后是函数内(如果有),之后全局,最后内置。 *默认情况下,变量名赋值会创建或改变本地变量 *全局声明将赋值变量名映射到模块文件内部的作用域。 3、作用域实例 #定义全局作用域 >>> X=99 >>> def func(Y): ...     Z=X+Y   #本地作用域 ...     return Z ... >>> func(1)     100 全局变量:X,func 本地变量:Y,Z 4、内置作用域 需要导入__builtin__ >>> import  __builtin__ >>> dir(__builtin__) 里面前一半是内置异常,后一半是内置函数 5、global global语句包含关键字global *全局变量是位于模块文件内部顶层的变量名 *全局变量如果是在函数内部被赋值的话,并需经过声明 *全局变量名在函数的内部不经过声明也可以被引用 >>> X=88      >>> def func(): ...     global X ...     X=99 ... >>> func() >>> print X 99 >>> y,z=1,2 >>> def Ftest(): ...     global x ...     x=y+z ... >>> Ftest() >>> x 3 6、最小化全局变量 (二)传递参数 *参数的传递是通过自动将对象赋值给本地变量来实现的。 *在函数内部的参数名的赋值不会影响调用者。 *改变函数的可变对象参数的值也许会对调用者有影响。 换句话说,因为参数是简单的通过赋值进行对象的传递,函数能够改变传入的可变对象,因此其结果会影响调用者。 *不可变参数是“通过值”进行传递。 像整数和字符串这样的对象是通过对象引用而不是拷贝进行传递的,但是因为你无论如何都不可能在原处改变不可变对象,实际的效果就是很像创建了一份拷贝。 可变对象是通过“指针”进行传递的。 1、参数和共享引用 >>> def changer(a,b): ...     a=2 ...     b[0]='diege' ... >>> X=1 >>> L=[1,2] >>> changer(X,L) >>> X,L (1, ['diege', 2]) 函数内部对参数或者参数的分片赋值了,X没改变,L改变了,X,Y都是全局变量。这说明了数字字符串不可变参数函数无法改变。 而列表,字典等可改变参数可以在执行函数调用后改变。 这里a是函数的本地变量名,第一个赋值对函数调用者没有影响。它仅简单的修改了本地变量名a,并没有改变参数a绑定的函数调用者的变量名X。 b也是一个本地变量名,但是他被传递给了一个可变对象。因为第二个赋值是一个在原处发生的对象改变(如果是b='diege'就没有改变,因为这样只改变本地变量名),对函数中b[0]进行赋值的结果是在函数返回后影响L的值。事实上我们没有修改b,修改是是b当前所引用 对象的一部分,并且这个改变将影响调用者。 2、避免可变参数的修改 在Python中,默认通过引用(也就是指针)进行函数的参数传递。如果不想在函数内部在原处的修改影响传递给它的对象。那么,能够简单的创建一个可变对象的拷贝。我们总是能够在调用时对列表进行拷贝L=[1,2] changer(X,L[:]) 如果不想改变传入的对象,无论函数是如何调用的,我们可以在函数内部进行拷贝,避免可变参数的修改 >>> def changer(a,b): ...     a=2 ...    b=b[:] ...     b[0]='diege' ... 3、对参数输出进行模拟 return能够返回任意种类的对象,它也能返回多个值,如这些值被封装进一个元组或者其他的集合类型 >>> def mul(x,y): ...     x=2 ...     y=[3,4] ...     return x,y ... >>> X=1 >>> L=[1,2] >>> mul(X,L) (2, [3, 4]) >>> X,L=mul(X,L)  >>> X,L (2, [3, 4]) 4、特定参数匹配模型 参数在ptyhon中总是通过赋值进行传递,传入的对象赋值给了在def头部的变量名。尽管这样,在模型的上层,python提供了额外的工具,该工具改变了调用过中,赋值时参数对象匹配在头部的参数名的优先级。这些工具是可选的。 默认情况下,参数是通过其位置进行匹配的,从左到右,而且必须精确地传递和函数头部参数名一样多的参数。还能够定义变量名进行匹配,默认参数值(arg2=10),以及对于额外参数的容器,必须要根据变量名匹配对象,匹配完成后在传递机制的底层依然是赋值。这些工具对于编写库文件的人来说,要比应用程序开放者更有用。 规则 *位置:从左到右进行匹配 *关键字参数:通过参数名进行匹配。 【调用者】可以定义那个函数接受这个值,通过在调用时使用参数的变量名,使用name=value这种语法。 *默认参数:为没有传入值得参数定义参数值【定义函数时】 如果调用时传入的值过于少的话,函数能够为参数定义接受的默认值,在函数定义中使用name=value *可变参数:收集任意多基于位置或关键字的参数 以*开头,收集任意多的额外参数 *可变参数:传递任意多的基于位置或关键字的参数。【调用时】 调用者能够再使用*语法去将参数集合打散,分成参数。这个*与函数头部的*恰恰相反。在函数头部他意味着收集任意多的参数,而在调用者中意味着传递任意多的参数。 总结与特定模式有关的语法: 语法            位置    解释 func(value)        调用者    常规参数,通过位置进行匹配 func(name=value)    调用者    关键字参数,通过变量名匹配 func(*name)        调用者    以name传递所有的对象,并作为独立的基于位置的参数 func(**name)        调用者    以name成对的传递所有的关键字/值,并作为独立的关键字的参数 def func(name)        函数    常规参数:通过位置或变量名进行匹配 def func(name=value)    函数    默认参数值:如果没有在调用中传递的话,就是用默认值 def func(*name)        函数    匹配并收集(在元组中)所有包含位置的参数 def func(**name)    函数    匹配并收集(在字典中)所有包含位置的参数。 5、关键字参数和默认参数的实例 >>> def f(a,b,c): ...     print a,b,c ... >>> f(1,3,4) 1 3 4 关键词参数 >>> f(c=5,a=8,b=9)       8 9 5 >>> f(4,c=8,b=9)    4 9 8 >>> def func(name,age,job): ...     print 'name','age','job' ... >>> func('diege',18,'op') name age job >>> func(age=18,job='op',name='diege') name age job 关键字参数在调用中起到了数据标签的作用 默认参数,如果调用时没有传入值得话,在函数运行前,参数就被赋了默认值。 >>> def f(a,b=2,c=5): ...     print a,b,c ... >>> f(4) 4 2 5 >>> def f(a,b=2,c=5): ...     print a+b+c ... >>> f(4) 11 >>> f(6,5)  16 >>> f(a=10) 17 >>> f(a=3,b=4) 12 >>> f(2,c=6)     10 >>> f(6,7,8) 21 6、任意参数的实例 *和** 让函数支持接收任意数目的参数。 收集参数 第一种用法:在函数定义中,在元组中收集不匹配的位置参数 >>> def f(*args):print args ... >>> f() () **特性类似,但是它只对关键字参数有效。将这些关键字参数传递给一个新的字典。 >>> def f(**agrs):print args >>> f() >>> def f(**args):print args ... >>> f() {} min调用 def min1(*args):     res=args[0]     for arg in args[1:]:         if arg < res:             res=arg     return 三、函数的高级话题 (一)、匿名函数:lamdba lambad 创建了一个之后能够被调用的函数,它返回了一个函数而不是将这个函数赋值给一个变量名。 1、lambda表达式 lanbda arg1,arg2,...,argN:expression using arguments lambda 是一个表达式,而不是一个语句 lambda的主体是一个单个的表达式,而不是代码块 >>> def func(x,y,z):return x+y+z ... >>> func(2,3,4) 9 等同于 >>> f=lambda x,y,z:x+y+z >>> f(2,3,4) 9 默认参数也能够再lambda参数中使用,就像在def中使用一样。 >>> x=(lambda a='free',b='file',c='feel':a+b+c)   >>> x('well') 'wellfilefeel 为什么要使用lambda lambda 通常用来编写跳转表,也就是行为的列表或字典,能够按照需要执行相应的动作。 L=[(lambda x:x**2),(lambda x:x**3),(lambda x:x**4)] >>> for f in L: ...     print f(2) ... 4 8 16 >>> print L[0](3) 9 2、嵌套lambda和作用域 >>> def action(x): ...     return (lambda y:x+y) ... >>> act=action(99) >>> act <function <lambda> at 0x285066f4> >>> act(2) 101 (二) 作参数来应用函数 1、内置函数apply 当需要变得更加动态的话,可以通过将一个函数作为一个参数传递给apply来调用一个生成的函数,并且也将传给那个函数的参数作为一个元组传递给apply函数() 2、传入关键字参数 >>> echo(1,2,a=3,b=4) (1, 2) {'a': 3, 'b': 4} >>> arg1=(1, 2) >>> arg2={'a': 3, 'b': 4} >>> apply(echo,arg1,arg2) (1, 2) {'a': 3, 'b': 4} 3、和apply类似的调用语法 >>> apply(func,args) 9 >>> func(args) 9 >>> apply(echo,arg1,arg2) (1, 2) {'a': 3, 'b': 4} (三) 在序列中映射函数:map >>> L=[1,2,3,4,5] >>> updated=[] >>> for x in L:            ...     updated.append(x+10) ... >>> updated [11, 12, 13, 14, 15] 使用内置工具map,map函数会对一个序列对象中的每一个元素应用被传入的函数,并且返回一个包含了所有函数调用结果的一个列表。 >>> def inc(x):return x+10 ... >>> L=[1,2,3,4,5] >>> map(inc,L) [11, 12, 13, 14, 15] map(函数,传入函数的序列对象) >>> map(None,S1,S2) >>> L=[1,2,3,4,5]  map嵌套lambda       >>> map((lambda x:x+3),L) [4, 5, 6, 7, 8] 高级功能:提供了多个序列作为参数,它能够并行返回分别以每个序列的元素作为【函数对应参数】得到的结果的列表 >>> pow(3,4) 81 >>> map(pow,[1,2,3],[2,3,4])    #1**2,2**3,3**4 [1, 8, 81] (四) 函数式编程工具:filter和reduce 函数式编程的意思就是对序列应用一些函数的工具。 基于某一测试函数过滤出一些元素-filter 对每对元素都应用函数并运行到最后结果-reduce >>> range(-5,5) [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4] >>> filter((lambda x:x>0),range(-5,5)) [1, 2, 3, 4] 这个等效于for range:if语句 reduce稍微复杂一点。这里两个reduce调用,计算在一个列表中所有元素加起来和以及乘起来的乘积 >>> reduce((lambda x,y:x+y),[1,2,3,4]) 10 >>> reduce((lambda x,y:x*y),[1,2,3,4]) 24 (五)重访列表解析:映射 1、列表解析基础 >>> [x**2 for x in range(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> map((lambda x:x**2),range(10)) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 2、增加测试和嵌套循环 在for之后编写if分支,用来增加逻辑选择,if分支相当filter >>> [x for x in range(5) if x%2==0] [0, 2, 4] >>> filter((lambda x:x%2==0),range(5)) [0, 2, 4] filter出来的列表可以作为map的第2个参数 >>> map((lambda x:x**2),filter((lambda x:x%2==0),range(5))) [0, 4, 16] 3、列表解析和矩阵 4、理解列表解析 对ptyhon初学者,通常使用简单的for循环,在其他大多数情况下,使用map调用(除非它们会变得过于复杂) 列表解析比map快,map比for循环快2倍 (六)重访迭代器:生成器 编写的函数能够返回一个值,并且稍后还可以从它刚才离开的地方仍然返回值。这样的函数被认作是生成器,因为它们随时间生成一个序列的值。 大多数方面生成器函数就像一般函数,在Python它们被自动用作实现迭代协议,因它只能够再迭代的语境中出现。 生成器和一般的函数之间代码上最大的不同就是一个生成器yield一直,而不是return一个值。yield语句将会将函数关起,并向它的调用者返回一个值 但是保存足够的状态信息为了让其能够在函数从它挂起的地方恢复。 包含yield的语句的函数将会特地编译成为生成器。当调用它时,他们返回一个生成器对象,这个生成器对象支持迭代器对象接口。 1、生成器实例的。 >>> def Dtest(N): ...     for i in range(N): ...             yield i**2 使用 >>> for i in Dtest(5): ...     print i,':', ... 0 : 1 : 4 : 9 : 16 : 查看过程 >>> x=Dtest(4) >>> x.next() 0 >>> x.next() 1 >>> x.next() 4 >>> x.next() 9 >>> x.next() for循环和生成器是一样的:通过重复调用next方法,知道捕获一个异常。 2、扩展生成器协议send和next 生成器函数协议中增加了一个send方法,send方法生成一系列结果的下一个元素,这一点就像next方法一样,但是它也提供了 一种调用者与生成器之间的进行通信的方法,从而能偶影响它的操作。 yiled是一个表达式,可以返回传入的元素来发送,而不是一个语句。值是通过调用本身send(value)方法传给生成器的。 之后恢复生成器的代码,并且yield表达式返回了为了发送而传入的值。如果调用了正常的放next()方法,yield返回None 3、迭代器和内置类型 内置的数据类型设计了对应于内置函数iter的迭代器对象。字典迭代器在每次迭代中产生关键字列表元素。 >>> D={'a':1,'b':2,'c':3} >>> x=inter(D) >>> x.next()  'a' >>> x.next() 'c' >>> x.next() 'b' >>> x.next() Traceback (most recent call last):   File "<stdin>", 所有迭代内容(包括for循环,map调用,列表解析等)一次设计用来自动调用iter函数。 通过支持迭代协议的类来实现任意的生成器对象是可能的,并且已经有很多这样的对象,在for循环和其他的迭代环境中使用。 这样的类定义了一个特别的__iter__方法,它将返回一个迭代对象。 4、生成器表达式:迭代器遇到列表解析 迭代器和列表解析的概念形成了这个语言的一个新的特性,生成器表达式。 (八)函数设计概念 *耦合性:对于输入使用参数,并且对于输出使用return语句 *耦合性:只有在真正必要的情况下使用全局变量。 *耦合性:不要改变可变类型的参数,除非调用者希望这样做。 *聚合性:每一个函数都应该有一个单一的,同一的目标 *大小:每一个函数应该相对较小。 *耦合:避免直接改变在另一个模块文件中的变量。 函数是对象:简洁调用 (九)函数陷阱 1、本地变量是静态检测的 >>> X=99 >>> def selector(): >>> def selector(): ...     import __main__ ...     print __main__.X ...     X=88 ...     print X ... >>> selector() 99 88 >>> X 99 所有的全局变量都再 __main__。 __main__就是顶层的命名空间.__main__.X得到了全局变量版本的X。 这里使用模块的属性标记来获得其全局变量。 2、默认和可变对象。 默认参数是在def语句运行时被评估并保存的,而不是在这个函数调用时。从内部来将,Python会将每一个默认 参数保存成一个对象。附加在这个函数本身。 3、没有return语句的函数 函数中return和yield语句是可选择。没有返回值函数自动返回None对象。 这样的函数被当做语句,就像他们只执行任务而不要计算有用的结果一样。 4、嵌套作用域的循环变量

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-09-12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档