python第4天之列表推导式、组包拆包、多个返回值、嵌套调用、递归调用、全局变量、局部变量、引用

2023-12-14 15:50:45

列表推导式

作用

提供一种简介的方式来创建列表。通常用于对序列中共的每个元素应用一个操作,或者从一个序列中共筛选出符合特定条件的元素子集

优点:

列表推导式比传统的的循环语句更加简介,并且很多情况下也更便于阅读。

格式:

列表名 = [ expression for item in list if condition ]
# expression是对应每个元素应用的操作
# item是从列表获取的值
# condition是可选的筛选条件

例子:

1、将一个数值的列表的每个元素的都平方

numbers = [1, 2, 3, 4, 5]
squared = [n ** 2 for n in numbers]

2、筛选出一个列表中的偶数

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
evens = [n for n in numbers if n % 2 == 0]

3、将一个字符串列表中的所有字符转换成大写

words = ['hello', 'world', 'python', 'is', 'awesome']
upper_words = [word.upper() for word in words]

4、使用两个列表创建一个坐标列表

x_values = [1, 2, 3]
y_values = [4, 5, 6]
coordinates = [(x, y) for x in x_values for y in y_values]

5、使用列表推导式结合条件表达式创建包含条件结果的列表

numbers = [1, 2, 3, 4, 5]
odd_even = ['even' if n % 2 == 0 else 'odd' for n in numbers]

组包和拆包

组包(packing)和拆包(unpacking)是指在没有明确指定变量数量的情况下,对多个值进行打包成一个元组(或者其它集合类型),或者将一个集合类型的对象解开成单独的变量。

组包(Packing)示例:

当我们将多个值赋给一个单独的变量时,Python 会自动将这些值组包成一个元组。

#组包示例
a = 1,2,3 #1,2,3被打包成元组赋给a
print(a)  #输出:(1,2,3)

拆包(Unpacking)示例:

当我们有一个集合类型的对象(比如元组或列表)并且我们想要将其内部的元素赋给多个单独的变量时,我们可以使用拆包。

# 拆包例子
a, b, c = (1, 2, 3)  # 元组拆包,元组中的值赋给了三个单独的变量
print(a)  # 输出: 1
print(b)  # 输出: 2
print(c)  # 输出: 3

在上面的例子中,元组 (1, 2, 3) 被拆开,其内部的值分别赋给了变量 a, b, 和 c

拆包常用于函数返回多个值时,例如:

def get_point():
    return 10, 20  # 返回一个元组(10, 20)

x, y = get_point()  # 拆包
print(x)  # 10
print(y)  # 20

还有一种扩展的拆包语法,可以用于不确定元素数量的情况,它使用星号 * 来处理多余的元素:

a, *b, c = (1, 2, 3, 4, 5)  # b会捕获中间的所有值
print(a)  # 输出: 1
print(b)  # 输出: [2, 3, 4]
print(c)  # 输出: 5

在这个例子中, a 被赋值为第一个元素 1c 被赋值为最后一个元素 5,而 b 是一个列表,包含了所有中间的元素 [2, 3, 4]。

函数的多个返回值

在Python中,可以通过返回一个元组来实现函数返回多个值。当你从一个函数返回多个值时,Python会自动将这些值打包成一个元组。调用函数的地方可以直接拆包这个元组来获取多个返回值。

例如:

# 定义一个函数,它返回三个值
def get_user_info():
    name = "Alice"
    age = 25
    city = "New York"
    return name, age, city  # 返回一个元组,包含三个值

# 调用函数并拆包返回的元组
user_name, user_age, user_city = get_user_info()

# 打印结果
print("Name:", user_name)  # 输出: Name: Alice
print("Age:", user_age)    # 输出: Age: 25
print("City:", user_city)  # 输出: City: New York

在上面的代码中,get_user_info 函数返回三个值:name, age, 和 city。当这个函数被调用时,返回的三个值被打包成一个元组。然后,我们通过拆包将这个元组中的值赋给了三个不同的变量:user_name, user_age, user_city

这种方法的好处是代码简洁明了,可以轻松地从函数中返回多个值,并在调用端简洁地获取这些值。

函数嵌套调用

嵌套调用是指,在一个被调用函数体内又调用了另外一个函数

例如:

# 定义三个函数
def func_a():
    print('Func A Start...')
    func_b()
    print('Func A Stop...')

def func_b():
    print('Func B Start...')
    func_c()
    print('Func B Stop...')

def func_c():
    print('Func C Start...')
    print('Func C Stop...')


# 执行函数调用
func_a()

#输出:
#Func A Start...
#Func B Start...
#Func C Start...
#Func C Stop...
#Func B Stop...
#Func A Stop...

#代码执行顺序a-b-c-b-a

函数递归调用

递归调用指的是函数在函数体内又调用自己的情况,递归函数需要满足两个情况:

1.基准情形:递归调用必须有一个或多个基准情形,即在不进行递归调用的情况下可以直接解决的简单情形(就是这个问题最终不再递归能解决)

2.递归步骤:递归调用必须逐步减少问题的规模,使问题主键基于基准情形(越调越简单,最终能解决)

例子,计算阶乘:

# 定义递归函数计算阶乘
def factorial(n):
    # 基准情形:当n等于0时,阶乘结果是1
    if n == 0:
        return 1
    # 递归步骤:n的阶乘是n乘以(n-1)的阶乘
    else:
        return n * factorial(n - 1)

# 调用递归函数
result = factorial(5)  # 计算5的阶乘

print(result)  # 输出: 120

