一、变量进阶
1、变量的引用
在python中,数据保存在内存中,变量保存的是数据在内存中的地址。
变量中记录数据的地址,就叫引用。
使用id()函数可以查看变量中保存数据所在的内存地址
在python中,函数的参数传递以及返回值都是靠引用传递的
# 变量进阶
a = 1
print(id(a)) # 2268418959664
print(id(1)) # 2268418959664
b = a
print(id(b)) # 2268418959664
a = 2
print(id(a)) # 2268418959696
# 变量的引用
# 引用传递
def test(num):
print("在函数内部 %d 对应的内存地址是 %d" % (num, id(num))) # 2268418959664
# 定义一个字符串变量
result = "hello"
print("在函数内部 %s 在内存中的地址值是 %d" % (result, id(result))) # 1879529173872
# 将字符串变量返回 返回的是数据的引用 而不是数据本身
return result
a = 1
print("a 变量所在的内存地址值是%d" % id(a)) # 2268418959664
r = test(a)
print("调用函数后 %s 在内存中的地址值是 %d" % (r, id(r))) # 1879529173872
二、可变和不可变类型
1、不可变类型,内存中的数据不允许被修改
数字类型:int bool float complex long
字符串:str
元组:tuple
2、可变类型,内存中的数据可以被修改
列表:list
字典:dict
通过方法改变可变类型的数据不会影响变量在内存中的地址。
# 不可变类型和可变类型
# 列表 数据可变类型
a = [1, 2, 3]
print(id(a)) # 2588053287680
a.append(4)
print(a) # [1, 2, 3, 4]
print(id(a)) # 2588053287680
a.remove(1)
print(a) # [2, 3, 4]
print(id(a)) # 2588053287680
a.clear() # 清空列表
print(a) # []
print(id(a)) # 2588053287680
# 重新对 a 赋值后 引用的地址值已经发生变化
a = []
print(id(a)) # 2491393136768
# 字典 数据可变类型
d = {"name": "xiaoming"}
print(id(d)) # 2208527826496
d["name"] = "xiaomei"
print(d) # {'name': 'xiaomei'}
print(id(d)) # 2208527826496
d["age"] = 20
print(d) # {'name': 'xiaomei', 'age': 20}
print(id(d)) # 2208527826496
d.clear()
print(d) # {}
print(id(d)) # 2208527826496
# 重新对字典 d 赋值后 d 指向的内存地址已经发生变化
d = {}
print(id(d)) # 1365805317760
注意:字典中的 key 只能使用不可变类型的数据,如数字、字符串、元组
三、局部变量和全局变量
1、局部变量:在函数内部定义的变量,只能在函数内部使用。
局部变量的生命周期:生命周期是指变量从被创建到被系统回收的过程。局部变量只有在函数执行时才会被创建。函数执行结束后局部变量被系统回收。局部变量在生命周期内,可以用来存储函数内部临时使用到的数据。
2、全局变量:函数外部定义的变量,所有函数内部都可以使用这个变量。
在python中是不允许直接修改全局变量的值。
num = 1
def test01():
num = 10 # 如果使用赋值语句 会在函数内部定义一个局部变量
print("修改全局变量num后函数内部num的值是%d" % num) # 10
test01(a)
print("调用函数后再观察num的值是%d" % num) # 1
若想在函数内部修改全局变量的值,需要用 global 进行声明
# 若想在函数内部修改全局变量的值,则需要用 global 关键字声明
num = 10
def demo1():
# global 关键字会告诉解释器后面的变量是全局变量
# 此时使用赋值语句就不会创建局部变量
global num
num = 99
print("修改全局变量num的值为 %d" % num)
demo1() # 99
print("调用修改全局变量的函数后num的值为 %d" % num) # 99
若函数有多个返回值如何接收?
元组可以包含多个数据,因此可以使用元组让函数一次返回多个值。
def measure():
"""测量温度和湿度"""
print("测量开始...")
temp = 39
wetness = 50
print("测量结束...")
# 如果返回值类型是元组 那小括号可以省略
return temp, wetness
result = measure()
print(result) # (39, 50)
print(type(result)) # <class 'tuple'>
print(result[0]) # 39
print(result[1]) # 50
# 通过索引访问元组中的元素非常不方便
# 如果函数返回的类型是元组,同时希望单独处理元组中的元素
glo_temp, glo_wetness = measure()
print(glo_temp)
print(glo_wetness)
四、缺省参数
1、什么是缺省参数?
定义函数时,可以给某个参数指定一个默认值,具有默认值的参数叫做缺省参数。
在调用函数时,如果没有传入缺省参数的值,则在函数内部默认使用定义函数时的参数默认值
如:对列表排序的方法
gl_list = [6, 2, 3]
# 升序排序
gl_list.sort()
print(gl_list) # [2, 3, 6]
# 降序排序
# 如果需要函数执行降序排序 需要指定 reverse 参数
gl_list.sort(reverse=True)
print(gl_list) # [6, 3, 2]
2、函数中缺省参数的定义
def print_info(name, gender=True):
# gender 是本函数的缺省参数,指定其默认值为True
gender_text = '男'
if not gender:
gender_text = '女'
print("%s 的性别是 %s" % (name, gender_text))
print_info("小明") # 小明 的性别是 男
print_info("小美", False) # 小美 的性别是 女
3、缺省参数的注意事项
(1)缺省参数的定义位置:必须保证带有默认值的缺省参数在参数列表末尾
如:def print_info(name, gender=True, title)这种定义方式是错误的
(2)调用带有多个缺省参数的函数:在调用函数时,如果有多个缺省参数,要指定参数名。
五、多值参数
1、python中两种多值参数:参数名前增加一个 * 可以接收元组;参数名前增加两个 * 可以接收字典。一般在给多值参数命名时,习惯使用 *args(存放元组参数) 和 **kwargs(存放字典参数)
def demo(num, *args, **kwargs):
print(num)
print(args)
print(kwargs)
demo(1, 2, 3, 4, 5)
# 1
# (2, 3, 4, 5)
# {}
demo(1, 2, 3, 4, 5, name='小美', age=19)
# 1
# (2, 3, 4, 5)
# {'name': '小美', 'age': 19}
2、元组和字典的拆包
在调用带有多值参数的函数时,如果想把一个元组变量直接传递给args或想把一个字典变量直接传递给kwargs时,就可以使用拆包,简化参数传递。
拆包方式是:在元组变量前增加一个 *,在字典变量前增加两个 *。
def demo1(*args, **kwargs):
print(args)
print(kwargs)
nums = (1, 2, 3)
person = {"name": "xiaomei", "age": 19}
# demo1(nums, person) # 此时将传入的两个参数num和person直接当成元组的两个元素
# ((1, 2, 3), {'name': 'xiaomei', 'age': 19})
# {}
# 拆包的语法
demo1(*nums, **person)
# (1, 2, 3)
# {'name': 'xiaomei', 'age': 19}