⛄变量的应用

变量和数据都是保存在内存中的,在Python中函数的参数传递以及返回值都是通过引用传递的。

👀引用的概念

Python中:

  • 变量和数据是分开存储的;
  • 数据保存在内存中的一个位置;
  • 变量中保存着数据在内存中的地址;
  • 变量中记录数据的地址,就叫作引用
  • 使用id()函数可以查看变量中保存数据所在的内存地址

注意:如果变量已经被定义,当给一个变量赋值的时候,本质上是修改了数据的引用。

  • 变量不再对之前的数据引用;
  • 变量改为对新赋值的数据引用。

👀函数的参数和返回值的传递

Python中,函数的实参/返回值都是通过引用来传递的。

def mytest(n):
print("*"*50)
print("%d 在函数内的内存地址是%x" % (n,id(n)))

result = 10000
print("返回值%d在函数内的内存地址是%x" % (result,id(result)))
print("*"*50)
return result

a = 100
print("调用函数前,内存地址是%x" % id(a))
r = mytest(a)

print("调用函数后,实参内存地址是%x" % id(a))
print("调用函数前,返回值内存地址是%x" % id(r))

# 输出结果
调用函数前,内存地址是7ffd3378adf0
**************************************************
100 在函数内的内存地址是7ffd3378adf0
返回值10000在函数内的内存地址是1cd96276b70
**************************************************
调用函数后,实参内存地址是7ffd3378adf0
调用函数前,返回值内存地址是1cd96276b70

⛄可变和不可变类型

  1. 不可变类型,内存中的数据不允许被修改:

    • 数字类型:intboolfloatcomplexlong

    • 字符串:str

    • 元组:tuple

  2. 可变类型,内存中的数据可以被修改:

    • 列表:list

    • 字典:dict,字典中的key只能使用不可变类型的数据

emo_list = [1, 3, 5]
print("定义列表后内存地址是%d" % id(demo_list))

demo_list.append(10)
demo_list.remove(1)
demo_list[0] = 30
print("修改数据后内存地址是%d" % id(demo_list))

demo_dict = {"name": "小李子"}
print("定义字典后内存地址是%d" % id(demo_dict))

demo_dict["age"] = 20
demo_dict["name"] = "小喜子"
print("修改数据后内存地址是%d" % id(demo_dict))

# 输出结果
定义列表后内存地址是1982499211272
修改数据后内存地址是1982499211272
定义字典后内存地址是1982498720808
修改数据后内存地址是1982498720808

可变类型的数据变化,是通过方法来实现的;如果给一个可变类型的变量,赋值一个新的数据,引用会修改:

  • 变量不再对之前的数据引用;
  • 变量改为对新赋值的数据引用

⛄局部变量和全局变量

局部变量是在函数内部定义的变量,只能在函数内部使用;函数执行结束后,函数内部的局部变量,会被系统回收;不同的函数,可以定义相同名字的局部变量,但是彼此之间不会产生影响;

局部变量的生命周期:

  • 所谓生命周期就是变量从被创建被系统回收的过程;
  • 局部变量在函数执行时才会被创建;
  • 函数执行结束后,局部变量被系统回收;
  • 局部变量在生命周期内,可以用来存储函数内部临时使用到的数据。

全局变量是在函数外部定义的变量,所有函数内部都可以使用这个变量。(不推荐使用,不易维护)

注意:函数执行时,需要处理变量时,会首先查找函数内部是否存在指定名称的局部变量,如果有,直接使用;如果没有,查找函数外部是否存在指定名称的全局变量,如果有,直接使用;如果还没有,程序报错!!!

注意:如果在函数内部定义了一个与全局变量同名的局部变量,只是变量名相同,不能直接修改全局变量的值。

如果在函数中需要修改全局变量,需要使用global进行声明。

⛄函数进阶

👀函数参数和返回值的作用

定义函数时,是否接收参数,或者是否返回结果,是根据实际的功能需求来确定的。

  • 如果函数内部处理的数据不确定,就可以将外界的数据以参数传递到函数内部;
  • 如果希望一个函数执行完成后,向外界汇报执行结果,就可以增加函数的返回值。

如果全局变量的数据类型是一个可变类型,在函数内部可以使用方法修改全局变量的内容,变量的引用不会改变;在函数内部,通过赋值语句才会修改变量的引用。

👀函数的返回值进阶

  • 程序开发中,希望一个函数执行结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理;
  • 返回值是函数完成工作后,最后给调用者的一个结果;
  • 在函数中使用return关键字可以返回结果;
  • 调用函数一方,可以使用变量来接收函数的返回结果。
  • 注意:如果一个函数执行后返回多个结果,可以利用元组,元祖括号可以省略;
  • 返回结果也是一个元组,可以将元组返回值赋值给一个变量或者相同个数的多个变量
def my_description():
stu = "00000001"
name = "xiaotang"
age = 20
height = 180
# return (stu, name, age, height) 括号可以省略
return stu, name, age, height
stu, name, age, height = my_description()
print(stu, name, age, height)
my_des = my_description()
print(my_des)

# 输出结果
00000001 xiaotang 20 180
('00000001', 'xiaotang', 20, 180)

例如:利用元组交换两个数字

