Python-函数的定义与调用

1初使用

定义一个函数

def stuinfo(name,age,sex):
    print(f"my name is {name},my age is {age},my sex is {sex}")

调用函数

stuinfo("sc",16,"male")

2返回值

函数可以有返回值,也可以没有函数,可以有多个返回值函数

程序在执行函数的时候遇到返回就退出函数了

2.1没有返回值的情况

没有返回值的时候会返回默认值None

定义函数
def add(a,b):
    print(f"a is {a},b is {b}")

调用

result = add(1,2)
print(result)
----------------------------------------------------
结果
# a is 1,b is 2
# end..........s
# None

2.2有多个返回值

定义函数

def add(a,b):
    print(f"a is {a},b is {b}")
        return a+b,a-b

如果用一个变量接受多个返回值,或者少数变量接受多个返回值时,

一个变量的情况,返回值会变为元组赋值给该变量

调用

c,b =add(1,2)
print(c,b)
---------------------------------------------
# a is 1,b is 2
# a is 1,b is 2
# 3 -1

少数变量接受多个返回值:除最后一个变量,前面的变量会按序接受返回值,而多出来的返回值会以元组的形式赋值给最后一个变量

c =add(1,2)
(3, -1, 2)}
--------------------------------------------------
# a is 1,b is 2
# a is 1,b is 2
# (3, -1)

3参数

Python3函数的参数可以分为默认参数,位置参数,关键字参数,可变参数。

形参:指在函数定义时声明的参数,用于接受传递给函数的实参,定义函数def func(x,y,z)的参数x,y,z是形参。

实参:指在函数调用时传递给函数的参数,如调用函数func(a,b,c)的参数a,b,c是实参。

默认参数:指在函数定义时给参数指定的默认值。当函数被调用时,如果没有传递对应的参数,则使用默认值。默认参数可以提供函数的默认行为,使函数调用更加简洁。

位置参数:指根据参数传递的位置来确定参数的值的一种参数类型。位置参数是最常用的参数类型之一,通常用于传递必要的参数值。

关键词参数:关键字参数是指根据参数名来确定参数的值的一种参数类型。关键字参数通常用于传递可选的参数值,可以使函数调用更加清晰明了。

可变长参数:指可以接受不定数量的参数的一种参数类型。Python3 中有两种可变长参数:*args 和 **kwargs。

默认参数

函数的默认参数是可选的,允许在定义函数时为一个或多个参数指定默认值。这样,当函数被调用时,如果没有为该参数传递值,则会使用默认值。

def greet(name, greeting="Hello", punctuation="!"):
    """向指定的人打招呼"""
    return f"{greeting}, {name}{punctuation}"

print(greet("小明"))  
print(greet("大明", "Hi")) 
print(greet("晓明", "Hey", "?"))  
-----------------------------------------
Hello, 小明!
Hi, 大明!
Hey, 晓明?

常见用法和注意事项

  1. 默认参数的默认值只会在函数定义时计算一次,而不是每次函数调用时都计算。因此,如果默认值是可变对象(如列表或字典),则可能会出现意外的行为,因为多次调用函数时,这些对象可能会被多次修改。为了避免这种情况,可以使用不可变对象作为默认值,或者在函数内部创建一个新的可变对象。

    def append_to_lst(item, lst=[]):
        lst.append(item)
        return lst
    
    print(append_to_lst(1))  
    print(append_to_lst(2))  
    print(append_to_lst(3))  
    ---------------------------------------------------
    [1]
    [1, 2]
    [1, 2, 3]
    

    在上面的例子中,第一次调用 append_to_lst(1) 时,lst 的默认值为 [],因此将 1 添加到列表中并返回 [1]。但是,第二次调用 append_to_lst(2) 时,lst 的默认值已经被修改为 [1],因此将 2 添加到列表中并返回 [1, 2]。依此类推,最终返回的列表是 [1, 2, 3]

    为了避免这种意外的行为,可以使用不可变对象作为默认值,或者在函数内部创建一个新的可变对象。例如,下面的例子中,使用 None 作为默认值,并在函数内部创建一个新的空列表:

    def append_to_lst(item, lst=None):
        if lst is None:
            lst = []
        lst.append(item)
        return lst
    
    print(append_to_lst(1))  
    print(append_to_lst(2))  
    print(append_to_lst(3))  
    ----------------------------------
    [1]
    [2]
    [3]
    
  2. 默认参数的顺序很重要。默认参数必须放在非默认参数之后。如果参数顺序不正确,则会发生语法错误。

    def add_numbers(a, b=6, c):
        return a + b + c
    print(add_numbers(1, 2, 3))
    ----------------------------------------------
    SyntaxError: non-default argument follows default argument
    
    def add_numbers(a, b=6, c=6):
        return a + b + c
    print(add_numbers(1, 2))
    ------------------------------------------
    9
    
  3. 默认参数的值可以是任何 Python 表达式,这包括函数调用、变量、以及其他复杂的表达式。

  4. 可以使用关键字参数来指定函数参数的值。这样可以避免在调用函数时出现混淆,特别是在具有多个参数的函数中。

