Python——函数设计与使用

小灰灰 2023-09-23 13:52 135阅读 0赞

文章目录

  • 函数定义
    • 注意事项:
  • 形参与实参
    • 验证
  • 参数类型
    • 必备参数
    • 默认值参数
    • 位置参数
    • 关键字参数
    • 可变长度参数
      • *args的用法
      • **kw的用法
      • 参数传递的序列解包
  • return语句
  • 变量作用域

函数定义

提示:这里可以添加本文要记录的大概内容:
①、函数是最基本的一种代码抽象的方式,将需要反复执行的代码封装为函数,并在需要该功能的地方进行调用,不仅可以实现代码复用,更重要的是可以保证代码的一致性,只需要修改该函数代码则所有调用均受到影响。

②、设计函数时,应注意提高模块的内聚性,同时降低模块之间的隐式耦合。

③、在编写函数时,应尽量减少副作用,尽量不要修改参数本身,不要修改除返回值以外的其他内容。
应充分利用Python函数式编程的特点,让自己定义的函数尽量符合纯函数式编程的要求。

  1. def 函数名([参数列表]):
  2. 函数体
  3. [return [表达式]]

注意事项:

函数形参不需要声明其类型,也不需要指定函数返回值类型

即使该函数不需要接收任何参数,也必须保留一对空的圆括号

括号后面的冒号必不可少

函数体相对于def关键字必须保持一定的空格缩进

Python允许嵌套定义函数

return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的
return相当于返回 None。

提示:下面案例可供参考

【例1】长方形面积函数定义和调用

  1. def area(width, height):
  2. '''计算长方形面积'''
  3. return width * height
  4. w = 4
  5. h = 5
  6. print("width =", w, " height =", h, " area =", area(w, h))

【例2】如果想定义一个什么事也不做的空函数,可以用pass语句

  1. >>> def nop():
  2. pass

pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。

【例3】生成斐波那契数列的函数定义和调用

  1. def fib(n):
  2. a, b = 1, 1
  3. while a < n:
  4. print(a, end=' ')
  5. a, b = b, a+b
  6. fib(1000)

提示:下面案例可供参考

形参与实参

1、函数定义时括弧内为形参,一个函数可以没有形参,但是括弧必须要有,表示该函数不接受参数。

函数调用时向其传递实参,将实参引用(地址)传递给形参。

  1. def fib(n): #n形参
  2. a, b = 1, 1
  3. while a < n:
  4. print(a, end=' ')
  5. a, b = b, a+b
  6. fib(1000) #1000实参

2、在定义函数时,对参数个数并没有限制,如果有多个形参,需要使用逗号进行分隔。
编写函数,接受两个整数,并输出其中最大数。

  1. def printMax(a, b):
  2. if a>b:
  3. pirnt(a, 'is the max')
  4. else:
  5. print(b, 'is the max')

3、对于绝大多数情况下,在函数内部直接修改形参的值不会影响实参。例如:

  1. >>> def addOne(a):
  2. print(a)
  3. a += 1
  4. print(a)
  5. >>> a = 3
  6. >>> addOne(a)
  7. 3
  8. 4
  9. >>> a
  10. 3

可以看出,函数内部修改了形参a的值,但当函数运行结束后,实参a的值并未被修改

4、在有些情况下,可以通过特殊的方式在函数内部修改实参的值,例如下面的代码。

  1. >>> def modify(v): #修改列表元素值
  2. v[0] = v[0]+1
  3. >>> a = [2,4]
  4. >>> modify(a)
  5. >>> a
  6. [3,4]
  7. >>> def modify(v, item): #为列表增加元素
  8. v.append(item)
  9. >>> a = [2]
  10. >>> modify(a,3)
  11. >>> a
  12. [2, 3]
  13. >>> def modify(d): #修改字典元素值或为字典增加元素
  14. d['age'] = 38
  15. >>> a = {
  16. 'name':'jack', 'age':37, 'sex':'Male'}
  17. >>> a
  18. {
  19. 'age': 37, 'name': 'jack', 'sex': 'Male'}
  20. >>> modify(a)
  21. >>> a
  22. {
  23. 'age': 38, 'name': 'jack', 'sex': 'Male'}

也就是说,如果传递给函数的是可变序列,并且在函数内部使用下标或可变序列自身的方法增加、删除元素或修改元素时,修改后的结果是可以反映到函数之外的,实参也得到相应的修改。



验证

传不可变对象:不会改变外面实参值

  1. def changeInt( a ):
  2. a = 10
  3. b = 2
  4. ChangeInt(b)
  5. print( b ) # 结果是 2

不可变对象:数字类型、元组、字符串

不可变类型:类似 c 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
可变类型:类似 c的指针传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响
画图解释

传可变对象实例:会改变外面实参值

  1. def changeList( blist ):
  2. blist.append([4,5,6])
  3. print ("函数内取值: ", blist)
  4. # 结果是 [1,2,3,4,5,6]
  5. alist = [1,2,3]
  6. changeList(alist)
  7. print( alist ) # 结果是 [1,2,3,4,5,6]

可变对象:列表、字典、集合等