a = 10
b = 5
# (1)使用中间变量
c = b
b = a
a = c
print(a, b)
# (2)不使用中间变量
a = 10
b = 5
a = a + b
b = a - b
a = a - b
print(a, b)
a = 10
b = 5
# 利用元祖
a, b = b, a
print(a, b)

# 输出结果
5 10
5 10
5 10

👀函数的参数进阶

(1)不可变和可变的参数

在函数内部,针对参数使用赋值语句,不会影响调用函数时传递的实参变量。

  • 无论传递的参数是可变还是不可变,只要针对参数使用赋值语句,会在函数内部修改局部变量的引用,不会影响到外部变量的引用。
  • 如果传递的参数是可变类型,在函数内部,使用方法修改了数据的内容,同样会影响到外部的数据。
def demo1(num, num_list):
print("函数内部")
# 赋值语句
num = 200
num_list = [1, 2, 3]
print(num)
print(num_list)
print("函数执行完成")

gl_num = 99
gl_list = [4, 5, 6]
demo1(gl_num, gl_list)
print(gl_num)
print(gl_list)

print("*"*50)

def demo2(num_list):
print("函数内部")
# 赋值语句
num_list.extend([7,8,9,10])
print(num_list)
print("函数执行完成")

gl_list = [4, 5, 6]
demo2(gl_list)
print(gl_list)

# 输出结果
函数内部
200
[1, 2, 3]
函数执行完成
99
[4, 5, 6]
**************************************************
函数内部
[4, 5, 6, 7, 8, 9, 10]
函数执行完成
[4, 5, 6, 7, 8, 9, 10]

Python中,列表变量调用+=本质上是在执行列表变量的extend()方法,不会修改变量的引用。

def demo3(num, num_list):
print("函数内部")
# 赋值语句
num = 200
num_list += [1, 2, 3]
print(num)
print(num_list)
print("函数执行完成")

gl_num = 99
gl_list = [4, 5, 6]
demo3(gl_num, gl_list)
print(gl_num)
print(gl_list)

# 输出结果
函数内部
200
[4, 5, 6, 1, 2, 3]
函数执行完成
99
[4, 5, 6, 1, 2, 3]

(2)缺省参数

  • 定义函数时,可以给某个参数指定一个默认值,具有默认值的参数就叫做缺省参数
  • 调用函数时,如果没有传入缺省参数的值,则在函数内部使用定义函数时指定的参数默认值
  • 函数的缺省参数,将常见的值设置为参数的缺省值,从而简化函数的调用。

例如:对列表排序的方法

num_list = [6, 4, 8]
# 默认就是升序排序,因为这种应用需求更多
num_list.sort()
print(num_list)
# 当需要降序排序时, 才需要传递"reverse"参数
num_list.sort(reverse=True)
print(num_list)

# 输出结果
[4, 6, 8]
[8, 6, 4]

缺省参数的注意事项:

  • 缺省参数的定义位置,必须保证带有默认值的缺省参数在参数列表末尾
  • 调用带有多个缺省参数的函数,需要指定参数名,这样解释器才能知道对应关系。

(3)多值参数

  • 有时可能需要一个函数能够处理的参数个数是不确定的,这个时候,就可以使用多值参数

  • python 中有两种多值参数:

    • 参数名前增加一个*,可以接收元组

    • 参数名前增加两个*,可以接收字典

  • 一般在给多值参数命名时,习惯使用以下两个名字

    • *args——存放元组参数,前面有一个*

    • **Kwargs——存放字典参数,前面有两个*

  • argsarguments的缩写,有变量的含义

  • kwkeyword的缩写,kwargs 可以记忆键值对参数

def demo4(num, *args, **kwargs):
print(num)
print(args)
print(kwargs)
demo4(1, 2, 3, 4, 5, name="小明", age=18, gender=True)

# 输出结果
1
(2, 3, 4, 5)
{'name': '小明', 'age': 18, 'gender': True}

(4)元组和字典的拆包(了解)

  • 在调用带有多值参数的函数时,如果希望:

    • 将一个元组变量,直接传递给args

    • 将一个字典变量,直接传递给kwargs

  • 可以使用拆包,简化参数的传递,拆包的方式是:

    • 元组变量前,增加一个*

    • 字典变量前,增加两个*

def demo5(*args, **kwargs):
print(args)
print(kwargs)

# 需要将一个元组变量/字典变量传递给函数对应的参数
num = (4, 5, 6)
dict_name = {"name": "小汤", "age": 20}
# 会把num, dict_name作为元组传递给args
demo5(num, dict_name)
print("*"*50)
# 元组和字典的拆包
demo5(*num, **dict_name)

# 输出结果
((4, 5, 6), {'name': '小汤', 'age': 20})
{}
**************************************************
(4, 5, 6)
{'name': '小汤', 'age': 20}

👀递归函数

函数内部调用自己。函数内部可以调用其他函数,当然在函数内部也可以调用自己。

代码特点:

  • 函数内部的代码是相同的,只是针对参数不同,处理的结果不同
  • 当参数满足一个条件时,函数不再执行。这个非常重要,通常被称为递归的出口,否则会出现死循环!

例如:计算数字累加

def sum_number(num):
if num == 1:
return 1
temp = sum_number(num - 1)
return num + temp
print(sum_number(10))

# 输出结果
55

笔者不才,请多交流!!!

参考文献:黑马程序员《Python入门教程完整版》