def func1(a, b=1, c=2):
    print(a, b, c)

func1(1)
func1(1, 2)
func1(1, c=3)
func1(a=1, c=3)
--------------------------------
1 1 2
1 2 2
1 1 3
1 1 3

位置参数

位置参数是指在函数定义中按照顺序出现的参数,它们通过位置来确定其值。当我们调用一个函数时,我们可以使用位置参数来传递参数值,这些参数值将按照定义顺序与函数的位置参数一一对应。

  • 在函数定义中,位置参数必须在关键字参数之前定义。也就是说,如果一个函数有关键字参数,那么所有的位置参数必须在关键字参数之前。
  • 在函数调用中,我们可以使用关键字参数来指定参数的值,这样可以避免参数的顺序混淆。
  • 如果我们在函数调用中只传递了一部分位置参数,那么 Python 会引发 TypeError 异常。因此,我们必须确保在函数调用中传递的参数数量和函数定义中的位置参数数量一致。
def greet(name, greeting):
    print(f"{greeting}, {name}!")

greet("小明", "Hello")
greet("大明", "Hi")      
-----------------------------------------------------
Hello, 小明!
Hi, 大明!

位置参数在关键字参数之后定义的情况

def greet(name="小子", greeting):
    print(f"{greeting}, {name}!")

greet("小明", "Hello")
greet()
-----------------------------------------
SyntaxError: non-default argument follows default argument

正常使用的情况

def greet(name, greeting="你好"):
    print(f"{greeting}, {name}!")

greet("小明", "Hello")
greet("大明")
--------------------------------------------
Hello, 小明!
你好, 大明!

传递实参的时候,实参数和形参数不一致(多或少了都会报错)

def greet(name, greeting):
    print(f"{greeting}, {name}!")

greet("小明", "Hello")
greet("大明")
----------------------------------------------
TypeError: greet() missing 1 required positional argument: 'greeting'

关键词参数

关键字参数是一种可以通过参数名指定参数值的参数类型。它们和位置参数不同,不需要按照顺序传递,而是可以根据参数名来指定参数的值。

def greet(name, greeting):
    print(f"{greeting}, {name}!")

greet(name="小明", greeting="Hello")
greet(name="大明", greeting="Hi")

-----------------------------------------
Hello, 小明!
Hi, 大明!
  • 关键字参数可以在函数调用时任意顺序出现,而不需要按照定义顺序传递参数值。

    def greet(name, greeting):
        print(f"{greeting}, {name}!")
    
    greet( greeting="Hello",name="小明",)
    greet( greeting="Hi",name="大明")
    
    -----------------------------------------
    
    Hello, 小明!
    Hi, 大明!
    
  • 如果一个函数同时具有位置参数和关键字参数,那么位置参数必须在关键字参数之前传递,否则会导致语法错误。(已经在位置参数处说明了,这是定义的时候需要注意的)

  • 如果我们在函数调用中使用了未定义的关键字参数,那么会抛出 TypeError 异常。

    def greet(name, greeting):
        print(f"{greeting}, {name}!")
    
    greet(name="小明", greeting="Hello",age=18)
    greet(name="大明", greeting="Hi")
    ----------------------------------------------------------
    TypeError: greet() got an unexpected keyword argument 'age'
    
    
  • 如果我们在函数调用中既使用了位置参数,又使用了关键字参数,那么位置参数必须在关键字参数之前传递。(这其实和定义的原因一样的)

    **原因:**位置参数必须在关键字参数之前传递,是因为 Python 解释器在解析函数调用时是按照参数位置来确定参数值的。如果我们在函数调用中将关键字参数放在位置参数之前,那么解释器就无法正确地将参数值和参数名对应起来,从而导致语法错误。

    def greet(name, greeting):
        print(f"{greeting}, {name}!")
    
    greet(name="小明", "Hello")	
    greet("大明", greeting="Hi")  #这是正确的	
    -------------------------------------------------
    SyntaxError: positional argument follows keyword argument
    
    
  • 关键字参数可以提供默认值。在函数定义时,我们可以为关键字参数指定默认值,这样在函数调用时如果没有提供参数值,就会使用默认值。

def greet(name, greeting="你好"):
    print(f"{greeting}, {name}!")

greet("小明")
greet("大明", greeting="Hi")
-------------------------------------------------
你好, 小明!
Hi, 大明!

可变参数

可变参数是一种可以接受任意数量参数的参数类型。Python 中有两种类型的可变参数:*args 和 **kwargs。