当一个引用传递给函数的时候,函数自动复制一份引用。这个函数里的引用和外边的引用没有任何关系了.所以函数把引用指向了一个不可变对象,当函数返回的时候,外面的引用没半毛关系.
而第函数内的引用指向的是可变对象,对它的操作就和定位了指针地址一样,在内存里进行修改.

传不可变对象:函数内部直接修改形参的值不会影响实参
传可变对象:函数内部修改实参的值会影响到实参

形参和实参变量各自有不同的存储单元,当一个引用传递给函数的时候,函数自动复制一份引用



参数类型

在Python中,函数参数有很多种:可以为普通参数、默认值参数、关键参数、可变长度参数等。

Python在定义函数时不需要指定形参的类型,完全由调用者传递的实参类型以及Python解释器的理解和推断来决定。类似于重载和泛型。

Python函数定义时也不需要指定函数的返回值类型,这将由函数中的return语句来决定,如果没有return语句或者return没有得到执行,则认为返回空值None。

必备参数

必需参数须以正确的顺序传入函数。调用时的数量、参数类型、位置必须和声明时的一样。否则会出现语法错误。

  1. def add( x , y ):
  2. return x+y

默认值参数

默认值参数:在定义函数时为形参设置默认值。

默认值参数必须出现在函数参数列表的最右端,任何一个默认值参数右边不能有非默认值参数。

  1. def 函数名(...,形参名=默认值):
  2. 函数体

调用带有默认值参数的函数时,可以不对默认值参数进行赋值,也可以通过显式赋值来替换默认值,具有很大的灵活性。

  1. >>> def say( message, times =1 ):
  2. print(message * times)
  3. >>> say('hello')
  4. hello
  5. >>> say('hello',3)
  6. hello hello hello
  7. >>> say('hi',7)
  8. hi hi hi hi hi hi hi

注意:

默认值参数的赋值只在函数定义时被解释一次

  1. >>> i = 3
  2. >>> def f(n=i): #参数n的值仅取决于i的当前值
  3. print(n)
  4. >>> f()
  5. 3
  6. >>> i = 5 #函数定义后修改i的值不影响参数n的默认值
  7. >>> f()
  8. 3

默认参数必须指向不变对象!

1、可以使用“函数名.defaults”查看所有默认参数的当前值,返回值为元组,其中元素依次表示每个默认值参数的当前值。

  1. >>> say.__defaults__
  2. (1,)
  3. >>> f.__defaults__ #查看函数默认值参数的当前值
  4. (3,)

2、默认值参数必须出现在函数参数列表的最右端,且任何一个默认值参数右边不能有非默认值参数。(为了避免歧义)

  1. >>> def f(a=3,b,c=5):
  2. print(a,b,c)
  3. >>> def f(a=3,b):
  4. print(a,b)
  5. >>> def f(a,b,c=5):
  6. print(a,b,c)
  7. >>> def f(a,b,c=5,d=5):
  8. print(a,b,c,d)
  9. >>> def f(a,b,c=5,d,e=8):
  10. print(a,b,c,d)

3、默认值参数如果使用不当,会导致很难发现的逻辑错误,例如:

  1. def demo(newitem,old_list=[]):
  2. old_list.append(newitem)
  3. return old_list
  4. print(demo(5,[1,2,3,4]))
  5. A [1, 2, 3, 4, 5] B [1, 2, 3, 4] C 报异常
  6. print(demo('aaa',['a','b']))
  7. A ['a', 'b', 'aaa'] B ['a', 'b'] C 报异常
  8. print(demo('a'))
  9. A ['a'] B [] C 报异常
  10. print(demo('b'))
  11. A ['b'] B ['a', 'b'] C 报异常
  12. #正确代码如下:
  13. def demo(newitem,old_list=None):
  14. if old_list is None:
  15. old_list=[]
  16. old_list.append(newitem)
  17. return old_list
  18. print(demo('5',[1,2,3,4]))
  19. print(demo('aaa',['a','b']))
  20. print(demo('a'))
  21. print(demo('b') )

位置参数

位置参数(positional arguments)是比较常用的形式,调用函数时实参和形参的顺序必须严格一致,并且实参和形参的数量必须相同。

  1. >>> def demo(a, b, c):
  2. print(a, b, c)
  3. >>> demo(3, 4, 5) #按位置传递参数
  4. 3 4 5
  5. >>> demo(3, 5, 4)
  6. 3 5 4
  7. >>> demo(1, 2, 3, 4) #实参与形参数量必须相同
  8. TypeError: demo() takes 3 positional arguments but 4 were given

关键字参数

关键字参数主要指实参,即调用函数时的参数传递方式。

通过关键字参数,按照参数名字传递,实参顺序可以和形参顺序不一致,但不影响传递结果,避免了用户需要牢记位置参数顺序的麻烦。

  1. >>> def demo(a,b,c=5):
  2. print(a,b,c)
  3. >>> demo(3,7)
  4. 3 7 5
  5. >>> demo(a=7,b=3,c=6)
  6. 7 3 6
  7. >>> demo(c=8,a=9,b=0)
  8. 9 0 8


