Python第四课----函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python第四课----函数相关的知识,希望对你有一定的参考价值。

函数

一、函数

由若干语句组成的语句块,函数名称、参数列表构成,它是组织代码的最小单元。

二、函数的作用

1、对代码的最基本封装,按照功能组织一段代码。
2、目的为了复用,减少冗余代码。

三、函数分类

1、内建函数:max(),reversed()。
2、库函数:math.ceil。

四、def语句定义函数   

def 函数名(参数列表)
  函数体(代码块)
  [return 返回值]
函数名就是标识符,命名要求一样。
语句块缩进四个空格。
函数中如果没有return语句,隐式会返回一个None值。
定义中的参数列表是形式参数,只是一种表达,简称形参。
2、调用
函数定义,只是声明,不会执行,需要调用
加上小括号调用
调用时写的参数是实际参数,是传入的值,简称实参

  五、函数的定义,调用

def add(x,y):
  result = x+y
  return result
out = add(4,5)
print(out)
函数---->add,计算结果通过返回值返回、返回值可以使用变量接收,函数是可调用对象,callable(add)试一下,是通用的

六、函数参数

1、参数调用时,传入的参数要和定义的个数匹配(可变例外)
2、位置参数:def f(x,y,z) 调用时:f(3,4,5),按照顺序传入实参
3、关键参数:def f(x,y,z) 调用时:f(x=3,y=4,z=5),使用形参名字传入实参的方式,顺序无所谓
4、传参:f(z=None,y=10,x=[1])、f((1,),z=6,x=4.1)、f(y=5,z=6,2)最后这种不行,位置参数必须在关键字参数之前传入

七、参数默认值

1、参数默认值:def f(x=4,y=5):这个时候,x,y都有默认值,默认可以输出
2、参数非常多的时候,并不需要输出所有参数,有默认值就可以了

八、可变参数

1、问题:有多个数,累加求和
    def add(nums):----这样的话,nums需要是一个可迭代对象
2、可变位置参数(一个星号)一个形参可以匹配任意个参数x
    def add(*args):----sum=0,for x in args:----sum+=x
3、可变关键字参数(两个星号)
def add(**kwargs):
  for k,v in kwargs.items( ):
     print(“{}={}”.format(k,v))
add(x=1,y=2)
只能用关键字调用,组成的是个字典
4、混合使用参数、可变参数:
    1、def  showconfig(username,password,**kwargs)
  2、def  showconfig(username,*args,**kwargs)
  3、def  showconfig(username,password=“mage”,*args,**kwargs)
  4、def fn(*args,x,y,**kwargs):---->这么写,调用必须对唯一关键词x、y进行关键字传参
  5、fn(*,x,y)强制将x,y变成唯一关键词
  6、fn(*agrs,x=5)默认值给了可以直接调用fn()

九:参数解构----实参解构       

