Python Learning-函数 二
如果列表被当作参数传递给函数后,被莫名的修改掉,再次使用列表时,其中的元素已经生了改变,有没有什么方法可以控制列表不被改变呢?
例一:
# 食物列表
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!
在实际开发中,某个导入的模块可能会用得很多,如果名字非常长,使用起来不方便,所以重命名可以让代码更加的简洁、实用