形参和实参

形参即函数内使用的参数,实参即调用函数时的赋值,如下:

  def tmp(name):  # 形参
  	print(name)
  
  tmp('实参')

形参类型

  • 位置参数
    函数内使用到的形参为关键参数,即调用该函数时必须传入的参数。

  • 默认参数
    如:tmp(name=‘lz’,age),此时形参name即为默认参数,默认值为lz。

  • 可变参数
    如:tmp(*params),此时传入的参数可以为任意个参数,接收的是一个tuple()

  • 关键字参数
    如:tmp(**params),接受的是一个dict{}

  • 命名关键字参数
    如:tmp(name, age, , sex),此时后的sex即为命名关键字参数,也就是调用时必须sex=’’,tmp(‘name’, ‘age’, sex=‘man’);若是tmp(name, age, *, sex=‘man’),此时调用是可以不传入sex参数。

除了可变参数无法与命名关键字参数混合,其余皆可混合使用,但是定义的顺序必须为:必选参数、默认参数、可变参数\命名关键字参数、关键字参数。

  def tmp(*params, name='lz', age='24'):
      for param in params:
          print('param:' + param)
  	print(name)
  	print(age)

  tmp(11, name='ss',age='22')  
  """
  	1.在调用含有可变参数的函数时,在可变参数后的形参进行设置默认值。
  	2.在调用函数时,尽量将调用函数内的参数写为:形参=实参,这样增加代码的可读性,也使得增加函数调用的准确性。
  """

函数和过程

函数是用返回值的,过程是没有返回值的。**对于python严格来说,只有函数,没有过程!
函数也可以有多个返回值。
如下个例子:

  def hello():
  	print('hello python')

  tmp = hello()
  print(tmp)  # None
  print(type(tmp))  # <class 'NoneType'>

  # 返回多个至
  def returnTmp(name, age):
      return '名字:' + name, '年龄:' + str(age)

  name, age = returnTmp('lz', 24)

  print(name, age)  #名字:lz 年龄:24

可以看出函数都是用返回值的。这是因为python都是动态的确定变量类型,其实就是没有变量,只有名字。

全局变量和局部变量

函数内的即局部变量,函数外的即为全局变量,函数外访问局部变量会出错。
函数可以访问全局变量,但不要试图去修改全局变量,因为在函数内修改全局变量的话,python会在该函数新定义一个名字一样的局部变量。

  def tmp():
      print(g_name)  # 报错UnboundLocalError: local variable 'g_name' referenced before assignment,如果不加:g_name = 'lz1',则不报错
      g_name = 'lz1'
      print(g_name)

  g_name = 'lz'
  tmp()
  print(g_name)
  # lz1
  # lz

global关键字

如果在函数内部试图修改全局变量,Python会使用屏蔽的方式(shadowing机制)去保护全局变量,即创建该函数内的同名的局部变量,所以这样就算修改,也只是修改了函数创建的局部变量,而全局变量却没有改变。
global关键字提供了函数内修改全局变量的方法。

 name = 'lz'
 def tmp():
     global name
     name = 'lzz'

 tmp()
 print(name)  # lzz,成功修改

递归

  • 递归形成有两个条件:

    • 必须有一个明确的结束条件(递归出口);
    • 每次递归都是为了让问题规模变小

    递归其实就是分治思想。而递归层数一旦过多会导致栈溢出,并且相对循环,递归效率差很多。所以只是合适的地方使用递归,而不是每个能递归的问题都是用递归。
    以下直接使用一个递归与非递归的斐波那契数列的例子,来表达递归及两者之间的效率差别。

  # 如果设置成35甚至更大,迭代结果立即出来,而递归则很慢
  def fab(n):
      n1 = 1
      n2 = 1
      n3 = 1
      if n < 1:
          print('输入有误')
          return -1
      while (n - 2) > 0:
          n3 = n2 + n1
          n1 = n2
          n2 = n3
          n -= 1
      return n3
  print(fab(20))

  def fab_recursion(n):
      if n < 1:
          return -1
      if n == 1 or n == 2:  # 结束条件
          return 1
      else:
          return fab(n-1) + fab(n-2)  #缩小问题
  print(fab_recursion(20))  

  • 汉诺塔
    汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

    • 汉诺塔问题解释
      我们假设三个指针为 A、B、C
    • hanoi(1):如果只有一个盘子,直接A->C
    • hanoi(2,A,B,C):如果两个盘子,即:A->B,A->C,B->C
    • 如果三个盘子,即:hanoi(2,A,C,B),A->C,hanoi(2,B,A,C)
      因此如果是n个盘子,就是这样的过程:hanoi(n-1,A,C,B),A->C,hanoi(n-1,B,A,C)
    • 代码实现:
      根据以上分析,可以得到以下代码:
     def hanoi(n, A, B, C):
         if n == 1:
             print(A, '->', C)
         else:
             hanoi(n - 1, A, C, B)
             print(A, '->', B)
             hanoi(n - 1, B, A, C)
    
     hanoi(3, 'A', 'B', 'C')
    

个人博客:Loak 正 - 关注人工智能及互联网的个人博客
文章地址:Python基础(五)—函数(参数解析、global、递归)