• Python 函数定义详解(More on Defining Functions)- 默认参数/位置参数/关键字参数


    在这里插入图片描述

    1.函数的定义和调用方法

    1.1函数定义方法

    """
        def 关键字用来定义一个函数。
        function_name 是函数名,应遵循命名规范。
        parameter1, parameter2, ... 是函数的参数列表,可以是任意数量和类型的参数。
        函数体是用缩进(通常为4个空格)来表示的代码块。
        return 语句用于返回函数的结果。
    """
    # def function_name(parameter1, parameter2, ...):
        # Function body
        #    return result
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    1.2函数调用方法

    """
    function_name 是要调用的函数名。
    argument1, argument2, ... 是传递给函数的参数列表。
    函数执行后,将返回一个结果,可以将其赋值给一个变量。
    """
    # result = function_name(argument1, argument2, ...)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1.3示例:定义一个函数计算两个数之和

    """
        定义个函数计算两个数之和
    """
    def add_numbers(num1,num2):# 定义函数
        result = num1 +num2
        return result
    
    sum = add_numbers(100,200)# 调用函数
    
    print(sum) # 输出结果为300
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.默认值参数(Default Argument Values)

      Python允许在函数定义中为参数提供默认值,这使得函数在调用时可以省略部分参数,从而提供了更大的灵活性

    2.1示例1:简单的示例函数,用于打招呼

    def greet(name, greeting="Hello"):
        # 参数name是位置参数,必须提供值。
        # 参数greeting是默认值参数,如果不提供值,默认为"Hello"。
        return f"{greeting}, {name}!"
    
    # 调用函数时可以只提供name参数,greeting参数会使用默认值。
    result1 = greet("Alice")
    print(result1)  # 输出 "Hello, Alice!"
    
    # 也可以同时提供name和greeting参数的值,这将覆盖默认值。
    result2 = greet("Bob", "Hi")
    print(result2)  # 输出 "Hi, Bob!"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

      greet函数接受两个参数,namegreeting,其中greeting是一个带有默认值的参数,默认值为"Hello"。当调用函数时,如果只提供了name参数,那么greeting参数将使用默认值。如果同时提供了name和greeting的值,那么提供的值将覆盖默认值。

    2.2python官网示例

    def ask_ok(prompt, retries=4, reminder='Please try again!'):
        # 定义一个函数ask_ok,接受三个参数:prompt、retries和reminder。
        # 默认情况下,retries被设置为4,reminder被设置为'Please try again!'。
        
        while True:
            # 进入一个无限循环,直到用户提供有效的回答或达到重试次数。
            
            ok = input(prompt)
            # 使用input()函数向用户提供一个提示,等待用户的输入,并将输入保存在ok变量中。
            
            if ok in ('y', 'ye', 'yes'):
                return True
                # 如果用户输入了'y', 'ye', 'yes'中的一个,函数返回True。
                
            if ok in ('n', 'no', 'nop', 'nope'):
                return False
                # 如果用户输入了'n', 'no', 'nop', 'nope'中的一个,函数返回False。
                
            retries = retries - 1
            # 如果用户输入既不是True也不是False,减少重试次数retries。
            
            if retries < 0:
                raise ValueError('invalid user response')
                # 如果重试次数小于0,引发一个ValueError异常,表示用户提供的回答无效。
                
            print(reminder)
            # 如果用户提供的回答不在有效选项内,打印提醒消息reminder,然后继续循环。
    
    # 通过以下方式调用:
    ask_ok('Do you really want to quit?')#只给出必选实参
    ask_ok('OK to overwrite the file?', 2)#给出一个可选实参
    ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')#给出所有实参
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    2.3重要提示

      默认值只计算一次。默认值为列表、字典或类实例等可变对象时,会产生与该规则不同的结果。
      下面以列表、字典或类实例示例说明:

    """
        列表作为默认参数
        在这个例子中,期望每次调用append_to函数时,列表都是新的,互不干扰。
        然而,由于默认参数的特性,得到的列表是共享的,所以每次调用都会影响这个列表。
    """
    def append_to(num, target=[]):  
        target.append(num)  
        return target  
      
    print(append_to(1))  # 输出:[1]  
    print(append_to(2))  # 输出:[1, 2],而不是[1]  
    print(append_to(3))  # 输出:[1, 2, 3],而不是[1, 2]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    """
        字典作为默认参数
        期望每次调用update_dict函数时,字典都是新的,但是因为默认参数的特性,得到的字典是共享的。
    """
    def update_dict(key, target={}):  
        target[key] = key  
        return target  
      
    print(update_dict(1))  # 输出:{1: 1}  
    print(update_dict(2))  # 输出:{1: 1, 2: 2},而不是{1: 1}  
    print(update_dict(3))  # 输出:{1: 1, 2: 2, 3: 3},而不是{1: 1, 2: 2}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    """
        类实例作为默认参数
        期望每次调用increment_by函数时,TestClass的实例都是新的,互不干扰。然而,由于默认参数的特性,得到的实例是共享的,所以每次调用都会影响这个实例的状态
    """
    class TestClass:  
        def __init__(self):  
            self.value = 0  
      
        def increment(self, num):  
            self.value += num  
            return self.value  
      
    def increment_by(num, target=TestClass()):  
        target.increment(num)  
        return target.value  
      
    print(increment_by(1))  # 输出:1  
    print(increment_by(2))  # 输出:3,而不是2  
    print(increment_by(3))  # 输出:6,而不是5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.4建议

      1.使用可变对象作为默认参数时,可以考虑使用None作为默认值,并在函数内部进行判断和处理。每次调用的时候,都会创建一个新的列表,避免了共享默认参数的问题。

    def append_to(num, target=None):  
        if target is None:  
            target = []  
        target.append(num)  
        return target
        
    print(append_to(1))
    print(append_to(2))
    print(append_to(3))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

      2.对于字典或类实例等可变对象,可以考虑使用函数内部的局部变量作为默认值,而不是使用一个全局变量。每次调用的时候都会创建一个新的字典或实例,避免共享默认参数的问题。

    def update_dict(key, target=None):  
        if target is None:  
            target = {}  
        target[key] = key  
        return target
    
    • 1
    • 2
    • 3
    • 4
    • 5
    def increment_by(num, target=None):  
        if target is None:  
            target = TestClass()  
        target.increment(num)  
        return target.value
    
    • 1
    • 2
    • 3
    • 4
    • 5

      3.如果可能的话,尽量避免使用可变对象作为默认参数,可以避免潜在的共享问题。考虑使用不可变对象(如字符串、数字或元组)作为默认参数。
      4.如果默认参数的值是一个复杂对象(如列表、字典或类实例),并且需要重复使用,可以考虑将该对象定义为全局变量或属性,并在函数内部引用该全局变量。可以确保每次调用函数时都使用同一个对象,避免了重复创建对象的开销。但是需要注意避免全局变量导致的命名冲突和其他问题。
      5.如果默认参数的值是一个不可变对象(如字符串、数字或元组),并且需要重复使用,可以考虑将该对象定义为函数的一个属性或静态变量。这样可以避免每次调用函数时都重新计算该对象的开销。但是需要注意避免该对象被修改导致的问题。

    3.关键字参数(Keyword Arguments

      kwarg=value形式的关键字参数 也可以用于调用函数。
      在函数调用中前面带有标识符(例如 arg=)或者作为包含在前面带有**的字典里的值传入。
      如:3和5在以下对complex()方法的调用中均属于关键字参数
      complex(real=3, imag=5)
      complex(**{'real': 3, 'imag': 5})

    3.1官网示例

    """
        parrot()函数接受一个必选参数(voltage)和三个可选参数(state, action 和 type)
        其中voltage既可以是位置参数,也可以是关键字参数;
        state、action、type是关键字参数
    """
    def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
        print("-- This parrot wouldn't", action, end=' ')
        print("if you put", voltage, "volts through it.")
        print("-- Lovely plumage, the", type)
        print("-- It's", state, "!")
    
    # 可用下列方法进行调用
    parrot(1000)                                          # 1 positional argument
    parrot(voltage=1000)                                  # 1 keyword argument
    parrot(voltage=1000000, action='VOOOOOM')             # 2 keyword arguments
    parrot(action='VOOOOOM', voltage=1000000)             # 2 keyword arguments
    parrot('a million', 'bereft of life', 'jump')         # 3 positional arguments
    parrot('a thousand', state='pushing up the daisies')  # 1 positional, 1 keyword
    
    # 以下调用函数的方式均无效
    parrot()                     # required argument missing
    parrot(voltage=5.0, 'dead')  # non-keyword argument after a keyword argument
    parrot(110, voltage=220)     # duplicate value for the same argument
    parrot(actor='John Cleese')  # unknown keyword argument
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

      函数调用时,关键字参数必须跟在位置参数后面。所有传递的关键字参数都必须匹配一个函数接受的参数(比如,actor不是函数 parrot 的有效参数),关键字参数的顺序并不重要。这也包括必选参数,(比如,parrot(voltage=1000) 也有效)。不能对同一个参数多次赋值。

    3.2 ```*args和**kwargs

      在Python中,*args **kwargs 是特殊的参数,用于在函数定义中接收任意数量的位置参数和关键字参数。
      *args表示一个元组类型的参数,用于接收任意数量的位置参数。这些参数将按照它们在函数调用中的顺序依次赋值给*args参数。在函数体中,可以像处理普通元组一样处理*args参数。
      **kwargs表示一个字典类型的参数,用于接收任意数量的关键字参数。这些参数将作为字典的键值对赋值给 **kwargs参数。在函数体中,可以使用**kwargs参数来访问这些关键字参数。

    """
        *argument 形参接收一个元组,在它之前的为位置参数
        **keywords 形参接收一个字典,传参数数时必须带变量名
    """
    def cheeseshop(kind, *arguments, **keywords):
        print("-- Do you have any", kind, "?")
        print("-- I'm sorry, we're all out of", kind)
        for arg in arguments:
            print(arg)
        print("-" * 40)
        for kw in keywords:
            print(kw, ":", keywords[kw])
    
    #调用该函数
    cheeseshop("Limburger", "It's very runny, sir.",
               "It's really very, VERY runny, sir.",
               shopkeeper="Michael Palin",
               client="John Cleese",
               sketch="Cheese Shop Sketch")
    
    # 输出结果:
    """
        -- Do you have any Limburger ?
        -- I'm sorry, we're all out of Limburger
        It's very runny, sir.
        It's really very, VERY runny, sir.
        ----------------------------------------
        shopkeeper : Michael Palin
        client : John Cleese
        sketch : Cheese Shop Sketch
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    4.特殊参数

      默认情况下,参数可以按位置或显式关键字传递给Python 函数。为了让代码易读、高效,最好限制参数的传递方式,这样,开发者只需查看函数定义,即可确定参数项是仅按位置、按位置或关键字,还是仅按关键字传递。
    函数定义如下:
    在这里插入图片描述

      / * 是可选的。这些符号表明形参如何把参数值传递给函数:位置位置或关键字关键字

    4.1 位置或关键字参数

      函数定义中未使用/ * 时,参数可以按位置或关键字传递给函数。

    4.2 仅位置参数

      仅限位置时,形参的顺序很重要,且这些形参不能用关键字传递。仅限位置形参应放在/ (正斜杠)前。/ 用于在逻辑上分割仅限位置形参与其它形参。如果函数定义中没有 /,则表示没有仅限位置形参。
    / 后可以是 位置或关键字 或 仅限关键字 形参。

    4.3 仅限关键字参数

      把形参标记为 仅限关键字,表明必须以关键字参数形式传递该形参,应在参数列表中第一个 仅限关键字形参前添加*

    """
        / 和 * 在参数中使用的语法:
        def function(positional_or_keyword_parameters, *, keyword_only_parameters):
        def function(positional_only_parameters, /, positional_or_keyword_parameters,*, keyword_only_parameters):
        
        在“/”左边的参数被视为仅位置参数
        如果函数定义中“/”没有指定,则函数中所有参数都不是仅位置参数
        仅位置参数的可选值的逻辑与位置-关键字参数的逻辑相同。
        一旦使用默认值指定了仅位置参数,下面的仅位置参数和位置-关键字参数也需要具有默认值。
    """
    # 有效的函数定义:
    def fun1(positional1, positional2, /, positional_or_keyword, *, keywords):pass
    def fun2(positional1, positional2=None, /, positional_or_keyword=None, *, keywords):pass
    def fun3(positional1, positional2=None, /, *, keywords):pass
    def fun4(positional1, positional2=None, /):pass
    def fun5(positional1, positional2, /, positional_or_keyword):pass
    def fun6(positional1, positional2, /):pass
    def fun7(positional_or_keyword, *, keywords):pass
    def fun8(*, keywords):pass
    
    # 无效定义
    def fun9(positional1, positional2=None, /, positional_or_keyword, *, keywords):pass
    def fun10(positional1=None, positional2, /, positional_or_keyword=None, *, keywords):pass
    def fun11(positional1=None, positional2, /):pass
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 相关阅读:
    【VS Code】推荐一套我非常喜欢的主题和字体样式
    Python教程:随机函数,开始猜英文单词的游戏
    整站SEO优化需要怎么做?SEO整站优化的思路及步骤
    数据结构学习笔记(第八章 排序-内部排序)
    windows下利用python计算文件md5值
    a commponent required a bean of type XXXXXX that could not be found-2022新项目
    Java企业微信对接(二)微信端回调到企业端
    第十四届蓝桥杯(Web应用开发)模拟赛1期-大学组
    使用 VPN ,一定要知道的几个真相!
    如何使用前端包管理器(如npm、Yarn)?
  • 原文地址:https://blog.csdn.net/Snailandfish/article/details/134317661