设为首页 收藏本站
查看: 1599|回复: 0

[经验分享] Python学习笔记整理(十二)Python的函数

[复制链接]

尚未签到

发表于 2018-8-4 10:38:46 | 显示全部楼层 |阅读模式
  一、函数基础
  函数可以计算出一个返回值。作用:最大化代码重用,最小化代码冗余,流程的分解
  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 &quot;<stdin>&quot;,
  所有迭代内容(包括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、嵌套作用域的循环变量

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-546350-1-1.html 上篇帖子: Python实战(5)Python和Shell打包压缩文件效率对比 下篇帖子: Python环境搭建—安利Python小白的Python安装详细教程
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表