可变长度参数

可变长度参数主要有两种形式:
*args 用来接受多个实参并将其放在一个元组中
**kw接受关键字参数并存放到字典中

可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。
而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。

*args的用法

接收多个参数放元组里
加了星号 * 的参数会以元组(tuple)的形式导入

  1. >>> def demo(*p):
  2. print(p)
  3. >>> demo(1,2,3)
  4. (1, 2, 3)
  5. >>> demo(1,2,3,4,5,6,7)
  6. (1, 2, 3, 4, 5, 6, 7)

**kw的用法

接受关键参数并存放到字典中
两个星号 ** 的参数会以字典的形式导入

  1. >>> def demo(**p):
  2. for item in p.items():
  3. print(item)
  4. >>> demo(x=1,y=2,z=3)
  5. ('y', 2)
  6. ('x', 1)
  7. ('z', 3)

参数传递的序列解包

传递参数时,可以通过在实参序列前加一个星号将其解包,然后传递给多个单变量形参。

  1. >>> def demo(a, b, c):
  2. print(a+b+c)
  3. >>> seq = [1, 2, 3]
  4. >>> demo(*seq)
  5. 6
  6. >>> tup = (1, 2, 3)
  7. >>> demo(*tup)
  8. 6

注意:调用函数时如果对实参使用一个星号*进行序列解包,这么这些解包后的实参将会被当做普通位置参数对待,并且会在关键参数和使用两个星号**进行序列解包的参数之前进行处理。

return语句

return语句用来从一个函数中返回一个值,同时结束函数。
如果函数没有return语句,或者有return语句但是没有执行到,或者只有return而没有返回值,Python将认为该函数以return None结束。

  1. def maximum( x, y ):
  2. if x>y:
  3. return x
  4. else:
  5. return y

在调用函数或对象方法时,一定要注意有没有返回值,这决定了该函数或方法的用法

  1. >>> a_list = [1, 2, 3, 4, 9, 5, 7]
  2. >>> print(sorted(a_list))
  3. [1, 2, 3, 4, 5, 7, 9]
  4. >>> print(a_list)
  5. [1, 2, 3, 4, 9, 5, 7]
  6. >>> print(a_list.sort())
  7. None
  8. >>> print(a_list)
  9. [1, 2, 3, 4, 5, 7, 9]

变量作用域

变量起作用的代码范围称为变量的作用域,不同作用域内变量名可以相同,互不影响。
一个变量在函数外部定义和在函数内部定义,其作用域是不同的。
在函数内部定义的普通变量只在函数内部起作用,称为局部变量。当函数执行结束后,局部变量自动删除,不再可以使用。
局部变量的引用比全局变量速度快,应优先考虑使用。

形参属于局部变量

如果想要在函数内部给一个定义在函数外的变量赋值,那么这个变量就不能是局部的,其作用域必须为全局的,能够同时作用于函数内外,称为全局变量,可以通过global来定义。这分为两种情况:
一个变量已在函数外定义,如果在函数内需要为这个变量赋值,并要将这个赋值结果反映到函数外,可以在函数内用global声明这个变量,将其声明为全局变量。
在函数内部直接将一个变量声明为全局变量,在函数外没有声明,该函数执行后,将增加为新的全局变量。

  1. >>> def demo():
  2. global x
  3. x = 3
  4. y = 4
  5. print(x,y)
  6. >>> x = 5
  7. >>> demo()
  8. 3 4
  9. >>> x
  10. 3
  11. >>> y
  12. NameError: name 'y' is not defined
  13. >>> del x
  14. >>> x
  15. NameError: name 'x' is not defined
  16. >>> demo()
  17. 3 4
  18. >>> x
  19. 3
  20. >>> y
  21. NameError: name 'y' is not defined

注意:在某个作用域内只要有为变量赋值的操作,该变量在这个作用域内就是局部变量,除非使用global进行了声明。

  1. >>> x = 3
  2. >>> def f():
  3. print(x) #本意是先输出全局变量x的值,但是不允许这样做
  4. x = 5 #有赋值操作,因此在整个作用域内x都是局部变量
  5. print(x)
  6. >>> f()
  7. Traceback (most recent call last):
  8. File "<pyshell#10>", line 1, in <module>
  9. f()
  10. File "<pyshell#9>", line 2, in f
  11. print(x)
  12. UnboundLocalError: local variable 'x' referenced before assignment

如果局部变量与全局变量具有相同的名字,那么该局部变量会在自己的作用域内隐藏同名的全局变量。

  1. >>> def demo():
  2. x = 3 #创建了局部变量,并自动隐藏了同名的全局变量
  3. >>> x = 5
  4. >>> x
  5. 5
  6. >>> demo()
  7. >>> x #函数执行不影响外面全局变量的值
  8. 5

发表评论

表情:
评论列表 (有 0 条评论,135人围观)

还没有评论,来说两句吧...

相关阅读

    相关 python函数定义使用

    什么是函数? 函数是一段具有特定功能的、可重用的语句组,是一种功能的抽象。一般函数表达特定功能。 它的一般表示形式为: def <函数名>(参数):