python常用代码-自用 三元表达式、列表生成式
文章目录
python
1、三元表达式
# if else
x = 10
y = 20
# 使用三元表达式判断 x 和 y 的大小,并赋值给 result
result = "x 大于 y" if x > y else "x 小于或等于 y"
print(result) # 输出: x 小于或等于 y
2、列表生成式
# [expression for item in iterable if condition]
# expression:要计算并添加到新列表中的表达式。
# item:从可迭代对象中获取的元素。
# iterable:一个可迭代对象,例如列表、字符串、范围等。
# condition(可选):过滤条件,只有满足条件的元素才会被包含在新列表中。
# 例子
# 创建一个包含 1 到 10 的平方的列表
squares = [x**2 for x in range(1, 11)]
print(squares) # 输出: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# 创建一个包含 1 到 10 中偶数的平方的列表
even_squares = [x**2 for x in range(1, 11) if x % 2 == 0]
print(even_squares) # 输出: [4, 16, 36, 64, 100]
# 嵌套循环:创建一个包含 (i, j) 元组的列表,其中 i 是 1 到 3,j 是 1 到 2
pairs = [(i, j) for i in range(1, 4) for j in range(1, 3)]
print(pairs) # 输出: [(1, 1), (1, 2), (2, 1), (2, 2), (3, 1), (3, 2)]
# 带有多个条件的列表生成式(两个if相当于用and连接)
filtered_list = [x for x in range(20) if x % 2 == 0 if x % 3 == 0]
# 等价于下面
filtered_list = [x for x in range(20) if (x % 2 == 0 and x % 3 == 0)]
print(filtered_list) # 输出: [0, 6, 12, 18]
# 带有多个条件的列表生成式使用or连接
custom_list = [x for x in range(20) if x % 2 == 0 or if x % 5 == 0]
custom_list = [x for x in range(20) if (x % 2 == 0 or x % 5 == 0)]
print(custom_list) # 输出: [0, 2, 4, 5, 6, 8, 10, 12, 14, 15, 16, 18, 20]
# 从一个字符串中提取字母并转换为大写
text = "Hello, World!"
uppercase_letters = [char.upper() for char in text if char.isalpha()]
print(uppercase_letters) # 输出: ['H', 'E', 'L', 'L', 'O', 'W', 'O', 'R', 'L', 'D']
3、判断一个序列是不是另一个序列的子序列
def is_subsequence(a, b):
b = iter(b)
return all(i in b for i in a)
print(is_subsequence([1, 3], [0, 1, 2, 3])) # 输出: True
print(is_subsequence([1, 4], [0, 1, 2, 3])) # 输出: False
定义函数def is_subsequence(a, b):
定义一个名为 is_subsequence
的函数,接受两个参数 a
和 b
创建迭代器b = iter(b)
:将 b
转换为一个迭代器。这样做的目的是为了在检查 b
中是否存在元素时,可以消耗掉 b
中的元素。换句话说,一旦某个元素在 b
中被找到,之后的查找会从该元素后面开始,而不是从头开始
检查子序列return all(i in b for i in a)
:
- 这个表达式使用生成器表达式遍历
a
中的每个元素i
。 - 对于每个元素
i
,它检查是否在迭代器b
中。 all()
函数会返回True
当且仅当生成器表达式中的所有检查都返回True
。也就是说,只有当a
中的每个元素都能在b
中找到时,is_subsequence
才会返回True
4、 GIL 全局解释器锁(Global Interpreter Lock,简称 GIL)
Python 的全局解释器锁(Global Interpreter Lock,简称 GIL)是一个机制,用于确保在任何时刻只有一个线程可以执行 Python 字节码。这一设计主要是为了简化 CPython 的内存管理并避免多线程环境下的数据竞争和崩溃。但使用线程时的时候仍需要自己加锁来管理内存。
GIL 工作原理
单线程运行: GIL 使得 CPython 解释器在执行字节码时只允许一个线程运行。这意味着即使在多核处理器上,Python 程序也不能利用多个 CPU 核心进行并行计算。
线程切换: 当一个线程需要执行一段时间的操作(如 I/O 操作),GIL 会被释放,允许其他线程获取 GIL 并执行。这种切换通常发生在 I/O 阻塞、时间片到期等情况下。这样,虽然 GIL 限制了 CPU 密集型操作的并行性,但对于 I/O 密集型操作,多个线程仍然可以有效共享时间。
影响:
- 对于 CPU 密集型任务,GIL 可能导致性能瓶颈,因为多个线程无法并行运行。
- 对于 I/O 密集型任务,如网络请求或文件读写,GIL 的影响较小,因为线程可以在等待 I/O 时让出 GIL。
注: NumPy 的许多核心功能是用 C 和 Fortran 编写的,这些底层库可以在执行计算时释放 GIL。这意味着在进行大量数值计算时,NumPy 可以利用多核 CPU 的优势,特别是在调用外部库(如 BLAS 或 LAPACK)进行矩阵运算时
5、装饰器
简单装饰器
- 装饰器是一个接收函数作为参数并返回一个增强功能的函数(通常是一个闭包)的函数。装饰器的目的是在不修改原始函数代码的前提下添加额外的功能
- 一个典型的装饰器定义没有外层函数包裹,直接
接收一个函数并返回一个函数
# 外层函数(Decorator Function):这个函数接受被装饰的函数作为参数
def decorator(func):
# 内层函数(Wrapper Function):这个函数用于包装或增强被装饰的函数的行为。它通常会接受任意的参数,并在适当的时候调用原始函数。
def wrapper():
print("在函数执行前做点什么")
# 调用原始函数
func()
print("在函数执行后做点什么")
return wrapper
@decorator
def say_hello():
print("Hello!")
say_hello()
装饰器工厂
- 装饰器工厂是一个
返回装饰器的函数
。这种结构让你可以在创建装饰器时传递参数,从而控制装饰器的行为。 - 装饰器工厂通常由两层或更多层函数组成:
最外层函数接收装饰器的配置参数
,内层函数则是实际的装饰器,它接收一个函数并返回一个增强版的函数。
# 简单装饰器本身不支持在装饰器应用时直接传递参数来控制其行为
def decorator_with_args(prefix):
def decorator(func):
def wrapper(*args, **kwargs):
print(prefix, "在函数执行前做点什么")
result = func(*args, **kwargs)
print(prefix, "在函数执行后做点什么")
return result
return wrapper
return decorator
@decorator_with_args("LOG:")
def say_hello():
print("Hello!")
say_hello()
类装饰器
类装饰器是使用类来实现装饰器的功能。类装饰器利用了类的 __call__
方法,这使得类的实例可以被当作函数调用,使用类装饰器的优势在于它能够利用面向对象编程的特性,如继承、封装等,来构建更复杂的装饰器逻辑。
普通的装饰器用类方法实现
class CountCalls:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("在函数执行前做点什么")
result = self.func(*args, **kwargs)
print("在函数执行后做点什么")
return result
@CountCalls
def say_hello():
print("Hello!")
say_hello()
装饰器工厂用类装饰器实现
from functools import wraps
class CountCalls:
def __init__(self, prefix):
self.prefix = prefix
def __call__(self, func):
# 将一些重要的元数据从原始函数(即被装饰的函数 func)复制到包装函数(即装饰器内部定义的函数 wrapper)。这些元数据包括函数的名称 __name__、文档字符串 __doc__、以及其他由用户定义的属性。
@wraps(func)
def wrapper(*args, **kwargs):
print(self.prefix, "在函数执行前做点什么")
result = func(*args, **kwargs)
print(self.prefix, "在函数执行后做点什么")
return result
return wrapper
@CountCalls(prefix='LOG:')
def say_hello():
print("Hello!")
say_hello()
当函数执行失败时按照传入参数重试
import logging
import time
from functools import wraps
from time import sleep
class Retry:
"""
类装饰器,当函数执行抛出异常时,按照max_retries和wait_time重试
"""
def __init__(self, max_retries=3, wait_time=2):
self.max_retries = max_retries
self.wait_time = wait_time
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
attempts = 0
while attempts < self.max_retries:
try:
return func(*args, **kwargs)
except Exception as e:
attempts += 1
logging.error(f"Error occurred: {e}. Retrying {attempts}/{self.max_retries}...")
time.sleep(self.wait_time) # 等待惩罚时间
if attempts == self.max_retries:
logging.error("Max retries reached. Giving up.")
return wrapper
@Retry(max_retries=5, wait_time=1)
def say_hello():
print("Hello!")
sleep(0.2)
raise Exception("手动抛出异常")
say_hello()
# Hello!
# ERROR:root:Error occurred: 手动抛出异常. Retrying 1/5...
# Hello!
# ERROR:root:Error occurred: 手动抛出异常. Retrying 2/5...
# Hello!
# ERROR:root:Error occurred: 手动抛出异常. Retrying 3/5...
# Hello!
# ERROR:root:Error occurred: 手动抛出异常. Retrying 4/5...
# Hello!
# ERROR:root:Error occurred: 手动抛出异常. Retrying 5/5...
# ERROR:root:Max retries reached. Giving up.