*args 表示接受任意数量的位置参数,它将参数打包成一个元组传递给函数

def myargs(*nums):
    print(nums)
    print(type(nums))

myargs()
myargs(1,2)
----------
()
<class 'tuple'>
(1, 2)
<class 'tuple'>

位置参数和可变参数同时出现的时候,位置参数截取对应自己位置的参数,接受的多余的参数全部打包给*nums

def myargs(a,*nums):
	print(a)
    print(nums)

myargs(1,2,"ass","s")
---------------
1
(2, 'ass', 's')

当然如果实参个数刚好等于位置参数的时候,形参的位置参数就接收转过来的值,形参的可变参数就会接收到一个空的元组

def myargs(a,*nums):
    print(a)
    print(nums)

myargs(1)
-----------------------------------------
1
()

如果实参个数少于形参的位置参数个数,就会报错

def myargs(a,*nums):
    print(a)
    print(nums)

myargs()
-------------------------------------------------
TypeError: myargs() missing 1 required positional argument: 'a'

**kwargs 表示接受任意数量的关键字参数,它将参数打包成一个字典传递给函数

只有**kwargs单独使用的使用,只有实参能以键值对的形式转入形参,一般不会报错

def myargs(**nums):
    for key, value in nums.items():
        print(f"{key}: {value}")

myargs(name="zzz",age=18,city="湖南")
----------------------------------------------------
name: zzz
age: 18
city: 湖南

需要注意的是,args和kwargs的顺序:在函数定义中,args和**kwargs的顺序是固定的,即必须先使用args,然后才能使用kwargs。这是因为*args只能接收位置参数,而kwargs只能接收关键字参数。

*args**kwargs***的关系