在上面的代码中,factorial 函数递归地调用自己。我们知道,0的阶乘是1,所以这是我们的基准情形。否则,我们通过计算 n * factorial(n - 1) 来递归调用函数,并且每次调用都会减小 n 的值,直到它达到基准情形。

递归函数通常非常简洁,但需要注意避免无限递归和栈溢出的问题,在Python中,默认的最大递归深度是1000(这个值可以通过 sys.setrecursionlimit 来修改)。因此,对于大规模的问题,通常需要寻找非递归的解决方案或优化递归算法(例如使用尾调用优化或动态规划)。

全局变量和局部变量

在Python中,变量的作用域决定了在哪里可以访问和修改这个变量的值。根据作用域的不同,变量可以被分类为全局变量或局部变量。

全局变量:

  • 全局变量是在函数之外定义的,可以在整个程序的任何地方访问。
  • 如果需要在函数内修改全局变量,必须使用?global?关键字声明。

局部变量:

  • 局部变量是在函数内部定义的,只能在该函数内部访问。
  • 函数内的局部变量与函数外同名的全局变量不会相互影响。

下面是一个展示全局变量和局部变量的例子:

# 定义全局变量
global_variable = "global variable"

# 定义一个函数,打印一个局部变量和全局变量
def my_function():
    # 定义局部变量
    local_variable = "local variable"
    # 打印局部变量
    print(local_variable)
    # 打印全局变量
    print(global_variable)

# 调用函数,观察变量打印结果
my_function()

# 尝试打印局部变量(会发生错误,因为它是局部的)
# print(local_variable)  # 这行代码会引发错误,因为local_variable是函数内的局部变量

# 打印全局变量
print(global_variable)  # 这是合法的,因为global_variable是全局变量

如果直接print(local_varible)

在这个例子中,global_variable 是一个全局变量,在函数 my_function 外部定义。local_variable 是在函数 my_function 内部定义的局部变量。在函数内部,我们可以访问并打印两个变量。但是,一旦我们尝试在函数外部访问 local_variable,将发生错误,因为它已经超出了其作用域。

如果你想在函数内修改全局变量,你需要使用 global 关键字。下面是一个例子:

# 定义全局变量
counter = 0

# 定义一个函数,修改全局变量
def increment_counter():
    global counter  # 声明counter为全局变量
    counter += 1   # 增加counter的值

# 调用函数
increment_counter()

# 打印全局变量,观察其是否被修改
print(counter)  # 输出: 1

在这个例子中,我们在函数 increment_counter 里使用 global counter 告诉Python counter 是一个全局变量,这样我们就可以在函数内部递增它的值。如果没有 global 关键字,将会在函数内部创建一个名为 counter 的新局部变量,而不是修改全局变量 counter

NOTES:

函数变量查找顺序遵循LEGB规则

Local -> EnClosed -> Global -> Buildins
本地  -> 闭包      -> 全局   -> 内建

使用全局变量共享数据

# 全局变量
num = 0
c_list = []
# 定义一个用来上传数据的函数
def upoad_data():
    # 如果想修改全局变量,需要声明
    global num
    num = 100
    print(num)
    c_list.append(1)
# 定义一个用下载数据的函数
def download_data():
    print(num,c_list)
# 测试
download_data()
upoad_data()
download_data()

#输出结果
# 0 []
# 100
# 100 [1]

引用

在Python中,引用是对对象的间接访问。当你创建一个变量,Python实际上会在内存中创建一个对象,并让变量引用(指向)那个对象。当你将一个变量赋值给另一个变量时,新变量将引用同一个对象,而不是创建一个新对象(跟文件的快捷方式一个原理,文件只有一个,快捷方式很多)。

这里有一个简单的例子来说明引用的概念:

# 创建一个列表对象,并让变量a引用它
a = [1, 2, 3]
# 让变量b也引用同一个列表对象
b = a
# 修改列表中的一个元素
a[0] = 10
# 打印两个变量
print(a)  # 输出: [10, 2, 3]
print(b)  # 输出: [10, 2, 3],因为b和a引用的是同一个对象

# 通过  id() 函数可以得到数据在内存中的地址
print(id(a))
print(id(b))

# 输出结果如下:
# [10, 2, 3]
# [10, 2, 3]
# 2153874264192
# 2153874264192

在这个例子中,a 是一个列表对象的引用。当我们将 a 赋值给 b 时,b 也成为了同一个列表对象的引用。因此,当我们通过 a 修改列表中的元素时,通过 b 打印列表也会显示修改后的结果。

Python中的引用特别重要,因为它们影响了如何传递参数到函数中,以及函数如何影响这些参数。Python中的参数传递是通过“传对象引用”完成的,这意味着函数中的形参变成了实参对象的一个新的引用,所以如果你在函数内部修改了这个对象(如列表、字典等可变类型),原始对象也会受到影响。但如果你在函数里重新绑定了形参到一个新对象,原始对象不会改变。

下面是一个例子来说明这一点:

def append_to_list(lst):
    # 这里修改的是lst引用的对象,所以原始对象也会改变
    lst.append(4)

def reassign_list(lst):
    # 这里将lst引用到了一个新的对象,原始对象不会改变
    lst = [4, 5, 6]

# 创建一个列表对象
my_list = [1, 2, 3]

# 传递引用到函数,修改列表
append_to_list(my_list)
print(my_list)  # 输出: [1, 2, 3, 4]

# 传递引用到函数,尝试重新赋值列表
reassign_list(my_list)
print(my_list)  # 输出: [1, 2, 3, 4],因为重新赋值没有影响原始对象

文章来源:https://blog.csdn.net/qq_44709053/article/details/134993071
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。