Python Learning-函数 二

作者: 东南有大树 | 来源:发表于2018-08-27 17:03 被阅读8次

    如果列表被当作参数传递给函数后,被莫名的修改掉,再次使用列表时,其中的元素已经生了改变,有没有什么方法可以控制列表不被改变呢?

    例一:

    # 食物列表 
    foods = ['tomato', 'potato', 'onion','apple', 'banana']
    
    def print_food(food_list):
        """打印食物名称"""
        
        # 循环,如果food_list是空将返回False
        while food_list:
            print(foods.pop())
        # 循环完毕后将列表副本打印
        print(food_list)
    
    # 打印原来的列表,以作对比
    print(foods)
    

    输出:

    banana
    apple
    onion
    potato
    tomato
    []
    ['tomato', 'potato', 'onion', 'apple', 'banana']

    可见,函数体中修改的是foods列表的副本而已,对原列表没有影响,但是这种情况也不是绝对的,请看下面示例

    例二:

    # 食物清单
    foods = [
        {'tomato': 3, 'potato': 2, 'onion': 4},
        {'apple': 5, 'banana': 3.3},
        {'beef': 23, 'pork': 14, 'chicken': 19.8, 'fish': 9.7}
    ]
    
    
    def print_food(food_list):
        """打印foods列表中的食物名称"""
    
        for food_dic in food_list:
            for food in food_dic.keys():
                # 将打印完毕的食物的价格改为0
                food_dic[food] = 0
    
        # 循环完毕后将列表副本打印出来,以作对比
        print(food_list)
    
    # 将foods列表的副本传递给函数
    print_food(foods[:])
    # 打印原列表
    print(foods)
    

    输出:

    [{'tomato': 0, 'potato': 0, 'onion': 0}, {'apple': 0, 'banana': 0}, {'beef': 0, 'pork': 0, 'chicken': 0, 'fish': 0}]
    [{'tomato': 0, 'potato': 0, 'onion': 0}, {'apple': 0, 'banana': 0}, {'beef': 0, 'pork': 0, 'chicken': 0, 'fish': 0}]

    结果显示,不管是原来的列表还是创建的副本列表,其price都被修改成了0,这是为什么呢?

    是因为列表中包含三个字典,而字典是引用类型,那引用类型为什么会影响两个对象呢?请看下面解释

    python的值类型和引用类型

    • 值类型:包含:字符串、元组、数值,本身不允许被修改
    • 引用类型:包含:列表、字典,本身允许修改

    也就是说,值类型提供的值本身,而引用类型提供的是指向值的一个引用地址;再看上面的例子,因为字典是个引用类型,所以foods列表与其副本中所装的三个字典都来字相同对象的引用,于是,在更改副中字典的元素后,实际上也影响到了原列表

    匿名函数

    Python 使用 lambda来创建匿名函数

    匿名是指不需要使用def定义函数与函数名称

    例:

    # 定义一个返回"Hello, XXX!"的函数
    def say_hello(name):
        """返回Hello语句"""
        
        message = "Hello, "+name+"!"
        return message
    
    # 打印函数返回的字符串
    print(say_hello("xiaohong"))
    
    # -----------------------------
    
    # 定义一个lambda表达式,并将该函数赋值给变量g
    g = lambda name : "Hello, "+name+"!"
    # 打开匿名函数
    print(g("xiaoming"))
    

    输出:

    Hello, xiaohong!
    Hello, xiaoming!

    lambda定义的匿名函数又叫lambda表达式,它只有一行代码

    格式:lambda [arg1 [,arg2,.....argn]]:expression,冒号前面的是可选的参数,冒号之后的语句是代码块,该代码块执行的结果将被返回,因此lambda表达式没有return语句

    再举个例子:

    # 食物清单 
    foods = [
        {'tomato': 3, 'potato': 2, 'onion': 4},
        {'apple': 5, 'banana': 3.3},
        {'beef': 23, 'pork': 14, 'chicken': 19.8, 'fish': 9.7}
    ]
    
    for food_dic in foods:
        # 将食物的价格翻倍,通过lambda表达式返回价格的列表
        x = [price*2 for price in food_dic.values()]
        # 打印列表
        print(x)
    

    在《列表的更多操作》一节中,讲过列表解析,其实就是使用了匿名函数,即lambda表达式

    传递任意数量的参数

    在不知道传递的参数到底有多少个,除了可以使用列表之外,还可以这样写:

    # 食物列表
    # foods = ['tomato', 'potato', 'onion','apple', 'banana']
    
    def print_food(*foods):
        """打印食物名称"""
    
        # 打印看看
        print(foods)
    
    # 打印原来的列表,以作对比
    print_food('apple', 'pear', 'milk')
    

    输出:

    ('apple', 'pear', 'milk')

    在形参foods之前加一个*号,表示创建了一个名为foods的无组,然后将传来的所有实参都装进这个无组中

    同理,Python也允许以相同的方式创建一个字典来接收键值对形式的多个参数

    # 食物列表
    # foods = ['tomato', 'potato', 'onion','apple', 'banana']
    
    def print_food(name,**foods):
        """打印食物名称"""
    
        # 打印看看
        print(foods)
    
    # 打印原来的列表,以作对比
    print_food('xiaoming', apple=2, pear=3, milk=2.5)
    

    输出:

    {'apple': 2, 'pear': 3, 'milk': 2.5}

    两个*号表示创建一个字典,并将所有传来的参数装进该字典中去;因此实参的形式必须以key=value这种形式传递

    注意:字典的key不能重复,apple虽然是字符串,但实参这里不需要给它加引号

    从上例中也可以看出,函数中可以现时存在不同形式的形参与实参,因此传递实参可以按照位置匹配的方式进行传递,所以将能接收任意数量实参的形参放在最后

    将函数封装进模块中

    还可以将函数封装进模块当中,与主程序进行分离开;在使用的时候,只要从相应的模块当中导入即可

    在保存Python文件的时候,文件后缀需要以.py结尾,以.py结尾的文件就是模块

    例,将下面代码保存到hello.py文件中

    def say_hello(name):
        """say hello 语句"""
    
        print(("hello, " + name + "!").title())
    
    
    def print_foods():
        """打印食物清单中的食物名称"""
    
        # 食物列表
        foods = ['tomato', 'potato', 'onion', 'apple', 'banana']
        # 打印
        for food in foods:
            print(food)
    

    然后在同一目录下,再新建一个main.py文件,其中代码如下:

    # 导入hello模块
    import hello  
    
    # 调用hello模块下的say_hello函数
    hello.say_hello('jack')
    

    输出:

    Hello, Jack!

    通过符号.来调用相应模块下的函数;通过.可以访问到模块下的所有函数

    调用print_foods()函数

    # 导入hello模块
    import hello  
    
    # 调用hello模块下的say_hello函数
    # hello.say_hello('jack')
    hello.print_foods()
    

    输出:

    tomato
    potato
    onion
    apple
    banana

    不仅可以导入模块,还可以直接导入模块中的函数

    # 导入hello模块中的函数
    from hello import say_hello
    
    # 调用hello模块下的say_hello函数
    say_hello('jack')
    

    其语法是:form x import x从某模块下导入一个函数

    如果要导入多个函数,如下:

    # 导入hello模块中的函数
    from hello import say_hello, print_foods
    
    # 直接调用函数
    say_hello('jack')
    print_foods()
    

    输出:

    Hello, Jack!
    tomato
    potato
    onion
    apple
    banana

    如果导入了模块中的函数,在使用的时候则不需要通过.来从模块中访问函数

    如果要导入模块下的全部函数,如下:

    # 导入hello模块中的函数
    from hello import *
    
    # 直接调用函数
    say_hello('jack')
    print_foods()
    

    *表示导入模块下的所有函数

    为模块与函数重命名

    import hello as ho
    from hello import say_hello as sh
    
    ho.say_hello('jack')
    sh('jack')
    

    输出:

    Hello, Jack!
    Hello, Jack!

    在实际开发中,某个导入的模块可能会用得很多,如果名字非常长,使用起来不方便,所以重命名可以让代码更加的简洁、实用

    目录
    上一章 Python Learning-函数 一
    下一章 Python Learning-面向对象编程-类 一

    相关文章

      网友评论

        本文标题:Python Learning-函数 二

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