*args**kwargs` 是 Python 函数定义中常用的参数类型,它们允许函数接受可变数量的参数

  • *args 表示函数接受可变数量的位置参数,它将传入函数的所有位置参数打包成一个元组(tuple),可以在函数中使用这个元组来访问这些参数

  • **kwargs 表示函数接受可变数量的关键字参数,它将传入函数的所有关键字参数打包成一个字典(dictionary),可以在函数中使用这个字典来访问这些参数。

  • 在函数调用中,*** 也有类似的作用,它们可以用来解包和打包序列或字典,将它们作为函数的位置参数或关键字参数传递给函数。

需要注意的是:*args**kwargs 的命名并不是强制要求,只是约定俗成的名称。实际上,可以用任何名称来表示可变数量的位置参数和关键字参数。

解包和打包

解包和打包都是通过*和**操作符来实现的。

在 Python3 中,解包和打包是指将序列(如列表和元组)或映射(如字典)中的值分别分解或组合成单独的变量或数据结构的过程。

  • 解包是将序列或映射中的值分解为单独的变量或数据结构的过程。在 Python3 中,可以使用 *** 运算符来解包序列和映射。
  • 打包:打包是将单独的变量或数据结构组合成序列或映射的过程。在 Python3 中,可以使用列表、元组和字典来打包数据。

需要注意的是:

  • 解包的值数量必须与变量数量匹配。如果不匹配,会引发 ValueError 异常。
  • 打包的数据必须是可迭代的对象,例如列表、元组或字典。
  • 解包和打包的语法不能在 lambda 表达式中使用。
解包序列

*的解包序列

#解包列表
lst =[1,2,3,"abc"]
print(*lst)
print(1, 2, 3 ,"abc")
-----------------------
1 2 3 abc
1 2 3 abc
#解包元组
t1 =(2,3,"tuple")
print(*t1)
print( 2, 3 ,"tuple")
-------------------------------
2 3 tuple
2 3 tuple

变量接收序列解包后的值

my_list = [1, 2, 3]
a, b, c = my_list
print(a, b, c) 
------------------------------------
# 输出:1 2 3

列表 my_list 中的值被解包为变量 abc

my_list = [1, 2, 3]
a, b = my_list  
-----------------------------------------
# 引发 ValueError 异常

可以看到通过*解包,打印出来的是独立的字符了,和直接打印字符是一样的效果,这就表明我们实参传递的时候也可用这种方法转递了

def my_func(a, b, c,d):
    print(a, b, c,d)

my_tuple = (1, 2, 3)
my_list =[4]

my_func(*my_tuple, *my_list)
my_func(1,2,3,4)
-------------------------------------------------
1 2 3 4
1 2 3 4

可以看到使用*解包的方式转递参数和直接传递参数的效果是一样

解包映射
my_dict = {"a": 1, "b": 2, "c": 3}
a, b, c = my_dict.values()
print(a, b, c) 
--------------------------------------------------
# 输出:1 2 3

如果字典中的键的数量与变量的数量不匹配,会引发 ValueError 异常。

my_dict = {"a": 1, "b": 2, "c": 3}
a, b = my_dict.values() 
---------------------------------------------------
# 引发 ValueError 异常

使用**·解包

d1={'a':1,"b":2}
d2={"c":3,"d":4}
d3=dict(d1,**d2)
d4=dict(d1,c=3,d=4)
print(d3)
print(d4)

---------------
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
打包序列

使用列表或元组来打包数据

a = 1
b = 2
c = 3
my_list = [a, b, c]
print(my_list) 
------------------------------
# 输出:[1, 2, 3]

变量 abc 被打包为列表 my_list

使用圆括号来打包数据为元组

a = 1
b = 2
c = 3
my_tuple = (a, b, c)
print(my_tuple)  # 输出:(1, 2, 3)

变量 abc 被打包为元组 my_tuple

打包映射

使用字典来打包数据

a = 1
b = 2
c = 3
my_dict = {"a": a, "b": b, "c": c}
print(my_dict)  # 输出:{"a": 1, "b": 2, "c": 3}

解包和打包的组合

my_dict = {"a": 1, "b": 2, "c": 3} #打包为映射
a, b, c = my_dict.values()			#将字典中的值解包为变量
my_tuple = (a, b, c)				#随后将变量打包为序列
print(my_tuple) 					
------------------------------------------
# 输出:(1, 2, 3)

总结

  • 解包序列:a, b, c = my_list
  • 解包映射:a, b, c = my_dict.values()
  • 打包为序列:my_list = [a, b, c]
  • 打包为映射:my_dict = {"a": a, "b": b, "c": c}
  • 解包和打包结合:my_tuple = (*my_list, **my_dict)

文档注释

文档注释是包 : 模块、函数里面第一个用三个引号引起来的字符串,而且必须是在函数体的最前面,否则就不是文档注释了

def func():
    """
    文档注释
    this is func
    :return: None
    """
print( help(func))
-------------------------------------------------------------------
func()
    文档注释
    this is func
    :return: None

None

python的函数参数传递,是属于值类型还是引用类型?

在Python中,函数参数传递是按照引用传递的方式进行的。将一个可变对象(如列表、字典等)作为参数传递给函数时,该函数可以修改这个对象的值,并且这个修改也会影响到函数外部的这个对象。

因为python存在可变和不可变数据的原因,所以python中的引用转递,并不是完全的引用转递,不可变的数据的转递表现形式像 值转递,而可变数据类型的表现形式像 引用转递

因此,将一个不可变对象作为参数传递给函数时,函数会创建一个新的对象并将其值复制到该对象中,函数对这个新对象的修改不会影响到函数外部的原始对象。

实例:

转递的是不可变数据类型

## python 参数传值
#转递的是不可变数据类型
def add(a,b):
        ##内存地址改变了
        a=222
        print(f"a -id {id(a)},b-id  {id(b)}")
        return a+b
x=10
y=100
print(f"x-id {id(x)},y-id  {id(y)}")
add(x,y)
------------------------------
x-id 2483596388944,y-id  2483596580304
a -id 2483596584272,b-id  2483596580304

转递的 可变数据类型

##转递的 可变数据类型
def changedate(lst):
    lst.append(1)
    print(f"lst -id {id(lst)}")
    print(lst)

lst1=[]
print(lst1)
print(f"lst1 -id {id(lst1)}")
changedate(lst1)
print(lst1)
----------------------------------------------
[]
lst1 -id 2784670162880
lst -id 2784670162880
[1]
[1]

变量名的解析

变量名的解析

LEGB

  • 先在本地作用域寻找 -》》local
  • 在上层作用域 -->enclosing
  • 在全局作用域中查找 -->global
  • 在内置作用域寻找(python解释器内部寻找) -->builtin
x = 1
def func():
    x = 2
    def func2():
        x = 3
        # __file__="abc"
        print(__file__)
        print(x)
    func2()  
func()
#当注释func2的x时,打印x=2,否则会打印x=3,x=3已经注释的情况下,如果注释x=2,打印x=1,否则打印x=2,以此类推,打印x=1,无结果输出

匿名函数

没有名字的函数,通常函数体只有一个表达式

参数 : 结果 表达式的结果就是返回值

func1 = lambda a,b: a+b

print(func1(1,2))

用在参数的转递

lst =[1,2,3]
lst2 = [10 ,20 , 30]
result = map(lambda x,y: x+y,lst,lst2)
print(result)
print(list(result))

递归函数

算法
自己调用自己
适用范围

  • 考虑一个大问题能不能通过查找规律,变成小问题
  • 考虑递归的出口
##求取 n 的阶乘
n!=1*2*3*...n
n!=n*(n-1)
f(n)=n*f(n-1)

def jiechang(n):
    if n == 1:
        return 1
    else:
        return n * jiechang(n-1)
print(jiechang(3))
  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈密猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值