1、fn(x,y):
       return(x+y)
   fn(*(4,5))/*[4,5]/*{4,5}/fn(*range(1,3))/fn((1,2)[0],[3][0])
2、字典解构fn(**{x:5,y:6})或者fn(*d.keys())或d.valus()
3、def fn(*args):
    print(args)
   fn(*[1,2,3])
4、def fn(*args):
    sum = 0
    for x in args:
      sum += x
    print(sum)

十:返回值

十一:作用域

1、一个标识符的可见范围,也就是变量,一般说变量的作用域
2、x = 5           x = 5
  def foo():         def foo():
  print(x)             x+=1
   foo()                                                print(x)
可执行,x为全局变量       foo()不可执行,下方的x+=1,实际上是重新定义变量x,但是并不存在
3、全局作用域,global变量,可以管辖下面的函数,但函数内部高度自治,自己管自己局部作用域,local变量,里面可以使用外部的变量,但本地变量,只能在内部使用,外部不可见
4、嵌套结构
def outer( ):                        def outer( ):
  o = 65                           o = 65
  def inner( ):                         def inner( ):
      print("inner { }".format(o))                o = 97
      print(chr(o))                       print("inner { }".format(o))
      print("outer { }".format(o))                print(chr(o))
  inner( )                             print("outer { }".format(o))
outer( )     打印65,65,A                    inner( )  
外部变量内部可用,但赋值即定义                                 outer( )打印结果65,97,a
x = 5
def foo( ):
   y = x+1
   x = 1
   print(x)
foo( )报错,赋值即定义,上面x用不上,下面的又没有定义就被y拿来使用
5、全局变量global
x = 5                                 def foo():
def foo():                            global x
   global  x                          x = 10
   x+=1                              x +=1     
将x声明为使用外部的全局作用域,外面必须有x的定义               这个x=10,是全局变量,是为外面定义一个变量
6、闭包
自由变量:未在本地作用域定义的变量,例如定义在外层函数作用域的变量
闭包:出现在嵌套函数中,指的是内层函数引用了外层函数的自由变量
def counter():
  c = [0]
  def inc( ):
    c[0] += 1
    return c[0]
  return inc
foo = counter( )
print(foo( ),foo( ))
c = 100
print(foo( ))   每次局部变量应该消失,但[ ]是引用对象,每次都会改变,借用的是引用类型
7、nonlocal关键字----关键字绝对不能被占用
使用了nonlocal关键字,将变量标记为在上级的局部作用域中定义,是上级的局部作用域,而不是全局作用域
函数调用为什么会循环count+=1???
def  counter():
   count = 0
   def inc():
     nonlocal  count
     count +=1
     return count
   return inc
foo = counter( )
print(foo( ),foo( ))     闭包内的函数,在外面foo调用的时候,保留了count这个变量,而且每次都执行了+1

       

8、函数默认值的作用域:(foo.__defaults__)使用两个下划线+defaults+两个下划线
def foo(xyz=[]):
  xyz.append(1)
    print(xyz)
print(foo(),id(foo))
print(foo.__defaults__)
print(foo(),id(foo))
print(foo.__defaults__)    
函数的默认值不会发生变化,缺省值不会改变,是个元组,但元组内的列表发生了改变,这是个引用
def foo(w,u="abc",z=123):
  u = "xyz"
  z = 456
  print(w,u,z)
print(foo.__defaults__)
foo("magedu")
print(foo.__defaults__)   
函数的默认值不会发生改变,重新赋值的展示在函数调用里
9、默认值的作用域用法:
def foo(xyz=[],u="abc",z=123):
  xyz=xyz[:]
  xyz.append(1)
  print(xyz)
foo()
print(foo.__defaults__)
foo()
print(foo.__defaults__)
foo([10])
print(foo.__defaults__)
foo([10,5])
print(foo.__defaults__)
xyz重新被赋值定义,做了拷贝,原xyz还是不变,默认值始终不变
def foo(xyz=None,u="abc",z=123):
  if xyz is None:
    xyz=[]
    xyz.append(1)
    print(xyz)
foo()
print(foo.__defaults__)
foo()
print(foo.__defaults__)
lst = [10]
foo(lst)
print(lst)
print(foo.__defaults__)
foo([10,5])
print(foo.__defaults__)
使用不可变类型默认值,如果使用none,则创建新列表,如果,传入一个列表,就修改这个列表,lst发生了变化,但是默认值一直没有发生变化,始终是None,abc,123的元组
def foo(x=None):
  if x == None:
    x = []
    x.append(1)
    return x
lst = foo()
a = foo(lst)
print(a)
一般这么写函数,lst=foo()就会执行一次foo(),结果是[1],a=foo(lst)会再执行一次,结果就是[1,1]

十二、函数销毁:

del或重新赋值

十三、树:     

1、定义:
  (1)、非线性解构,每个元素可以有多个前驱和后继(这句话,是前驱0或1,后继多个)
 (2)、树是n≥0个元素的集合
  (3)、n = 0,则是空树,树的根Root没有前驱
 (4)、其余元素只能有一个前驱,多个后继
2、递归定义:
  (1)、有且只有一个特殊元素根,其余元素划分为m个互不相交的集合T1,T2.。。。Tm,每一个集合都是树,称为T的子树Subtree
  (2)、子树也有自己的根
3、树的概念                                                              
  (1)、结点,树中的数据元素,每个元素都是一个结点
 (2)、结点的度degree:结点拥有的子树的数目,称为度,记作d(v),B的度是1,C的度是2,D的度是3
 (3)、叶子结点,结点的度为0,则是叶子结点leaf、终端结点,末端结点
 (4)、分支结点,结点度不为0,则是分支结点  ABCDE
 (5)、分支,结点之间的关系,A和B的分支,关系,这条线
 (6)、内部结点,除掉根和叶子结点,中间的结点
 (7)、树的度:树内各结点,谁的度数大,树的度数就是多少,上图为3
 (8)、孩子(儿子Child)结点,结点的子树的根节点成为成为该结点的孩子
 (9)、双亲(父Parent)结点:一个结点是它各个子树的根结点的双亲
 (10)、兄弟结点(sibling):具有相同双亲结点的结点
 (11)、祖先结点:从根结点到该结点所经分支上所有的结点。ABD都是G的祖先
 (12)、子孙结点:结点的所有子树上的结点都成为该结点的子孙,B的子孙是GDHI
 (13)、结点的层次(Level):根结点为第一层,根的孩子是第二层,以此类推,记作L(v)
 (14)、树的深度(高度Depth):树的层次的最大值,上图深度为4
 (15)、堂兄弟,双亲在同一层的结点
4、树的概念:
 (1)、有序树:结点的子树是有顺序的,不能交换
 (2)、无序树:结点的子树是无序的,可以交换
 (3)、路径:树的k个结点n1,n2,。。。nk,满足ni是n(i+1)的双亲,成为n1到nk的一条路径,就是一条线下来的,前一个是后一个的父结点,A-B-D-G
 (4)、路径长度:路径上结点数-1
 (5)、森林:m≥0颗不相交的树的集合 D、E、F,结点的子树集合就是森林
5、树的特点:
 (1)、唯一的根
 (2)、子树不相交
  (3)、除了根之外,每个元素只有一个前驱,0或多个后继
 (4)、根结点没有前驱,叶子结点没有后继
 (5)、如果vi是vj的双亲,则L(vi)=L(vj)-1,双亲比孩子Level小1
 (6)、堂兄弟的双亲不一定是兄弟

十四:二叉树

1、每个结点最多两颗子树:二叉树不存在度数大于二的结点
2、二叉树是有序树,左子树,右子树是有顺序的,不能交换
3、即使某个结点只有一棵树,也要确定它是左子树还是右子树
4、二叉树的五种形态
 (1)、空二叉树   
 (2)、只有根结点的二叉树
 (3)、根结点只有左子树
 (4)、根结点只有右子树
 (5)、根结点有左子树和右子树

十五、斜树:

1、左斜树:全是左子树
2、右斜树:全是右子树

十六、满二叉树:       

1、一颗二叉树的所有分支结点都存在左子树和右子树,并且叶子结点只存在最下面一层,一个都不能少,左右完全对称
2、同样深度中,满二叉树结点最多
3、k为深度(1≤k≤n),则结点总数为2**k-1

十七:完全二叉树:       

1、若二叉树的深度为k,则二叉树的层数从1到k-1层的结点数都达到了最大个数,在第k曾的所有结点都集中在最左边,这就是完全二叉树(最后一层,从左到右,不能空)
2、满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树 
3、H在左边,若E有一个分支结点,则不是,必须D有两个,E有一个左子树,才是完全二叉树

十八、二叉树性质:   

1、在二叉树的第i层上最多有2**(i-1)个结点
2、深度为k的二叉树,至多有2**k-1个结点
3、对于任意一颗二叉树T,如果其终端结点为n0,度数为2的结点为n2,则有n0=n2+1(叶子结点,是度数为2的结点加1)上图中,叶子结点n0=4(HEFG),n2=3(ABC)
4、叶子结点数-1就等于度数为2的结点数
   证明:n0+n1+n2=n(0叶子,1度数为1,2度数为2):
      n0+n1+n2-1(一棵树的分支数为n-1(总数减去根结点))
      分支数还等于n0*0+n1*1+n2*2-----2n*2+n1
      2*n2+n1=n0+n1+n2-1---->n2=n0-1
5、高度为k的二叉树,至少有k个结点(左斜树)
7、具有n个结点的完全二叉树的深度为int((log2n+1))n开方+1取整,或者math.ceil(log2(n+1))
8、如果有一颗n个结点的完全二叉树,可以按照层序编号
 (1)、如果i=1,则结点i是二叉树的根,无双亲,如果i>1,则其双亲是int(i/2),向下取整。就是子结点的编号整除2得到的就是父结点的编号。父节点如果是i,左孩子结点就是2i,右孩子就是2i+1
 (2)、如果2i>n,则结点无左孩子,即结点i为叶子结点,否则其左孩子结点存在编号为2i
 (3)、如果2i+1>n,则结点i无右孩子,否则右孩子存在编号为2i+1

十九、变量名解析原则LEGB    

1、Local----先本地作用域,调用结束消亡
2、Enclosing,嵌套函数的闭包的外部函数的命名空间
3、Global----全局,解释器退出时消亡
4、Build-in 内置模块的命名空间,解释器启动到退出,就是生命周期,print、open等

二十、函数执行流程:

1、函数执行流程:              全局帧中生成foo1、2、3、main函数对象
def foo1(b,b1=3):              main函数调用
  print("foo1 called",b,b1)      main中查找内建函数print压栈,将常量字符串压栈,调用函数,弹出栈顶
def foo2(c):                  main中全局查找函数foo1压栈,将常量100,101压栈,调用foo1函数,
  foo3(c)                  创建栈帧,print压栈,字符串和常量压栈,调用函数,弹出栈顶,返回值。  
  print("foo3 called",c)            后续全部类似
def foo3(d):
  print("foo3 called",d)
def main():
  print("main called")
  foo1(100,101)
  foo2(200)
  print("main called")
main()

二十一、递归Recursion

        1、函数直接或间接调用自身,就是递归

        2、递归需要边界条件

        3、当不满足边界条件时,递归前进,当满足边界条件时,递归结束。


本文出自 “13277682” 博客,谢绝转载!

以上是关于Python第四课----函数的主要内容,如果未能解决你的问题,请参考以下文章

Python 基础 2022 最新第四课 基础语法

Python 基础 2022 最新第四课 基础语法

Python 基础 2022 最新第四课 基础语法

进阶第四课 Python模块之os

python第二模块 步骤一 第四课数据库的高级查询

进阶 第四课:函数(第四节)