美文网首页
函数(二)

函数(二)

作者: Peng_001 | 来源:发表于2020-05-21 10:52 被阅读0次

    参考:https://www.liaoxuefeng.com/wiki/1016959663602400/1017261630425888

    根据函数(一)中的内容,不难发现python 函数的定义非常简单,且灵活度也非常大。

    除了正常使用的必选参数外,还可以使用默认参数、可变参数与关键字参数,使得函数定义出来的接口,不但能处理复杂的信息,而且能简化使用者的代码。

    位置参数

    函数中,最常见的就是位置参数。

    比如我们定义一个计算幂的函数。

    def power(x):
        return x * x
    

    这个函数中,x就是一个位置参数。

    当我们调用power时,必须传入这样一个位置参数。

    但我们如果想要计算x**3, x**4 呢?

    总不至于重新设定power_3, power_4 吧。

    最简单的方法,便是给函数添加一个新的参数。

    def power(x, n):
        return x ** n
    

    但问题又来了,使用新函数时,旧的调用代码就失效了,有没有办法可以解决呢? 默认参数是个不错的选择。

    默认参数

    由于进行幂计算时,最常用的便是平方,也就是二次幂的计算。

    因此python 也提供了默认参数的选择,我们可以将 n = 2,使得默认下,即在不做修改的前提下,默许 n = 2。

    def power(x, n = 2):
        return x ** n
    

    而对于其他的幂,则可以明确传入power, power(2, 3)

    除此之外需要注意两点。

    1)必选参数必须在默认参数后面。如果必选参数在前,当我们将参数传入函数时,函数会默认将在先的参数传给默认参数,而这样子就可能会导致没有参数传入位置参数,导致函数出错。

    2)在意识到第一点下,便可以极大地发挥默认参数的好处:将变化大的参数放在前面,变化小的放在后面。这样便可最大的简化使用者的代码。

    比如需要编写一个学生注册的程序,需要录入学生的姓名,性别,年龄和籍贯。
    对于大多数学生来说,年龄和籍贯都是固定的,因此可以将它们作为默认参数。

    def enroll(name, gender, age = 6, city = 'Shang\'hai'):
        print('name : ', name)
        print('gender : ', gender)
        print('age : ', age)
        print('city : ', city)
    
    enroll('Li Yang', 'M') # 调用
    

    默认参数的“坑”

    根据上面的演示,不难看出默认参数确实是一个方便我们书写代码的利器,合理的默认参数极大降低了使用者代码的重复度与复杂度。

    def add_end(L=[]):
        L.append('END')
        return L
    

    上面的代码,似乎设想的不错,在列表的末尾加上新的元素END,而不指定列表,也会默认定义L 为一个空列表。

    但当我们多次调用函数,问题就来了。

    >>> add_end()
    ['END']
    >>> add_end()
    ['END', 'END']
    

    每新调用一次函数,列表便在先前的基础上,新添加了一个元素。这和想要的不一样呀!

    原因很简单,因为默认参数L 也是被一个变量定义,L指向该变量[],每次我们调用函数时,该变量都会被改变,因此在新的调用时L 的内容也会发生改变。只要我们不重新对L 赋值,则 L 会永远记得之前添加的元素。(还挺记仇?)

    因此,一定要注意,默认参数必须指向不变对象

    通过将L 指向None,这一不可变对象,即可实现。

    def add_end(L = None):
        if L is None: # 默认下 L 为None,执行语句
            L = [] # 对L 重新赋值,使其为列表,巧妙避开默认参数的位置
        L.append('END')
        return L
    

    正因此,python 设计了 tuple, str, None 这类的不可变对象,相当于给程序添加了保险,避免了因为对象内部数据的改变而影响了结果。

    可变参数

    可变参数不是说这个参数是可以变化的,而是指传入的参数的个数是可变的,可以是0个、1个、2个甚至无限个。

    比如想要设计一个计算一组数字的平方之和的函数。

    要定义这个函数,首先需要确定输入的参数。而由于可变参数的参数个数不固定,因此可以用list 或tuple 来传递参数。

    def calc(numbers):
        sum = 0
        for n in numbers:
            sum = sum + n * n
        return sum
    

    但问题时,在传入参数时,必须以list 或tuple 的形式。
    而利用可变参数,便可以简化调用函数的方式。

    >>> calc([1, 2, 3])
    14
    >>> calc(1, 2, 3)
    14
    

    定义可变参数

    在参数前加上*便可以定义可变参数。这时,输入的对象在函数内部便转换为了tuple。可以传入0或任意个参数。

    def calc(*numbers):
        sum = 0
        for n in numbers:
            sum = sum + n * n
        return sum
    

    如果想要传入list 或tuple呢?

    一个方法是提取list或tuple 中的每一个元素,再传入函数中,但这未免有些麻烦。

    还有一个方法是把list 或tuple 中的元素变成可变参数传入进去。即在该list 前加上*

    list = [1, 2, 3]
    
    def calc(*numbers):
        sum = 0
        for n in numbers:
            sum = sum + n * n
        return sum
    
    print(calc(*list))
    

    关键字参数

    可变参数在函数调用时将参数自动组装为一个tuple,允许传入0个或任意个元素。而关键字参数则在函数内容组装为一个dict,也允许传入0个或任意个含参数名的参数。

    关键字参数可以拓展函数的功能。提供可选择的参数选项。

    在参数前加上**便可定义关键字参数。

    def person(name, age, **kw):
        print('name:', name, 'age:', age, 'other:', kw)
    

    而关键字参数不是必须的。

    >>> person('Michael', 30)
    name: Michael age: 30 other: {}
    

    也可以传入关键字参数,但需定义参数名及参数值。
    且该关键字参数内容会保存在字典中。

    >>> person('Adam', 45, gender='M', job='Engineer')
    name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
    

    如果想要传入dict 呢?

    和可变参数同理,可以通过提取dict 中的每一个元素,再分别赋值给关键字参数的新参数名。

    或者也可以在该dict 前加上**,把这个字典中的全部键值对传入到关键字参数中。

    extra = {'city': 'Beijing', 'job': 'Engineer'}
    
    def person(name, age, **kw):
        print('name:', name, 'age:', age, 'other:', kw)
    
    person('Jack', 24, **extra)
    

    命名关键字参数

    有的时候我们可能不希望传入无限制的关键字参数,这时,我们便可以使用命名关键字参数。

    命名关键字参数和关键字参数**kw不同,是通过在参数之间加上特殊分隔符*,从而达到*后面的参数为关键字参数。

    def person(name, age, *, city, job):
        print(name, age, city, job)
    
    person('Jack', 24, city='Beijing', job='Engineer')
    
    # 返回 Jack 24 Beijing Engineer
    
    # 这时候如果输入其他的非指定的关键字参数
    person('Jack', 24, city='Beijing', job='Engineer', zipp = 213213)
    # 会报错
    '''
    TypeError: person() got an unexpected keyword argument 'zipp'
    '''
    

    如果函数中已经有了一个可变参数,则可变参数之后的参数被认为是命名关键字参数。

    def person(name, age, *args, city, job):
        print(name, age, args, city, job)
    

    不同于位置参数,关键字参数必须传入参数名,否则会报错。因为如果不传入参数名,python 解释器会将参数默认为位置参数。

    而命名关键字参数也可以和默认参数结合在一起使用,可以为关键字参数设定默认值,从而简化代码。

    def person(name, age, *, city='Beijing', job):
        print(name, age, city, job)
    

    测试

    >>> person('Jack', 24, job='Engineer')
    Jack 24 Beijing Engineer
    

    参数组合

    有了这么多的参数种类,一个强大的程序必定是将这些参数组合在一起,从而实现强大的功能。
    一共有五种参数。

    • 必选参数(位置参数)
    • 默认参数
    • 可变参数
    • 命名关键字参数
    • 关键字参数

    而定义这五种参数也需要遵循一定的顺序,必选参数、默认参数、可变参数、命名关键字参数和关键字参数

    注意:虽然可以使用五种参数,但一般不建议使用过多的组合,否则函数的接口的可理解性将会很差。

    相关文章

      网友评论

          本文标题:函数(二)

          本文链接:https://www.haomeiwen.com/subject/cepnohtx.html