当前位置: 首页 > news >正文

python语法笔记

Python 问题解答记录

python语法笔记之-字符串 index() 方法语法详解

问题代码

str1 = "Hello,Python";
str2 = "Python";
print(str1.index(str2));

语法详解

1. str.index() 方法基本语法
str.index(sub[, start[, end]])

参数说明:

  • sub: 要查找的子字符串
  • start: 可选参数,开始查找的位置(默认为0)
  • end: 可选参数,结束查找的位置(默认为字符串长度)

返回值:

  • 返回子字符串在原字符串中第一次出现的索引位置
  • 如果找不到子字符串,会抛出 ValueError 异常
2. 代码执行过程分析
str1 = "Hello,Python"  # 原字符串
str2 = "Python"        # 要查找的子字符串
print(str1.index(str2))  # 输出:7

执行步骤:

  1. str1 包含字符串 "Hello,Python"
  2. str2 包含字符串 "Python"
  3. str1.index(str2)str1 中查找 str2 第一次出现的位置
  4. "Python""Hello,Python" 中从索引7开始出现
  5. 输出结果:7
3. 字符串索引位置说明
字符串: "Hello,Python"
索引:    012345678901
  • "Python" 从索引7开始,到索引12结束
  • 所以 index() 返回第一个字符 'P' 的位置:7
4. 相关方法对比
方法功能找不到时的行为
index()查找子字符串位置抛出 ValueError
find()查找子字符串位置返回 -1
rindex()从右向左查找抛出 ValueError
rfind()从右向左查找返回 -1
5. 实际应用示例
# 基本用法
text = "Hello, World!"
print(text.index("World"))  # 输出:7# 指定搜索范围
text = "Hello, World! Hello, Python!"
print(text.index("Hello", 1))  # 从索引1开始查找,输出:14# 错误处理
try:text = "Hello, World!"position = text.index("Python")print(f"找到位置:{position}")
except ValueError:print("未找到子字符串")# 使用 find() 方法(推荐)
text = "Hello, World!"
position = text.find("Python")
if position != -1:print(f"找到位置:{position}")
else:print("未找到子字符串")
6. 注意事项
  1. 区分大小写index() 方法区分大小写

    text = "Hello, World!"
    print(text.index("world"))  # ValueError: substring not found
    
  2. 只返回第一次出现的位置:如果有多个相同的子字符串,只返回第一个

    text = "Hello, Hello, World!"
    print(text.index("Hello"))  # 输出:0(不是7)
    
  3. 空字符串:空字符串在任何位置都能找到

    text = "Hello"
    print(text.index(""))  # 输出:0
    
  4. 建议使用 find() 方法find() 方法更安全,不会抛出异常

    text = "Hello, World!"
    position = text.find("Python")  # 返回 -1,不会抛出异常
    

python语法笔记之-divmod() 函数语法详解

问题代码

a = 100
b = 14
print(divmod(a, b))

语法详解

1. divmod() 函数基本语法
divmod(x, y)

参数说明:

  • x: 被除数(dividend)
  • y: 除数(divisor)

返回值:

  • 返回一个元组 (quotient, remainder)
  • quotient: 商(整数除法结果)
  • remainder: 余数
2. 代码执行过程分析
a = 100  # 被除数
b = 14   # 除数
print(divmod(a, b))  # 输出:(7, 2)

执行步骤:

  1. a = 100b = 14
  2. divmod(100, 14) 计算 100 除以 14
  3. 商:100 ÷ 14 = 7(整数除法)
  4. 余数:100 - (14 × 7) = 100 - 98 = 2
  5. 返回元组:(7, 2)
3. 数学原理说明

divmod(a, b) 等价于:

quotient = a // b    # 整数除法
remainder = a % b    # 取余运算
return (quotient, remainder)

验证:

a, b = 100, 14
print(f"a // b = {a // b}")  # 7
print(f"a % b = {a % b}")    # 2
print(f"divmod(a, b) = {divmod(a, b)}")  # (7, 2)
4. 实际应用示例
# 基本用法
print(divmod(10, 3))    # (3, 1)
print(divmod(20, 5))    # (4, 0)
print(divmod(7, 2))     # (3, 1)# 负数情况
print(divmod(-10, 3))   # (-4, 2)
print(divmod(10, -3))   # (-4, -2)
print(divmod(-10, -3))  # (3, -1)# 浮点数情况
print(divmod(10.5, 3))  # (3.0, 1.5)
print(divmod(10, 3.5))  # (2.0, 3.0)# 零除错误
try:print(divmod(10, 0))
except ZeroDivisionError as e:print(f"错误:{e}")  # 错误:integer division or modulo by zero
5. 常见应用场景

1. 时间转换

# 将秒数转换为小时和分钟
total_seconds = 3661
hours, remaining_seconds = divmod(total_seconds, 3600)
minutes, seconds = divmod(remaining_seconds, 60)
print(f"{total_seconds}秒 = {hours}小时{minutes}分钟{seconds}秒")
# 输出:3661秒 = 1小时1分钟1秒

2. 数字分解

# 将数字分解为百位、十位、个位
number = 123
hundreds, remainder = divmod(number, 100)
tens, ones = divmod(remainder, 10)
print(f"{number} = {hundreds}×100 + {tens}×10 + {ones}")
# 输出:123 = 1×100 + 2×10 + 3

3. 进制转换

# 十进制转二进制
def decimal_to_binary(n):if n == 0:return "0"binary = ""while n > 0:n, remainder = divmod(n, 2)binary = str(remainder) + binaryreturn binaryprint(decimal_to_binary(10))  # 1010

4. 循环队列实现

# 循环队列索引计算
def get_circular_index(index, size):return divmod(index, size)[1]  # 等价于 index % sizequeue_size = 5
for i in range(10):circular_index = get_circular_index(i, queue_size)print(f"原始索引: {i}, 循环索引: {circular_index}")
6. 与其他函数的对比
函数/操作功能返回值
divmod(x, y)同时计算商和余数(quotient, remainder)
x // y整数除法quotient
x % y取余运算remainder
x / y浮点除法float
7. 注意事项
  1. 整数除法divmod() 使用整数除法,不是浮点除法

    print(divmod(10, 3))  # (3, 1) 不是 (3.333..., 1)
    
  2. 负数处理:负数的 divmod() 结果遵循 Python 的整数除法规则

    print(divmod(-10, 3))   # (-4, 2)
    print(divmod(10, -3))   # (-4, -2)
    
  3. 浮点数:如果参数是浮点数,结果也是浮点数

    print(divmod(10.5, 3))  # (3.0, 1.5)
    
  4. 零除错误:除数为0时会抛出 ZeroDivisionError

    try:divmod(10, 0)
    except ZeroDivisionError:print("不能除以零")
    

python语法笔记之-字符编码函数语法详解

问题代码

return ? == 'A';

选项:

  • A: ord(65)
  • B: chr(65)
  • C: 65+''
  • D: '+65

答案

正确答案:B - chr(65)

语法详解

1. chr() 函数基本语法
chr(i)

参数说明:

  • i: 整数,表示 Unicode 码点(0-1,114,111)

返回值:

  • 返回对应的 Unicode 字符

示例:

print(chr(65))  # 'A'
print(chr(97))  # 'a'
print(chr(48))  # '0'
print(chr(32))  # ' ' (空格)
2. ord() 函数基本语法
ord(c)

参数说明:

  • c: 单个字符

返回值:

  • 返回字符的 Unicode 码点

示例:

print(ord('A'))  # 65
print(ord('a'))  # 97
print(ord('0'))  # 48
print(ord(' '))  # 32
3. 各选项详细分析

选项A:ord(65)

# 错误用法
print(ord(65))  # TypeError: ord() expected a character, but int found
  • ord() 函数需要字符作为参数,不能是数字
  • 正确的用法:ord('A') 返回 65

选项B:chr(65)

# 正确用法
print(chr(65))  # 'A'
print(chr(65) == 'A')  # True
  • chr(65) 返回字符 ‘A’
  • 所以 chr(65) == 'A' 返回 True

选项C:65+''

# 语法错误
print(65 + '')  # TypeError: unsupported operand type(s) for +: 'int' and 'str'
  • Python 中不能直接将整数与字符串相加
  • 需要先转换:str(65) + ''65 + ''(如果 65 是字符串)

选项D:'+65

# 语法错误
print('+65')  # 这只是字符串,不是表达式
  • 这不是有效的 Python 表达式
  • 可能是想表达 '+' + str(65) 或其他含义
4. 字符编码相关函数对比
函数功能参数返回值示例
chr(i)数字转字符整数字符chr(65)'A'
ord(c)字符转数字字符整数ord('A')65
str(i)数字转字符串任意类型字符串str(65)'65'
int(s)字符串转数字字符串整数int('65')65
5. 实际应用示例

1. 字符转换

# 大写字母转小写
def to_lower(char):if 'A' <= char <= 'Z':return chr(ord(char) + 32)return charprint(to_lower('A'))  # 'a'
print(to_lower('Z'))  # 'z'

2. 字符串处理

# 检查字符类型
def is_uppercase(char):return 'A' <= char <= 'Z'def is_lowercase(char):return 'a' <= char <= 'z'def is_digit(char):return '0' <= char <= '9'print(is_uppercase('A'))  # True
print(is_lowercase('a'))  # True
print(is_digit('5'))      # True

3. 密码学应用

# 简单的凯撒密码
def caesar_cipher(text, shift):result = ""for char in text:if char.isalpha():# 确定基准值(A=65, a=97)base = ord('A') if char.isupper() else ord('a')# 计算新位置new_pos = (ord(char) - base + shift) % 26# 转换回字符result += chr(base + new_pos)else:result += charreturn resultprint(caesar_cipher("HELLO", 3))  # "KHOOR"
print(caesar_cipher("KHOOR", -3))  # "HELLO"

4. 进制转换

# 十六进制字符转换
def hex_to_char(hex_str):return chr(int(hex_str, 16))def char_to_hex(char):return hex(ord(char))print(hex_to_char('41'))  # 'A'
print(char_to_hex('A'))   # '0x41'
6. ASCII 码表(常用部分)
字符ASCII 码说明
'A'65大写字母A
'Z'90大写字母Z
'a'97小写字母a
'z'122小写字母z
'0'48数字0
'9'57数字9
' '32空格
'\n'10换行符
'\t'9制表符
7. 注意事项
  1. Unicode 支持chr()ord() 支持 Unicode,不仅仅是 ASCII

    print(chr(128512))  # '😀' (笑脸表情)
    print(ord('😀'))    # 128512
    
  2. 参数范围chr() 的参数范围是 0-1,114,111

    try:print(chr(-1))
    except ValueError as e:print(f"错误:{e}")  # 错误:chr() arg not in range(0x110000)
    
  3. 字符长度ord() 只能处理单个字符

    try:print(ord('AB'))
    except TypeError as e:print(f"错误:{e}")  # 错误:ord() expected a character, but string of length 2 found
    
  4. 类型转换:注意字符串和数字的区别

    print(chr(65))    # 'A' (字符)
    print(str(65))    # '65' (字符串)
    print(int('65'))  # 65 (整数)
    

python语法笔记之-slots 继承机制语法详解

问题代码

class Vector:__slots__ = 'x', 'y'def __init__(self):passclass Vector3d(Vector):__slots__ = 'x', 'z'def __init__(self):passvector = Vector()
vector3d = Vector3d()

语法详解

1. __slots__ 基本概念

__slots__ 是 Python 类的一个特殊属性,用于:

  • 限制类的实例只能拥有指定的属性
  • 节省内存空间(避免 __dict__ 字典)
  • 提高属性访问速度
2. 代码执行分析
# 创建 Vector 实例
vector = Vector()
# vector 只能有 x, y 属性# 创建 Vector3d 实例  
vector3d = Vector3d()
# vector3d 只能有 x, z 属性(注意:没有 y 属性)

属性测试:

# Vector 实例
vector.x = 1  # 正常
vector.y = 2  # 正常
try:vector.z = 3  # AttributeError: 'Vector' object has no attribute 'z'
except AttributeError as e:print(f"Vector 错误:{e}")# Vector3d 实例
vector3d.x = 1  # 正常
vector3d.z = 3  # 正常
try:vector3d.y = 2  # AttributeError: 'Vector3d' object has no attribute 'y'
except AttributeError as e:print(f"Vector3d 错误:{e}")
3. __slots__ 继承机制详解

重要规则:

  1. 子类的 __slots__完全覆盖父类的 __slots__
  2. 子类不会自动继承父类的 __slots__ 属性
  3. 如果需要父类的属性,必须在子类中显式声明

继承关系分析:

class Vector:__slots__ = 'x', 'y'  # Vector 实例只能有 x, y 属性class Vector3d(Vector):__slots__ = 'x', 'z'  # Vector3d 实例只能有 x, z 属性# 注意:没有 y 属性!
4. 正确的继承方式

方式1:显式包含父类属性

class Vector:__slots__ = 'x', 'y'def __init__(self):passclass Vector3d(Vector):__slots__ = 'x', 'y', 'z'  # 显式包含父类的 x, y 属性def __init__(self):super().__init__()# 测试
vector3d = Vector3d()
vector3d.x = 1  # 正常
vector3d.y = 2  # 正常
vector3d.z = 3  # 正常

方式2:使用元组合并

class Vector:__slots__ = 'x', 'y'def __init__(self):passclass Vector3d(Vector):__slots__ = Vector.__slots__ + ('z',)  # 合并父类的 slotsdef __init__(self):super().__init__()# 测试
vector3d = Vector3d()
vector3d.x = 1  # 正常
vector3d.y = 2  # 正常
vector3d.z = 3  # 正常
5. 实际应用示例

1. 几何图形类

class Point2D:__slots__ = 'x', 'y'def __init__(self, x, y):self.x = xself.y = ydef distance_to_origin(self):return (self.x**2 + self.y**2)**0.5class Point3D(Point2D):__slots__ = 'x', 'y', 'z'  # 包含父类的 x, ydef __init__(self, x, y, z):super().__init__(x, y)self.z = zdef distance_to_origin(self):return (self.x**2 + self.y**2 + self.z**2)**0.5# 测试
p2d = Point2D(3, 4)
p3d = Point3D(3, 4, 5)
print(f"2D距离:{p2d.distance_to_origin()}")  # 5.0
print(f"3D距离:{p3d.distance_to_origin()}")  # 7.0710678118654755

2. 数据结构类

class Node:__slots__ = 'data', 'next'def __init__(self, data):self.data = dataself.next = Noneclass DoubleNode(Node):__slots__ = 'data', 'next', 'prev'  # 包含父类的 data, nextdef __init__(self, data):super().__init__(data)self.prev = None# 测试
node = Node(10)
dnode = DoubleNode(20)
print(f"Node: {node.data}")      # 10
print(f"DoubleNode: {dnode.data}")  # 20

3. 配置类

class BaseConfig:__slots__ = 'host', 'port'def __init__(self, host, port):self.host = hostself.port = portclass DatabaseConfig(BaseConfig):__slots__ = 'host', 'port', 'username', 'password', 'database'def __init__(self, host, port, username, password, database):super().__init__(host, port)self.username = usernameself.password = passwordself.database = database# 测试
db_config = DatabaseConfig('localhost', 3306, 'user', 'pass', 'mydb')
print(f"数据库:{db_config.host}:{db_config.port}")
6. __slots____dict__ 对比
特性使用 __slots__使用 __dict__
内存使用更少更多
属性访问速度更快较慢
动态添加属性不允许允许
继承复杂性需要显式管理自动继承
7. 常见错误和注意事项

错误1:忘记包含父类属性

class Parent:__slots__ = 'a', 'b'class Child(Parent):__slots__ = 'c'  # 错误:丢失了 a, b 属性def __init__(self):self.a = 1  # AttributeError!

错误2:重复定义属性

class Parent:__slots__ = 'a', 'b'class Child(Parent):__slots__ = 'a', 'b', 'a'  # 错误:重复的 'a'

错误3:与 __dict__ 冲突

class MyClass:__slots__ = 'x', 'y'__dict__ = {}  # 错误:不能同时使用 __slots__ 和 __dict__
8. 最佳实践
  1. 明确继承关系:在子类中显式包含需要的父类属性
  2. 使用元组合并__slots__ = Parent.__slots__ + ('new_attr',)
  3. 考虑内存优化:对于大量实例的类,使用 __slots__ 可以节省内存
  4. 保持灵活性:如果类需要动态添加属性,不要使用 __slots__
9. 性能对比示例
import sys# 不使用 __slots__
class RegularPoint:def __init__(self, x, y):self.x = xself.y = y# 使用 __slots__
class SlottedPoint:__slots__ = 'x', 'y'def __init__(self, x, y):self.x = xself.y = y# 内存使用对比
regular = RegularPoint(1, 2)
slotted = SlottedPoint(1, 2)print(f"RegularPoint 大小:{sys.getsizeof(regular)} 字节")
print(f"SlottedPoint 大小:{sys.getsizeof(slotted)} 字节")
# 通常 SlottedPoint 比 RegularPoint 小 40-50 字节

python语法笔记之-Python 类继承语法详解

问题代码

# 2. 继承
print("\n2. 继承:")class Person:def __init__(self, name, age):self.name = nameself.age = agedef speak(self):return f"{self.name}在说话"class Teacher(Person):def __init__(self, name, age, subject):super().__init__(name, age)self.subject = subjectdef teach(self):return f"{self.name}正在教授{self.subject}"teacher = Teacher("张老师", 35, "数学")
print(teacher.speak())
print(teacher.teach())

语法详解

1. 继承的基本概念

继承是面向对象编程的核心概念之一,允许一个类(子类)继承另一个类(父类)的属性和方法。

继承关系:

  • Person 是父类(基类)
  • Teacher 是子类(派生类)
  • Teacher 继承 Person 的所有属性和方法
2. 父类 Person 分析
class Person:def __init__(self, name, age):self.name = name    # 实例属性:姓名self.age = age      # 实例属性:年龄def speak(self):return f"{self.name}在说话"  # 实例方法:说话

特点:

  • 构造函数 __init__ 初始化 nameage 属性
  • speak() 方法返回说话信息
  • 这是一个通用的"人"类
3. 子类 Teacher 分析
class Teacher(Person):  # 继承 Person 类def __init__(self, name, age, subject):super().__init__(name, age)  # 调用父类构造函数self.subject = subject       # 新增属性:学科def teach(self):return f"{self.name}正在教授{self.subject}"  # 新增方法:教学

关键语法:

  1. class Teacher(Person) - 声明继承关系
  2. super().__init__(name, age) - 调用父类构造函数
  3. self.subject = subject - 添加子类特有的属性
  4. teach() - 添加子类特有的方法
4. 代码执行过程分析
teacher = Teacher("张老师", 35, "数学")

执行步骤:

  1. 创建 Teacher 实例,传入参数 ("张老师", 35, "数学")
  2. 调用 Teacher.__init__() 方法
  3. 执行 super().__init__(name, age),调用父类 Person.__init__()
  4. 父类初始化 self.name = "张老师"self.age = 35
  5. 子类初始化 self.subject = "数学"
  6. 实例创建完成

结果:

print(teacher.speak())  # 输出:张老师在说话
print(teacher.teach())  # 输出:张老师正在教授数学
5. 继承的属性和方法

继承的属性:

  • teacher.name = “张老师”(来自父类)
  • teacher.age = 35(来自父类)
  • teacher.subject = “数学”(子类特有)

继承的方法:

  • teacher.speak() - 继承自父类
  • teacher.teach() - 子类特有
6. super() 函数详解

super() 的作用:

  • 返回父类的代理对象
  • 用于调用父类的方法
  • 支持多重继承

语法形式:

super().__init__(args)      # Python 3 推荐写法
super(Teacher, self).__init__(args)  # Python 2 写法

实际应用:

class Teacher(Person):def __init__(self, name, age, subject):# 调用父类构造函数,初始化 name 和 agesuper().__init__(name, age)# 初始化子类特有属性self.subject = subjectself.salary = 5000  # 可以继续添加更多属性
7. 继承的类型

1. 单继承(当前示例)

class Teacher(Person):  # 只继承一个父类pass

2. 多重继承

class Employee:def __init__(self, employee_id):self.employee_id = employee_idclass Teacher(Person, Employee):  # 继承多个父类def __init__(self, name, age, subject, employee_id):Person.__init__(self, name, age)Employee.__init__(self, employee_id)self.subject = subject

3. 多层继承

class Student(Person):def __init__(self, name, age, grade):super().__init__(name, age)self.grade = gradeclass GraduateStudent(Student):  # 继承 Student,间接继承 Persondef __init__(self, name, age, grade, research_area):super().__init__(name, age, grade)self.research_area = research_area
8. 方法重写(Override)

重写父类方法:

class Teacher(Person):def __init__(self, name, age, subject):super().__init__(name, age)self.subject = subjectdef speak(self):  # 重写父类的 speak 方法return f"{self.name}老师说:同学们好!"def teach(self):return f"{self.name}正在教授{self.subject}"# 测试
teacher = Teacher("张老师", 35, "数学")
print(teacher.speak())  # 输出:张老师老师说:同学们好!
9. 实际应用示例

1. 动物类继承体系

class Animal:def __init__(self, name, species):self.name = nameself.species = speciesdef make_sound(self):return "发出声音"class Dog(Animal):def __init__(self, name, breed):super().__init__(name, "狗")self.breed = breeddef make_sound(self):return f"{self.name}汪汪叫"def fetch(self):return f"{self.name}在捡球"class Cat(Animal):def __init__(self, name, color):super().__init__(name, "猫")self.color = colordef make_sound(self):return f"{self.name}喵喵叫"def climb(self):return f"{self.name}在爬树"# 测试
dog = Dog("旺财", "金毛")
cat = Cat("咪咪", "橘色")
print(dog.make_sound())  # 旺财汪汪叫
print(cat.make_sound())  # 咪咪喵喵叫

2. 图形类继承体系

class Shape:def __init__(self, color):self.color = colordef area(self):return 0def perimeter(self):return 0class Rectangle(Shape):def __init__(self, color, width, height):super().__init__(color)self.width = widthself.height = heightdef area(self):return self.width * self.heightdef perimeter(self):return 2 * (self.width + self.height)class Circle(Shape):def __init__(self, color, radius):super().__init__(color)self.radius = radiusdef area(self):import mathreturn math.pi * self.radius ** 2def perimeter(self):import mathreturn 2 * math.pi * self.radius# 测试
rect = Rectangle("红色", 5, 3)
circle = Circle("蓝色", 4)
print(f"矩形面积:{rect.area()}")      # 15
print(f"圆形面积:{circle.area():.2f}")  # 50.27
10. 继承的优势和注意事项

优势:

  1. 代码复用:避免重复编写相同的代码
  2. 层次结构:建立清晰的类层次关系
  3. 多态性:不同子类可以有不同的实现
  4. 维护性:修改父类影响所有子类

注意事项:

  1. 合理设计:继承关系应该符合"是一个"的关系
  2. 避免过深继承:继承层次不要太深,通常不超过3层
  3. 使用组合:有时候组合比继承更合适
  4. 方法重写:重写方法时要考虑是否调用父类方法
11. 继承 vs 组合

继承(is-a 关系):

class Teacher(Person):  # Teacher 是一个 Personpass

组合(has-a 关系):

class Teacher:def __init__(self, person, subject):self.person = person  # Teacher 有一个 Personself.subject = subjectdef speak(self):return self.person.speak()

python语法笔记之-列表 append() 方法语法详解

问题代码

numbers = [1, 2, 3, 4]
numbers.append([5,6,7,8])
print(len(numbers))

答案

输出结果:5

语法详解

1. list.append() 方法基本语法
list.append(x)

参数说明:

  • x: 要添加到列表末尾的元素(可以是任何类型)

返回值:

  • 无返回值(None),直接修改原列表

功能:

  • 在列表末尾添加一个元素
  • 无论 x 是什么类型,都会作为一个整体元素添加
2. 代码执行过程分析
numbers = [1, 2, 3, 4]           # 初始列表:[1, 2, 3, 4]
numbers.append([5,6,7,8])        # 添加列表:[5,6,7,8]
print(len(numbers))              # 输出:5

执行步骤:

  1. 创建列表 numbers = [1, 2, 3, 4],长度为 4
  2. 执行 numbers.append([5,6,7,8])
    • 将整个列表 [5,6,7,8] 作为一个元素添加到末尾
    • 列表变成 [1, 2, 3, 4, [5,6,7,8]]
  3. 执行 len(numbers),返回 5

验证:

numbers = [1, 2, 3, 4]
print(f"原始列表:{numbers},长度:{len(numbers)}")
# 输出:原始列表:[1, 2, 3, 4],长度:4numbers.append([5,6,7,8])
print(f"添加后:{numbers},长度:{len(numbers)}")
# 输出:添加后:[1, 2, 3, 4, [5,6,7,8]],长度:5
3. 常见误解分析

误解1:认为会展开列表

# 错误理解:以为会变成 [1, 2, 3, 4, 5, 6, 7, 8]
# 实际情况:变成 [1, 2, 3, 4, [5,6,7,8]]

误解2:认为会报错

# 错误理解:以为不能添加列表到列表中
# 实际情况:Python 允许列表嵌套,完全合法
4. 不同添加方法的对比
方法语法功能示例结果
append()list.append(x)添加单个元素[1,2].append([3,4])[1,2,[3,4]]
extend()list.extend(iterable)展开添加元素[1,2].extend([3,4])[1,2,3,4]
insert()list.insert(i, x)在指定位置插入[1,2].insert(1,3)[1,3,2]
+ 操作符list1 + list2连接两个列表[1,2] + [3,4][1,2,3,4]
5. 实际应用示例

1. 基本用法对比

# append() - 添加整个列表作为元素
numbers = [1, 2, 3]
numbers.append([4, 5])
print(numbers)  # [1, 2, 3, [4, 5]]
print(len(numbers))  # 4# extend() - 展开列表元素
numbers = [1, 2, 3]
numbers.extend([4, 5])
print(numbers)  # [1, 2, 3, 4, 5]
print(len(numbers))  # 5# + 操作符 - 连接列表
numbers = [1, 2, 3]
result = numbers + [4, 5]
print(result)  # [1, 2, 3, 4, 5]
print(len(result))  # 5

2. 嵌套列表应用

# 创建二维列表
matrix = []
matrix.append([1, 2, 3])
matrix.append([4, 5, 6])
matrix.append([7, 8, 9])
print(matrix)  # [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(len(matrix))  # 3# 访问元素
print(matrix[0])     # [1, 2, 3]
print(matrix[0][1])  # 2

3. 数据分组

# 按类型分组数据
numbers = [1, 2, 3, 4, 5]
strings = ['a', 'b', 'c']
booleans = [True, False]all_data = []
all_data.append(numbers)
all_data.append(strings)
all_data.append(booleans)print(all_data)  # [[1, 2, 3, 4, 5], ['a', 'b', 'c'], [True, False]]
print(len(all_data))  # 3# 访问特定类型的数据
print(all_data[0])  # [1, 2, 3, 4, 5] (数字)
print(all_data[1])  # ['a', 'b', 'c'] (字符串)

4. 购物车示例

class ShoppingCart:def __init__(self):self.items = []def add_item(self, name, price, quantity=1):# 将商品信息作为列表添加item = [name, price, quantity]self.items.append(item)def get_total(self):total = 0for item in self.items:total += item[1] * item[2]  # price * quantityreturn total# 使用示例
cart = ShoppingCart()
cart.add_item("苹果", 5.0, 3)
cart.add_item("香蕉", 3.0, 2)
cart.add_item("橙子", 4.0, 1)print(f"购物车项目数:{len(cart.items)}")  # 3
print(f"总价:{cart.get_total()}")  # 23.0
6. 列表操作的其他方法

1. 添加元素的方法

numbers = [1, 2, 3]# append() - 添加单个元素
numbers.append(4)
print(numbers)  # [1, 2, 3, 4]# extend() - 展开添加多个元素
numbers.extend([5, 6])
print(numbers)  # [1, 2, 3, 4, 5, 6]# insert() - 在指定位置插入
numbers.insert(0, 0)
print(numbers)  # [0, 1, 2, 3, 4, 5, 6]# += 操作符
numbers += [7, 8]
print(numbers)  # [0, 1, 2, 3, 4, 5, 6, 7, 8]

2. 删除元素的方法

numbers = [1, 2, 3, 4, 5]# remove() - 删除指定值的第一个元素
numbers.remove(3)
print(numbers)  # [1, 2, 4, 5]# pop() - 删除并返回指定位置的元素
popped = numbers.pop(1)
print(f"删除的元素:{popped}")  # 删除的元素:2
print(numbers)  # [1, 4, 5]# del 语句 - 删除指定位置的元素
del numbers[0]
print(numbers)  # [4, 5]# clear() - 清空列表
numbers.clear()
print(numbers)  # []
7. 性能考虑

append() vs extend() 性能对比:

import time# 使用 append() 添加多个元素
def test_append():numbers = []for i in range(10000):numbers.append(i)return numbers# 使用 extend() 添加多个元素
def test_extend():numbers = []numbers.extend(range(10000))return numbers# 性能测试
start = time.time()
test_append()
append_time = time.time() - startstart = time.time()
test_extend()
extend_time = time.time() - startprint(f"append() 时间:{append_time:.6f}秒")
print(f"extend() 时间:{extend_time:.6f}秒")
# extend() 通常更快,因为减少了函数调用次数
8. 常见错误和注意事项

错误1:混淆 append() 和 extend()

numbers = [1, 2, 3]# 想要添加 4, 5, 6 到列表中
numbers.append([4, 5, 6])  # 错误:会变成 [1, 2, 3, [4, 5, 6]]
print(numbers)# 正确做法
numbers = [1, 2, 3]
numbers.extend([4, 5, 6])  # 正确:会变成 [1, 2, 3, 4, 5, 6]
print(numbers)

错误2:忘记 append() 返回 None

numbers = [1, 2, 3]
result = numbers.append(4)
print(result)  # None
print(numbers)  # [1, 2, 3, 4]

错误3:在循环中修改列表

numbers = [1, 2, 3, 4, 5]# 错误:在循环中修改列表可能导致问题
for i in range(len(numbers)):if numbers[i] % 2 == 0:numbers.append(numbers[i] * 2)  # 可能导致无限循环# 正确做法:使用副本或反向遍历
numbers = [1, 2, 3, 4, 5]
for i in range(len(numbers) - 1, -1, -1):  # 反向遍历if numbers[i] % 2 == 0:numbers.append(numbers[i] * 2)
9. 最佳实践
  1. 选择合适的添加方法

    • 添加单个元素:使用 append()
    • 添加多个元素:使用 extend()+=
    • 在指定位置插入:使用 insert()
  2. 注意性能

    • 大量添加元素时,extend() 比多次 append() 更高效
    • 考虑使用列表推导式或生成器
  3. 避免常见错误

    • 记住 append() 返回 None
    • 在循环中修改列表要小心
    • 区分嵌套列表和扁平列表

python语法笔记之-PyCodeObject 对象详解

问题概述

PyCodeObject 是 Python 解释器内部用于表示编译后代码的核心数据结构,它是 Python 字节码执行的基础。

基本概念

1. PyCodeObject 的作用

PyCodeObject 对象是 Python 代码编译后的结果,包含:

  • 字节码指令序列
  • 常量表
  • 变量名表
  • 函数名表
  • 代码对象的各种元数据
2. 代码编译过程
# Python 代码编译过程
源代码 → 语法树 → 字节码 → PyCodeObject

详细步骤:

  1. 词法分析:将源代码分解为标记(tokens)
  2. 语法分析:构建抽象语法树(AST)
  3. 字节码生成:将 AST 转换为字节码
  4. PyCodeObject 创建:将字节码和相关信息封装成 PyCodeObject

语法详解

1. 查看 PyCodeObject 的方法

方法1:使用 compile() 函数

# 编译代码并获取 PyCodeObject
source_code = "print('Hello, World!')"
code_obj = compile(source_code, '<string>', 'exec')
print(type(code_obj))  # <class 'code'>
print(code_obj)        # <code object <module> at 0x...>

方法2:使用 dis 模块查看字节码

import disdef example_function():x = 10y = 20return x + y# 获取函数的 PyCodeObject
code_obj = example_function.__code__
print(f"代码对象:{code_obj}")
print(f"文件名:{code_obj.co_filename}")
print(f"函数名:{code_obj.co_name}")
print(f"参数数量:{code_obj.co_argcount}")# 反汇编查看字节码
print("\n字节码:")
dis.dis(code_obj)
2. PyCodeObject 的主要属性
def sample_function(a, b, c=10):"""示例函数"""x = a + by = x * creturn ycode_obj = sample_function.__code__# 基本信息
print(f"文件名:{code_obj.co_filename}")
print(f"函数名:{code_obj.co_name}")
print(f"行号:{code_obj.co_firstlineno}")
print(f"参数数量:{code_obj.co_argcount}")
print(f"局部变量数量:{code_obj.co_nlocals}")
print(f"栈大小:{code_obj.co_stacksize}")# 常量表
print(f"\n常量表:{code_obj.co_consts}")# 变量名表
print(f"变量名表:{code_obj.co_varnames}")# 函数名表
print(f"函数名表:{code_obj.co_names}")# 自由变量表
print(f"自由变量表:{code_obj.co_freevars}")# 单元格变量表
print(f"单元格变量表:{code_obj.co_cellvars}")

实际应用示例

1. 代码分析工具
import dis
import inspectdef analyze_function(func):"""分析函数的 PyCodeObject"""code_obj = func.__code__print(f"=== 函数分析:{func.__name__} ===")print(f"文件名:{code_obj.co_filename}")print(f"行号:{code_obj.co_firstlineno}")print(f"参数:{code_obj.co_varnames[:code_obj.co_argcount]}")print(f"局部变量:{code_obj.co_varnames}")print(f"常量:{code_obj.co_consts}")print(f"全局变量:{code_obj.co_names}")print("\n字节码:")dis.dis(func)# 测试函数
def complex_function(x, y, z=5):result = x + yif result > z:print("结果大于默认值")else:print("结果小于等于默认值")return result * 2analyze_function(complex_function)
2. 字节码优化分析
import dis
import timedef original_function():"""原始函数"""result = 0for i in range(1000):result += ireturn resultdef optimized_function():"""优化后的函数"""return sum(range(1000))# 分析字节码差异
print("=== 原始函数字节码 ===")
dis.dis(original_function)print("\n=== 优化函数字节码 ===")
dis.dis(optimized_function)# 性能对比
start = time.time()
for _ in range(10000):original_function()
original_time = time.time() - startstart = time.time()
for _ in range(10000):optimized_function()
optimized_time = time.time() - startprint(f"\n性能对比:")
print(f"原始函数:{original_time:.6f}秒")
print(f"优化函数:{optimized_time:.6f}秒")
print(f"性能提升:{original_time/optimized_time:.2f}倍")
3. 动态代码生成
import typesdef create_function_dynamically():"""动态创建函数"""# 定义字节码code = bytes([0x64, 0x01, 0x00,  # LOAD_CONST 10x64, 0x02, 0x00,  # LOAD_CONST 20x17,              # BINARY_ADD0x53               # RETURN_VALUE])# 创建 PyCodeObjectcode_obj = types.CodeType(0,                  # argcount0,                  # posonlyargcount0,                  # kwonlyargcount0,                  # nlocals2,                  # stacksize67,                 # flags (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)code,               # code(None, 1, 2),       # consts(),                 # names(),                 # varnames'<string>',         # filename'dynamic_func',     # name1,                  # firstlinenob'',                # lnotab(),                 # freevars()                  # cellvars)# 创建函数对象func = types.FunctionType(code_obj, globals(), 'dynamic_func')return func# 测试动态创建的函数
dynamic_func = create_function_dynamically()
print(f"动态函数结果:{dynamic_func()}")  # 输出:3
4. 代码混淆和反混淆
import dis
import marshaldef obfuscate_code(source_code):"""简单的代码混淆"""# 编译代码code_obj = compile(source_code, '<string>', 'exec')# 序列化 PyCodeObjectmarshalled = marshal.dumps(code_obj)# 简单的异或加密key = 0x42encrypted = bytes(b ^ key for b in marshalled)return encrypteddef deobfuscate_code(encrypted_data):"""反混淆代码"""# 异或解密key = 0x42decrypted = bytes(b ^ key for b in encrypted_data)# 反序列化code_obj = marshal.loads(decrypted)return code_obj# 测试代码混淆
source = """
x = 10
y = 20
print(f"结果:{x + y}")
"""# 混淆
obfuscated = obfuscate_code(source)
print(f"混淆后大小:{len(obfuscated)} 字节")# 反混淆并执行
deobfuscated = deobfuscate_code(obfuscated)
exec(deobfuscated)

PyCodeObject 属性详解

1. 核心属性说明
属性类型说明
co_codebytes字节码指令序列
co_conststuple常量表
co_namestuple全局变量名表
co_varnamestuple局部变量名表
co_freevarstuple自由变量名表
co_cellvarstuple单元格变量名表
co_filenamestr源文件名
co_namestr函数/类名
co_firstlinenoint第一行行号
co_lnotabbytes行号表
co_argcountint参数数量
co_posonlyargcountint仅位置参数数量
co_kwonlyargcountint仅关键字参数数量
co_nlocalsint局部变量数量
co_stacksizeint栈大小
co_flagsint代码标志
2. 字节码指令示例
import disdef example():x = 10y = 20z = x + yreturn zcode_obj = example.__code__print("字节码指令:")
for i, byte in enumerate(code_obj.co_code):if i % 2 == 0:print(f"{i:2d}: {byte:2d} ({dis.opname[byte]})")else:print(f"    {byte:2d}")print("\n反汇编结果:")
dis.dis(code_obj)

高级应用

1. 代码注入
import types
import disdef inject_code(target_func, injection_code):"""向函数注入代码"""# 获取原始代码对象original_code = target_func.__code__# 编译注入代码injection_obj = compile(injection_code, '<injection>', 'exec')# 合并常量表new_consts = original_code.co_consts + injection_obj.co_consts# 创建新的代码对象(简化版本)new_code = types.CodeType(original_code.co_argcount,original_code.co_posonlyargcount,original_code.co_kwonlyargcount,original_code.co_nlocals,original_code.co_stacksize,original_code.co_flags,original_code.co_code,new_consts,original_code.co_names,original_code.co_varnames,original_code.co_filename,original_code.co_name,original_code.co_firstlineno,original_code.co_lnotab,original_code.co_freevars,original_code.co_cellvars)# 创建新函数new_func = types.FunctionType(new_code, target_func.__globals__, target_func.__name__)return new_func# 测试代码注入
def target_function():print("原始函数执行")return 42# 注入代码
injected_func = inject_code(target_function, "print('注入的代码执行')")# 执行
result = injected_func()
print(f"结果:{result}")
2. 性能分析工具
import dis
import time
import statisticsdef analyze_performance(func, iterations=1000):"""分析函数性能"""code_obj = func.__code__print(f"=== 性能分析:{func.__name__} ===")print(f"字节码大小:{len(code_obj.co_code)} 字节")print(f"常量数量:{len(code_obj.co_consts)}")print(f"局部变量数量:{code_obj.co_nlocals}")print(f"栈大小:{code_obj.co_stacksize}")# 执行时间分析times = []for _ in range(iterations):start = time.perf_counter()func()end = time.perf_counter()times.append(end - start)print(f"平均执行时间:{statistics.mean(times)*1000:.3f} 毫秒")print(f"标准差:{statistics.stdev(times)*1000:.3f} 毫秒")return times# 测试函数
def fast_function():return sum(range(100))def slow_function():result = 0for i in range(100):result += ireturn result# 分析性能
fast_times = analyze_performance(fast_function)
slow_times = analyze_performance(slow_function)

注意事项和最佳实践

1. 安全考虑
# 危险:执行任意代码
def dangerous_exec(code_string):code_obj = compile(code_string, '<string>', 'exec')exec(code_obj)  # 可能执行恶意代码# 安全:限制执行环境
def safe_exec(code_string, allowed_globals=None):if allowed_globals is None:allowed_globals = {}code_obj = compile(code_string, '<string>', 'exec')exec(code_obj, allowed_globals)  # 限制全局变量
2. 调试技巧
import dis
import sysdef debug_code_object(code_obj):"""调试代码对象"""print(f"代码对象:{code_obj}")print(f"文件名:{code_obj.co_filename}")print(f"函数名:{code_obj.co_name}")print(f"行号:{code_obj.co_firstlineno}")# 检查字节码if len(code_obj.co_code) > 0:print("字节码指令:")dis.dis(code_obj)# 检查常量if code_obj.co_consts:print(f"常量:{code_obj.co_consts}")# 检查变量if code_obj.co_varnames:print(f"变量:{code_obj.co_varnames}")# 使用示例
def test_function():x = 10y = 20return x + ydebug_code_object(test_function.__code__)
3. 内存优化
import sys
import gcdef analyze_memory_usage(func):"""分析函数的内存使用"""code_obj = func.__code__print(f"=== 内存分析:{func.__name__} ===")print(f"代码对象大小:{sys.getsizeof(code_obj)} 字节")print(f"字节码大小:{len(code_obj.co_code)} 字节")print(f"常量表大小:{sys.getsizeof(code_obj.co_consts)} 字节")print(f"变量名表大小:{sys.getsizeof(code_obj.co_varnames)} 字节")# 创建多个实例测试内存instances = []for i in range(1000):instances.append(func)print(f"1000个函数实例总大小:{sys.getsizeof(instances)} 字节")# 清理del instancesgc.collect()# 测试
def simple_function():passanalyze_memory_usage(simple_function)

python语法笔记之-PyCodeObject 对象数量分析

问题代码

class A:pass
def Fun():pass
a = A() 
Fun()

问题

根据名字空间特性,以下代码经过 Python 编译器编译后,一共得到()个 PyCodeObject 对象?

答案

正确答案:3个 PyCodeObject 对象

详细分析

1. PyCodeObject 对象的创建规则

Python 编译器会为以下结构创建 PyCodeObject 对象:

  • 模块级别:每个 Python 文件(模块)都会创建一个 PyCodeObject
  • 函数定义:每个函数都会创建一个 PyCodeObject
  • 类定义:每个类都会创建一个 PyCodeObject
  • 方法定义:类中的每个方法都会创建一个 PyCodeObject
  • 生成器表达式:某些情况下也会创建独立的 PyCodeObject
2. 代码结构分析
class A:          # 类定义 → 创建 1 个 PyCodeObjectpassdef Fun():        # 函数定义 → 创建 1 个 PyCodeObjectpassa = A()           # 实例化语句(在模块级别)
Fun()             # 函数调用(在模块级别)

分析结果:

  1. 模块级别:整个文件作为一个模块 → 1个 PyCodeObject
  2. 类 A:类定义 → 1个 PyCodeObject
  3. 函数 Fun:函数定义 → 1个 PyCodeObject

总计:3个 PyCodeObject 对象

3. 验证方法

方法1:使用 compile() 函数

source_code = """
class A:pass
def Fun():pass
a = A() 
Fun()
"""# 编译整个模块
module_code = compile(source_code, '<string>', 'exec')
print(f"模块代码对象:{module_code}")# 编译类定义
class_code = compile("class A:\n    pass", '<string>', 'exec')
print(f"类代码对象:{class_code}")# 编译函数定义
func_code = compile("def Fun():\n    pass", '<string>', 'exec')
print(f"函数代码对象:{func_code}")

方法2:使用 dis 模块分析

import dis# 定义测试代码
class A:passdef Fun():pass# 分析模块级别的代码对象
print("=== 模块级别代码对象 ===")
dis.dis(compile("a = A()\nFun()", '<string>', 'exec'))print("\n=== 类代码对象 ===")
dis.dis(A.__dict__['__init__'].__code__ if '__init__' in A.__dict__ else "无")print("\n=== 函数代码对象 ===")
dis.dis(Fun.__code__)
4. 名字空间特性分析

Python 的名字空间层次:

模块名字空间
├── 类 A 的名字空间
│   └── 类方法(如果有)
├── 函数 Fun 的名字空间
└── 全局变量和语句

每个名字空间对应一个 PyCodeObject:

  • 模块名字空间 → 1个 PyCodeObject
  • 类 A 名字空间 → 1个 PyCodeObject
  • 函数 Fun 名字空间 → 1个 PyCodeObject
5. 实际验证示例

示例1:基本结构

import dis# 测试代码
test_code = """
class MyClass:passdef my_function():pass# 执行代码
obj = MyClass()
my_function()
"""# 编译并分析
compiled_code = compile(test_code, '<test>', 'exec')
print(f"编译后的代码对象:{compiled_code}")# 反汇编查看
print("\n反汇编结果:")
dis.dis(compiled_code)

示例2:更复杂的结构

class ComplexClass:def method1(self):passdef method2(self):passdef outer_function():def inner_function():passreturn inner_function# 分析代码对象数量
print("=== 代码对象分析 ===")
print(f"ComplexClass 代码对象:{ComplexClass.__dict__}")
print(f"outer_function 代码对象:{outer_function.__code__}")
print(f"inner_function 代码对象:{outer_function().__code__}")
6. 不同情况下的 PyCodeObject 数量

情况1:只有模块级代码

# 只有模块级代码
x = 10
y = 20
print(x + y)
# PyCodeObject 数量:1个(模块级别)

情况2:包含函数定义

def func():pass
# PyCodeObject 数量:2个(模块 + 函数)

情况3:包含类定义

class MyClass:pass
# PyCodeObject 数量:2个(模块 + 类)

情况4:包含类和方法

class MyClass:def method(self):pass
# PyCodeObject 数量:3个(模块 + 类 + 方法)

情况5:嵌套函数

def outer():def inner():passreturn inner
# PyCodeObject 数量:3个(模块 + outer函数 + inner函数)
7. 编译过程详解

Python 编译器的处理步骤:

  1. 词法分析:将源代码分解为标记
  2. 语法分析:构建抽象语法树(AST)
  3. 代码生成:为每个代码块创建 PyCodeObject
  4. 优化:对字节码进行优化

代码块识别规则:

  • 模块级别的代码作为一个代码块
  • 每个函数定义作为一个独立的代码块
  • 每个类定义作为一个独立的代码块
  • 类中的每个方法作为独立的代码块
8. 内存和性能考虑

PyCodeObject 的内存占用:

import sysdef analyze_code_objects():"""分析代码对象的内存占用"""# 定义测试代码class TestClass:def test_method(self):passdef test_function():pass# 分析内存占用module_size = sys.getsizeof(compile("", '<string>', 'exec'))class_size = sys.getsizeof(TestClass.__dict__['__init__'].__code__)func_size = sys.getsizeof(test_function.__code__)print(f"模块代码对象大小:{module_size} 字节")print(f"类代码对象大小:{class_size} 字节")print(f"函数代码对象大小:{func_size} 字节")print(f"总大小:{module_size + class_size + func_size} 字节")analyze_code_objects()
9. 调试和检查工具

工具1:代码对象检查器

def inspect_code_objects(source_code):"""检查源代码中的代码对象"""try:# 编译代码code_obj = compile(source_code, '<string>', 'exec')print(f"=== 代码对象分析 ===")print(f"代码对象:{code_obj}")print(f"常量:{code_obj.co_consts}")print(f"变量名:{code_obj.co_varnames}")print(f"函数名:{code_obj.co_names}")# 统计代码对象数量count = 1  # 模块级别# 检查常量中的代码对象for const in code_obj.co_consts:if hasattr(const, '__code__'):count += 1print(f"发现代码对象:{const}")print(f"总代码对象数量:{count}")except Exception as e:print(f"编译错误:{e}")# 测试
test_code = """
class A:pass
def Fun():pass
a = A() 
Fun()
"""inspect_code_objects(test_code)

工具2:递归代码对象计数器

def count_code_objects(code_obj, visited=None):"""递归计算代码对象数量"""if visited is None:visited = set()if id(code_obj) in visited:return 0visited.add(id(code_obj))count = 1# 检查常量中的代码对象for const in code_obj.co_consts:if hasattr(const, '__code__'):count += count_code_objects(const.__code__, visited)return count# 使用示例
source = """
class A:pass
def Fun():pass
a = A() 
Fun()
"""compiled = compile(source, '<string>', 'exec')
total_count = count_code_objects(compiled)
print(f"代码对象总数:{total_count}")
10. 常见误解和澄清

误解1:认为只有函数和类创建代码对象

  • 事实:模块级别也会创建代码对象

误解2:认为语句也会创建代码对象

  • 事实:只有代码块(函数、类、模块)创建代码对象,语句不创建

误解3:认为变量赋值创建代码对象

  • 事实:变量赋值是语句,不创建独立的代码对象

误解4:认为导入语句创建代码对象

  • 事实:导入语句在模块级别执行,不创建额外的代码对象
11. 实际应用场景

场景1:代码分析工具

def analyze_code_structure(filename):"""分析 Python 文件的代码结构"""with open(filename, 'r', encoding='utf-8') as f:source = f.read()code_obj = compile(source, filename, 'exec')print(f"=== 文件:{filename} ===")print(f"模块代码对象:{code_obj}")# 统计函数和类functions = []classes = []for name in code_obj.co_names:if name in globals():obj = globals()[name]if hasattr(obj, '__code__'):functions.append(name)elif hasattr(obj, '__dict__'):classes.append(name)print(f"函数数量:{len(functions)}")print(f"类数量:{len(classes)}")print(f"总代码对象数量:{1 + len(functions) + len(classes)}")

场景2:性能优化分析

def optimize_code_analysis(source_code):"""分析代码的优化潜力"""code_obj = compile(source_code, '<string>', 'exec')print("=== 代码优化分析 ===")print(f"字节码大小:{len(code_obj.co_code)} 字节")print(f"常量数量:{len(code_obj.co_consts)}")print(f"局部变量数量:{code_obj.co_nlocals}")print(f"栈大小:{code_obj.co_stacksize}")# 分析代码对象数量对性能的影响code_object_count = 1  # 模块级别for const in code_obj.co_consts:if hasattr(const, '__code__'):code_object_count += 1print(f"代码对象数量:{code_object_count}")print(f"平均每个代码对象大小:{len(code_obj.co_code) / code_object_count:.2f} 字节")

python语法笔记之-列表 sort() 方法语法详解

基本语法

list.sort(key=None, reverse=False)

参数说明

  • key:用于排序的函数(可选),对每个元素调用一次,排序时以其返回值为依据
  • reverse:是否倒序排序,默认为 False(升序),设为 True 时降序

返回值

  • 无返回值(返回 None),排序操作在原列表上进行

功能说明

  • sort() 是列表的原地排序方法,会直接修改原列表,不返回新列表
  • 排序算法为 Timsort,时间复杂度 O(n log n)

示例

numbers = [3, 1, 4, 2]
numbers.sort()
print(numbers)  # [1, 2, 3, 4]numbers.sort(reverse=True)
print(numbers)  # [4, 3, 2, 1]words = ['apple', 'banana', 'pear', 'orange']
words.sort(key=len)
print(words)  # ['pear', 'apple', 'banana', 'orange']

注意事项

  • sort() 只能用于列表,不能用于元组、字典等
  • 排序是原地进行的,原列表会被修改
  • 如果需要返回新排序列表而不改变原列表,请用 sorted()

常见错误

numbers = [3, 1, 2]
result = numbers.sort()
print(result)  # None
# 正确做法:直接用 numbers.sort(),然后用 numbers 查看结果

高级用法

  • 按对象属性排序
class Student:def __init__(self, name, score):self.name = nameself.score = scorestudents = [Student('Tom', 90), Student('Jerry', 85), Student('Alice', 95)]
students.sort(key=lambda s: s.score, reverse=True)
for s in students:print(s.name, s.score)
# 输出:Alice 95, Tom 90, Jerry 85

sort() 与 sorted() 区别

方法是否原地排序返回值适用对象
sort()None仅列表
sorted()新排序后的对象任意可迭代

典型应用场景

  • 数字、字符串、对象等的排序
  • 按自定义规则排序(如长度、属性、函数值等)

python语法笔记之-字典 fromkeys() 方法语法详解

基本语法

dict.fromkeys(keys, value=None)

参数说明

  • keys:可迭代对象,包含要作为字典键的元素
  • value:可选参数,所有键的默认值,默认为 None

返回值

  • 返回一个新的字典对象

功能说明

  • fromkeys() 是字典的类方法,用于创建一个新字典
  • 以给定的键和默认值创建字典
  • 所有键共享同一个值对象

基本示例

# 基本用法
keys = ['a', 'b', 'c']
d1 = dict.fromkeys(keys)
print(d1)  # {'a': None, 'b': None, 'c': None}d2 = dict.fromkeys(keys, 0)
print(d2)  # {'a': 0, 'b': 0, 'c': 0}# 使用字符串作为键
d3 = dict.fromkeys('hello', 1)
print(d3)  # {'h': 1, 'e': 1, 'l': 1, 'o': 1}# 使用元组作为键
d4 = dict.fromkeys((1, 2, 3), 'default')
print(d4)  # {1: 'default', 2: 'default', 3: 'default'}

注意事项

  • 所有键共享同一个值对象(如果值是可变对象,会有问题)
  • 重复的键会被覆盖
  • 键必须是可哈希的

常见陷阱

# 错误:所有键共享同一个列表对象
d = dict.fromkeys(['a', 'b', 'c'], [])
d['a'].append(1)
print(d)  # {'a': [1], 'b': [1], 'c': [1]} - 所有键的值都变了!# 正确做法:使用字典推导式
d = {key: [] for key in ['a', 'b', 'c']}
d['a'].append(1)
print(d)  # {'a': [1], 'b': [], 'c': []}# 或者使用 copy 方法
import copy
d = dict.fromkeys(['a', 'b', 'c'], [])
for key in d:d[key] = copy.deepcopy(d[key])
d['a'].append(1)
print(d)  # {'a': [1], 'b': [], 'c': []}

高级用法

# 使用函数作为默认值
def create_list():return []d = dict.fromkeys(['a', 'b', 'c'], create_list())
# 注意:这样仍然有问题,因为函数只被调用一次# 正确的做法:使用字典推导式
d = {key: create_list() for key in ['a', 'b', 'c']}# 使用 lambda 表达式
d = {key: lambda: [] for key in ['a', 'b', 'c']}
# 注意:这样创建的是函数对象,不是列表

实际应用场景

# 1. 初始化计数器
counters = dict.fromkeys(['a', 'b', 'c'], 0)
print(counters)  # {'a': 0, 'b': 0, 'c': 0}# 2. 初始化标志位
flags = dict.fromkeys(['feature1', 'feature2', 'feature3'], False)
print(flags)  # {'feature1': False, 'feature2': False, 'feature3': False}# 3. 初始化配置
config = dict.fromkeys(['host', 'port', 'timeout'], None)
print(config)  # {'host': None, 'port': None, 'timeout': None}# 4. 字符频率统计初始化
char_count = dict.fromkeys('abcdefghijklmnopqrstuvwxyz', 0)
print(char_count)  # {'a': 0, 'b': 0, ..., 'z': 0}

与其他方法的对比

方法语法特点适用场景
fromkeys()dict.fromkeys(keys, value)所有键共享同一值初始化简单值
字典推导式{k: v for k in keys}每个键独立值初始化复杂值
setdefault()dict.setdefault(key, default)单个键设置默认值动态添加键值对

性能考虑

import time# 测试 fromkeys() 性能
keys = list(range(10000))start = time.time()
d1 = dict.fromkeys(keys, 0)
time1 = time.time() - startstart = time.time()
d2 = {key: 0 for key in keys}
time2 = time.time() - startprint(f"fromkeys() 时间:{time1:.6f}秒")
print(f"字典推导式时间:{time2:.6f}秒")
# fromkeys() 通常更快,因为它是 C 实现的

常见错误和解决方案

# 错误1:使用可变对象作为默认值
d = dict.fromkeys(['a', 'b'], [])
d['a'].append(1)
print(d)  # 所有键的值都变了# 解决方案1:使用字典推导式
d = {key: [] for key in ['a', 'b']}# 解决方案2:使用 copy 模块
import copy
d = dict.fromkeys(['a', 'b'], [])
for key in d:d[key] = copy.deepcopy(d[key])# 错误2:期望不同的默认值
d = dict.fromkeys(['a', 'b'], lambda: [])
# 这样创建的是函数对象,不是列表# 解决方案:使用字典推导式
d = {key: [] for key in ['a', 'b']}

最佳实践

  1. 使用不可变对象作为默认值:如数字、字符串、元组
  2. 使用字典推导式处理可变对象:如列表、字典、集合
  3. 注意键的重复:重复的键会被覆盖
  4. 考虑性能:对于大量键,fromkeys() 比字典推导式更快

python语法笔记之-range() 函数语法详解

基本语法

range(stop)                    # 从0开始,步长为1
range(start, stop)             # 从start开始,步长为1
range(start, stop, step)       # 从start开始,指定步长

参数说明

  • start:序列的起始值(可选,默认为0)
  • stop:序列的结束值(不包含)
  • step:步长(可选,默认为1)

返回值

  • 返回一个 range 对象,这是一个可迭代对象
  • 不是列表,但可以转换为列表

功能说明

  • range() 是 Python 的内置函数,用于生成一个不可变的数字序列
  • 内存效率高,不会立即生成所有数字
  • 支持负数步长

基本示例

# 基本用法
print(list(range(5)))          # [0, 1, 2, 3, 4]
print(list(range(1, 6)))       # [1, 2, 3, 4, 5]
print(list(range(0, 10, 2)))   # [0, 2, 4, 6, 8]# 负步长
print(list(range(5, 0, -1)))   # [5, 4, 3, 2, 1]
print(list(range(10, 0, -2)))  # [10, 8, 6, 4, 2]# 空序列
print(list(range(0)))          # []
print(list(range(1, 1)))       # []
print(list(range(5, 1)))       # []

常见用法

# 1. for 循环
for i in range(5):print(i, end=' ')  # 0 1 2 3 4# 2. 列表推导式
squares = [x**2 for x in range(5)]
print(squares)  # [0, 1, 4, 9, 16]# 3. 索引遍历
fruits = ['apple', 'banana', 'orange']
for i in range(len(fruits)):print(f"{i}: {fruits[i]}")# 4. 倒序遍历
for i in range(len(fruits)-1, -1, -1):print(f"{i}: {fruits[i]}")

高级用法

# 1. 生成等差数列
def arithmetic_sequence(start, end, step):return list(range(start, end + 1, step))print(arithmetic_sequence(1, 10, 2))  # [1, 3, 5, 7, 9]# 2. 生成几何数列
def geometric_sequence(start, ratio, count):return [start * (ratio ** i) for i in range(count)]print(geometric_sequence(1, 2, 5))  # [1, 2, 4, 8, 16]# 3. 矩阵索引
def create_matrix(rows, cols):matrix = []for i in range(rows):row = []for j in range(cols):row.append(i * cols + j)matrix.append(row)return matrixprint(create_matrix(3, 3))
# [[0, 1, 2], [3, 4, 5], [6, 7, 8]]# 4. 滑动窗口
def sliding_window(data, window_size):for i in range(len(data) - window_size + 1):yield data[i:i + window_size]data = [1, 2, 3, 4, 5]
for window in sliding_window(data, 3):print(window)
# [1, 2, 3]
# [2, 3, 4]
# [3, 4, 5]

性能特点

import sys# 内存效率对比
large_range = range(1000000)
large_list = list(range(1000000))print(f"range 对象大小:{sys.getsizeof(large_range)} 字节")
print(f"列表大小:{sys.getsizeof(large_list)} 字节")
# range 对象占用很少内存,而列表占用大量内存# 迭代效率
import timestart = time.time()
for i in range(1000000):pass
range_time = time.time() - startstart = time.time()
for i in list(range(1000000)):pass
list_time = time.time() - startprint(f"range 迭代时间:{range_time:.6f}秒")
print(f"列表迭代时间:{list_time:.6f}秒")
# range 迭代通常更快

实际应用场景

# 1. 计数器
for i in range(10):print(f"倒计时:{10-i}")# 2. 索引遍历
names = ['Alice', 'Bob', 'Charlie']
for i in range(len(names)):print(f"{i+1}. {names[i]}")# 3. 重复操作
def repeat_operation(func, times):for _ in range(times):func()# 4. 数值计算
def sum_range(start, end):return sum(range(start, end + 1))print(sum_range(1, 100))  # 5050# 5. 时间模拟
def simulate_time(hours):for hour in range(hours):for minute in range(60):for second in range(60):yield f"{hour:02d}:{minute:02d}:{second:02d}"# 使用示例(只显示前几个)
for time_str in simulate_time(1):print(time_str)break  # 避免输出太多

常见错误和注意事项

# 错误1:期望包含结束值
print(list(range(5)))  # [0, 1, 2, 3, 4] 不包含5# 错误2:负步长时的边界
print(list(range(5, 1)))  # [] 空序列,因为默认步长为1# 错误3:浮点数参数
# range(1.5, 5.5)  # TypeError: 'float' object cannot be interpreted as an integer# 正确做法:使用整数
print(list(range(1, 6)))  # [1, 2, 3, 4, 5]# 注意事项:range 对象不是列表
r = range(5)
print(type(r))  # <class 'range'>
print(r[2])     # 2 (可以索引)
print(r[1:3])   # range(1, 3) (可以切片)

与其他序列生成方法的对比

方法语法特点适用场景
range()range(start, stop, step)内存效率高,整数序列循环、索引
list()list(range())立即生成所有元素需要列表操作
enumerate()enumerate(iterable)同时获取索引和值遍历时需索引
itertools.count()count(start, step)无限序列无限循环

最佳实践

# 1. 使用 range 进行循环
for i in range(10):print(i)# 2. 使用 enumerate 获取索引和值
fruits = ['apple', 'banana', 'orange']
for i, fruit in enumerate(fruits):print(f"{i}: {fruit}")# 3. 使用 range 生成列表
squares = [x**2 for x in range(10)]# 4. 使用 range 进行倒序遍历
for i in range(len(fruits)-1, -1, -1):print(fruits[i])# 5. 使用 range 进行步长遍历
for i in range(0, 100, 10):print(i)  # 0, 10, 20, 30, ...

高级技巧

# 1. 自定义 range 类
class CustomRange:def __init__(self, start, stop, step=1):self.start = startself.stop = stopself.step = stepdef __iter__(self):current = self.startwhile current < self.stop:yield currentcurrent += self.step# 使用示例
for i in CustomRange(1, 10, 2):print(i)  # 1, 3, 5, 7, 9# 2. 生成器表达式
def fibonacci_range(n):a, b = 0, 1for _ in range(n):yield aa, b = b, a + bprint(list(fibonacci_range(10)))  # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]# 3. 条件 range
def conditional_range(start, stop, condition):for i in range(start, stop):if condition(i):yield i# 使用示例
even_numbers = list(conditional_range(1, 20, lambda x: x % 2 == 0))
print(even_numbers)  # [2, 4, 6, 8, 10, 12, 14, 16, 18]

python语法笔记之-字典 update() 方法语法详解

基本语法

dict.update([other])

参数说明

  • other:可以是字典、键值对的可迭代对象,或其他可迭代对象

返回值

  • 无返回值(返回 None),直接修改原字典

功能说明

  • update() 是字典的方法,用于更新字典的内容
  • 可以添加新的键值对或更新现有的键值对
  • 支持多种参数类型

基本示例

# 1. 使用字典更新
d1 = {'a': 1, 'b': 2}
d2 = {'c': 3, 'd': 4}
d1.update(d2)
print(d1)  # {'a': 1, 'b': 2, 'c': 3, 'd': 4}# 2. 更新现有键
d1.update({'a': 10, 'e': 5})
print(d1)  # {'a': 10, 'b': 2, 'c': 3, 'd': 4, 'e': 5}# 3. 使用键值对列表
d1.update([('f', 6), ('g', 7)])
print(d1)  # {'a': 10, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7}# 4. 使用关键字参数
d1.update(h=8, i=9)
print(d1)  # {'a': 10, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7, 'h': 8, 'i': 9}

不同参数类型的使用

# 1. 字典对象
config = {'host': 'localhost', 'port': 8080}
config.update({'timeout': 30, 'debug': True})
print(config)  # {'host': 'localhost', 'port': 8080, 'timeout': 30, 'debug': True}# 2. 键值对列表
user_info = {'name': 'Alice', 'age': 25}
user_info.update([('email', 'alice@example.com'), ('city', 'Beijing')])
print(user_info)  # {'name': 'Alice', 'age': 25, 'email': 'alice@example.com', 'city': 'Beijing'}# 3. 键值对元组
settings = {'theme': 'dark', 'language': 'en'}
settings.update((('font_size', 14), ('auto_save', True)))
print(settings)  # {'theme': 'dark', 'language': 'en', 'font_size': 14, 'auto_save': True}# 4. 关键字参数
profile = {'username': 'john_doe'}
profile.update(first_name='John', last_name='Doe', age=30)
print(profile)  # {'username': 'john_doe', 'first_name': 'John', 'last_name': 'Doe', 'age': 30}# 5. 混合使用
data = {'id': 1}
data.update({'status': 'active'}, created_at='2024-01-01', updated_at='2024-01-02')
print(data)  # {'id': 1, 'status': 'active', 'created_at': '2024-01-01', 'updated_at': '2024-01-02'}

实际应用场景

# 1. 配置管理
def load_config():base_config = {'host': 'localhost','port': 8080,'timeout': 30}# 从文件加载配置file_config = {'port': 9000,  # 覆盖默认端口'debug': True}# 从环境变量加载配置env_config = {'host': 'production.server.com','ssl': True}# 按优先级更新配置base_config.update(file_config)base_config.update(env_config)return base_configconfig = load_config()
print(config)  # {'host': 'production.server.com', 'port': 9000, 'timeout': 30, 'debug': True, 'ssl': True}# 2. 用户信息合并
def merge_user_profiles(profile1, profile2):"""合并两个用户配置文件"""merged = profile1.copy()  # 创建副本避免修改原字典merged.update(profile2)return mergedprofile1 = {'name': 'Alice', 'age': 25, 'email': 'alice@example.com'}
profile2 = {'age': 26, 'city': 'Beijing', 'phone': '123-456-7890'}merged_profile = merge_user_profiles(profile1, profile2)
print(merged_profile)  # {'name': 'Alice', 'age': 26, 'email': 'alice@example.com', 'city': 'Beijing', 'phone': '123-456-7890'}# 3. 数据库记录更新
def update_database_record(record_id, updates):"""更新数据库记录"""# 模拟从数据库获取记录record = {'id': record_id,'name': 'Product A','price': 100,'category': 'Electronics','created_at': '2024-01-01'}# 应用更新record.update(updates)record['updated_at'] = '2024-01-02'return recordupdates = {'price': 120, 'category': 'Gadgets', 'stock': 50}
updated_record = update_database_record(1, updates)
print(updated_record)# 4. API 响应处理
def process_api_response(base_response, additional_data):"""处理 API 响应数据"""response = base_response.copy()response.update(additional_data)return responsebase_response = {'status': 'success','code': 200,'message': 'Operation completed'
}additional_data = {'data': {'user_id': 123, 'username': 'john_doe'},'timestamp': '2024-01-01T12:00:00Z'
}final_response = process_api_response(base_response, additional_data)
print(final_response)

高级用法

# 1. 条件更新
def conditional_update(target_dict, source_dict, condition_func):"""根据条件更新字典"""for key, value in source_dict.items():if condition_func(key, value):target_dict[key] = valueconfig = {'debug': False, 'verbose': False, 'log_level': 'INFO'}
updates = {'debug': True, 'verbose': True, 'log_level': 'DEBUG', 'max_retries': 3}# 只更新布尔值
conditional_update(config, updates, lambda k, v: isinstance(v, bool))
print(config)  # {'debug': True, 'verbose': True, 'log_level': 'INFO'}# 2. 深度更新(简化版)
def deep_update(target, source):"""深度更新字典"""for key, value in source.items():if key in target and isinstance(target[key], dict) and isinstance(value, dict):deep_update(target[key], value)else:target[key] = valuenested_config = {'database': {'host': 'localhost','port': 3306},'cache': {'enabled': False}
}updates = {'database': {'host': 'production.db.com','ssl': True},'cache': {'enabled': True,'ttl': 3600}
}deep_update(nested_config, updates)
print(nested_config)# 3. 批量更新
def batch_update(target_dict, updates_list):"""批量更新字典"""for update_dict in updates_list:target_dict.update(update_dict)user_data = {'id': 1, 'name': 'Alice'}updates_batch = [{'email': 'alice@example.com'},{'age': 25},{'city': 'Beijing'},{'age': 26}  # 覆盖之前的年龄
]batch_update(user_data, updates_batch)
print(user_data)  # {'id': 1, 'name': 'Alice', 'email': 'alice@example.com', 'age': 26, 'city': 'Beijing'}

性能考虑

import time# 性能测试:update() vs 直接赋值
def test_update_performance():# 准备测试数据base_dict = {f'key_{i}': i for i in range(1000)}update_dict = {f'new_key_{i}': i for i in range(1000)}# 测试 update() 方法start = time.time()for _ in range(10000):test_dict = base_dict.copy()test_dict.update(update_dict)update_time = time.time() - start# 测试直接赋值start = time.time()for _ in range(10000):test_dict = base_dict.copy()for key, value in update_dict.items():test_dict[key] = valueassign_time = time.time() - startprint(f"update() 方法时间:{update_time:.6f}秒")print(f"直接赋值时间:{assign_time:.6f}秒")print(f"性能比:{assign_time/update_time:.2f}")test_update_performance()

常见错误和注意事项

# 错误1:期望返回值
d1 = {'a': 1}
result = d1.update({'b': 2})
print(result)  # None# 错误2:使用不可哈希的键
try:d1.update({[1, 2]: 'value'})  # TypeError: unhashable type: 'list'
except TypeError as e:print(f"错误:{e}")# 错误3:参数类型错误
try:d1.update(123)  # TypeError: 'int' object is not iterable
except TypeError as e:print(f"错误:{e}")# 注意事项1:update() 会修改原字典
original = {'a': 1}
copy_dict = original.copy()
copy_dict.update({'b': 2})
print(f"原字典:{original}")  # {'a': 1}
print(f"副本:{copy_dict}")   # {'a': 1, 'b': 2}# 注意事项2:重复键会被覆盖
d1 = {'a': 1, 'b': 2}
d1.update({'a': 10, 'c': 3})
print(d1)  # {'a': 10, 'b': 2, 'c': 3}

与其他方法的对比

方法语法特点适用场景
update()dict.update(other)批量更新,原地修改合并多个字典
dict()dict(**d1, **d2)创建新字典Python 3.5+
`` 操作符d1 | d2创建新字典
`=` 操作符d1 |= d2原地更新

最佳实践

# 1. 使用 copy() 避免修改原字典
def safe_update(base_dict, updates):"""安全更新字典,不修改原字典"""result = base_dict.copy()result.update(updates)return result# 2. 使用类型检查
def validate_update_dict(updates):"""验证更新字典的有效性"""if not isinstance(updates, dict):raise TypeError("更新数据必须是字典类型")for key, value in updates.items():if not isinstance(key, (str, int, float, bool, tuple)):raise TypeError(f"键 {key} 必须是可哈希类型")return True# 3. 使用默认值
def update_with_defaults(target_dict, updates, defaults=None):"""使用默认值更新字典"""if defaults is None:defaults = {}# 先应用默认值target_dict.update(defaults)# 再应用更新target_dict.update(updates)return target_dict# 使用示例
config = {'host': 'localhost'}
updates = {'port': 8080}
defaults = {'timeout': 30, 'retries': 3}final_config = update_with_defaults(config, updates, defaults)
print(final_config)  # {'host': 'localhost', 'timeout': 30, 'retries': 3, 'port': 8080}

python语法笔记之-正则表达式 groups 语法详解

问题代码

import restrs = 'Type:This is Python'
res = re.match('Type:(\w+) is (\w+)', strs)
print(res.groups())
print(res.group(1))
print(res.group(2))

输出结果

('This', 'Python')
This
Python

语法详解

1. 正则表达式模式分析
'Type:(\w+) is (\w+)'

模式分解:

  • Type: - 字面匹配字符串 “Type:”
  • (\w+) - 第一个捕获组:匹配一个或多个单词字符
  • is - 字面匹配字符串 " is "
  • (\w+) - 第二个捕获组:匹配一个或多个单词字符
2. groups() 方法详解

res.groups() 返回一个元组,包含所有捕获组的内容:

print(res.groups())  # ('This', 'Python')

特点:

  • 返回所有捕获组的值组成的元组
  • 不包含完整匹配的字符串
  • 按捕获组的顺序排列
3. group() 方法详解

res.group(n) 返回指定编号的捕获组:

print(res.group(0))  # 'Type:This is Python'  # 完整匹配
print(res.group(1))  # 'This'                  # 第一个捕获组
print(res.group(2))  # 'Python'                # 第二个捕获组

编号规则:

  • group(0) - 完整匹配的字符串
  • group(1) - 第一个捕获组
  • group(2) - 第二个捕获组
  • 以此类推…
4. 捕获组的概念

捕获组是用括号 () 包围的正则表达式部分:

# 示例1:基本捕获组
pattern = r'(\d{3})-(\d{3})-(\d{4})'
text = "123-456-7890"
match = re.match(pattern, text)
print(match.groups())  # ('123', '456', '7890')# 示例2:嵌套捕获组
pattern = r'(\w+(\d+))'
text = "abc123"
match = re.match(pattern, text)
print(match.groups())  # ('abc123', '123')
5. 实际应用示例

示例1:解析日志文件

import relog_line = "2024-01-01 10:30:45 [INFO] User login successful"
pattern = r'(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) \[(\w+)\] (.+)'match = re.match(pattern, log_line)
if match:date, time, level, message = match.groups()print(f"日期: {date}")print(f"时间: {time}")print(f"级别: {level}")print(f"消息: {message}")

示例2:解析邮箱地址

email = "user@example.com"
pattern = r'([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})'match = re.match(pattern, email)
if match:username, domain, tld = match.groups()print(f"用户名: {username}")print(f"域名: {domain}")print(f"顶级域名: {tld}")

示例3:解析配置文件

config_line = "database.host=localhost"
pattern = r'([^.]+)\.([^=]+)=(.+)'match = re.match(pattern, config_line)
if match:section, key, value = match.groups()print(f"节: {section}")print(f"键: {key}")print(f"值: {value}")
6. 命名捕获组

使用 (?P<name>pattern) 语法:

pattern = r'Type:(?P<first>\w+) is (?P<second>\w+)'
text = 'Type:This is Python'match = re.match(pattern, text)
if match:print(match.groups())           # ('This', 'Python')print(match.group('first'))     # 'This'print(match.group('second'))    # 'Python'print(match.groupdict())        # {'first': 'This', 'second': 'Python'}
7. 非捕获组

使用 (?:pattern) 语法:

# 普通捕获组
pattern1 = r'(\w+) is (\w+)'
text = "This is Python"
match1 = re.match(pattern1, text)
print(match1.groups())  # ('This', 'Python')# 非捕获组
pattern2 = r'(?:\w+) is (\w+)'
match2 = re.match(pattern2, text)
print(match2.groups())  # ('Python',) - 只有第二个组被捕获
8. 高级用法

示例1:条件匹配

# 匹配 "Type:xxx is yyy" 或 "Type:xxx are yyy"
pattern = r'Type:(\w+) (?:is|are) (\w+)'
text1 = "Type:This is Python"
text2 = "Type:These are examples"match1 = re.match(pattern, text1)
match2 = re.match(pattern, text2)print(match1.groups())  # ('This', 'Python')
print(match2.groups())  # ('These', 'examples')

示例2:重复捕获组

# 匹配多个数字组
pattern = r'(\d+)(?:,(\d+))*'
text = "1,2,3,4"match = re.match(pattern, text)
print(match.groups())  # ('1', '4') - 只捕获第一个和最后一个
9. 常见错误和注意事项

错误1:访问不存在的组

pattern = r'(\w+)'
text = "Hello"
match = re.match(pattern, text)try:print(match.group(2))  # IndexError: no such group
except IndexError as e:print(f"错误:{e}")

错误2:匹配失败时访问组

pattern = r'(\d+)'
text = "Hello"
match = re.match(pattern, text)if match:  # 总是检查匹配是否成功print(match.groups())
else:print("没有匹配")

注意事项:

# 1. groups() 返回元组,group() 返回字符串
match = re.match(r'(\w+)', "Hello")
print(type(match.groups()))  # <class 'tuple'>
print(type(match.group(1)))  # <class 'str'># 2. 空匹配的处理
pattern = r'(\w*)'
text = ""
match = re.match(pattern, text)
print(match.groups())  # ('',) - 空字符串
10. 性能优化建议
# 1. 编译正则表达式以提高性能
import repattern = re.compile(r'Type:(\w+) is (\w+)')
text = "Type:This is Python"match = pattern.match(text)  # 比 re.match(pattern, text) 更快
if match:print(match.groups())# 2. 使用 findall() 获取所有匹配
text = "Type:This is Python, Type:That is Java"
pattern = r'Type:(\w+) is (\w+)'matches = re.findall(pattern, text)
print(matches)  # [('This', 'Python'), ('That', 'Java')]
11. 实际应用场景

场景1:数据提取

# 从文本中提取价格信息
text = "商品价格: $99.99, 折扣价: $79.99"
pattern = r'\$(\d+\.\d+)'prices = re.findall(pattern, text)
print(f"找到的价格: {prices}")  # ['99.99', '79.99']

场景2:数据验证

# 验证电话号码格式
def validate_phone(phone):pattern = r'^(\d{3})-(\d{3})-(\d{4})$'match = re.match(pattern, phone)if match:area, prefix, line = match.groups()return True, f"区号: {area}, 前缀: {prefix}, 线路: {line}"return False, "格式错误"print(validate_phone("123-456-7890"))  # (True, '区号: 123, 前缀: 456, 线路: 7890')
print(validate_phone("123-456"))       # (False, '格式错误')

场景3:文本处理

# 解析日志文件
log_lines = ["2024-01-01 10:30:45 [INFO] User login successful","2024-01-01 10:31:12 [ERROR] Database connection failed","2024-01-01 10:32:00 [WARN] High memory usage detected"
]pattern = r'(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) \[(\w+)\] (.+)'for line in log_lines:match = re.match(pattern, line)if match:date, time, level, message = match.groups()print(f"[{level}] {message}")
12. 总结

正则表达式中的 groups 相关方法:

方法功能返回值
groups()返回所有捕获组元组
group(0)返回完整匹配字符串
group(n)返回第n个捕获组字符串
groupdict()返回命名捕获组字典

关键要点:

  1. 捕获组用括号 () 定义
  2. groups() 返回所有捕获组的元组
  3. group(n) 返回指定编号的捕获组
  4. 编号从1开始,0表示完整匹配
  5. 总是检查匹配是否成功再访问组

python语法笔记之-原始字符串(Raw String)语法详解

问题代码

print r"\nwoow"

输出结果

\nwoow

语法详解

1. 原始字符串的概念

原始字符串(Raw String) 是 Python 中的一种字符串字面量,使用前缀 rR 表示。在原始字符串中,反斜杠 \ 不会被转义,而是作为普通字符处理。

2. 代码执行分析
print r"\nwoow"  # 输出:\nwoow
print "\nwoow"   # 输出:换行 + woow

对比分析:

  • r"\nwoow" - 原始字符串,\n 被当作两个字符 \n
  • "\nwoow" - 普通字符串,\n 被转义为换行符
3. 转义字符对比
转义序列普通字符串原始字符串说明
\n换行符\n换行
\t制表符\t制表符
\r回车符\r回车
\\\\\反斜杠
\""\"双引号
4. 实际应用示例

示例1:文件路径

# 普通字符串 - 需要双反斜杠
path1 = "C:\\Users\\Documents\\file.txt"
print(path1)  # C:\Users\Documents\file.txt# 原始字符串 - 更简洁
path2 = r"C:\Users\Documents\file.txt"
print(path2)  # C:\Users\Documents\file.txt

示例2:正则表达式

import re# 普通字符串 - 需要转义
pattern1 = "\\d+\\s+\\w+"
text = "123  abc"
match1 = re.search(pattern1, text)# 原始字符串 - 更清晰
pattern2 = r"\d+\s+\w+"
match2 = re.search(pattern2, text)print(match1.group() if match1 else "无匹配")  # 123  abc
print(match2.group() if match2 else "无匹配")  # 123  abc

示例3:Windows 路径处理

# 处理 Windows 路径
windows_path = r"C:\Program Files\Python\Scripts"
print(windows_path)  # C:\Program Files\Python\Scripts# 分割路径
path_parts = windows_path.split('\\')
print(path_parts)  # ['C:', 'Program Files', 'Python', 'Scripts']
5. 高级用法

示例1:多行原始字符串

# 多行原始字符串
multiline_raw = r"""
这是一个多行
原始字符串
包含 \n \t \r 等字符
"""
print(multiline_raw)

示例2:正则表达式中的复杂模式

import re# 复杂的正则表达式
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
email = "user@example.com"if re.match(email_pattern, email):print("有效的邮箱地址")
else:print("无效的邮箱地址")

示例3:SQL 查询字符串

# SQL 查询
sql_query = r"""
SELECT name, age, city 
FROM users 
WHERE age > 18 AND city = 'Beijing'
"""
print(sql_query)
6. 常见错误和注意事项

错误1:在原始字符串中使用引号

# 错误:原始字符串中的引号问题
try:print(r"这是一个"问题"的字符串")  # SyntaxError
except SyntaxError as e:print(f"语法错误:{e}")# 正确:使用不同类型的引号
print(r'这是一个"正确"的字符串')  # 这是一个"正确"的字符串
print(r"这是一个'正确'的字符串")  # 这是一个'正确'的字符串

错误2:原始字符串末尾的反斜杠

# 错误:原始字符串末尾的反斜杠
try:print(r"C:\Users\")  # SyntaxError
except SyntaxError as e:print(f"语法错误:{e}")# 正确:使用字符串连接或转义
print(r"C:\Users" + "\\")  # C:\Users\
print(r"C:\Users\\")       # C:\Users\

注意事项:

# 1. 原始字符串中的反斜杠数量
print(r"\\")  # \\
print("\\\\")  # \\# 2. 原始字符串中的其他转义序列
print(r"\x41")  # \x41 (不是字符 'A')
print("\x41")   # A# 3. 原始字符串中的 Unicode 转义
print(r"\u0041")  # \u0041 (不是字符 'A')
print("\u0041")   # A
7. 实际应用场景

场景1:配置文件路径

# 配置文件路径
config_path = r"C:\App\config\settings.ini"
backup_path = r"C:\App\backup\settings_backup.ini"print(f"配置文件:{config_path}")
print(f"备份文件:{backup_path}")

场景2:日志文件路径

import os
from datetime import datetime# 日志文件路径
log_dir = r"C:\Logs\Application"
log_file = os.path.join(log_dir, f"app_{datetime.now().strftime('%Y%m%d')}.log")print(f"日志文件:{log_file}")

场景3:网络路径

# 网络共享路径
network_path = r"\\server\share\documents"
unc_path = r"\\192.168.1.100\public\files"print(f"网络路径:{network_path}")
print(f"UNC路径:{unc_path}")

场景4:正则表达式模式

import re# 复杂的正则表达式模式
phone_pattern = r'^(\+?1)?[-.\s]?\(?([0-9]{3})\)?[-.\s]?([0-9]{3})[-.\s]?([0-9]{4})$'
phone_numbers = ["123-456-7890","(123) 456-7890","123.456.7890","+1-123-456-7890"
]for phone in phone_numbers:if re.match(phone_pattern, phone):print(f"有效号码:{phone}")else:print(f"无效号码:{phone}")
8. 性能考虑
import time# 性能测试:原始字符串 vs 普通字符串
def test_raw_string_performance():# 测试原始字符串start = time.time()for _ in range(1000000):path = r"C:\Users\Documents\file.txt"raw_time = time.time() - start# 测试普通字符串start = time.time()for _ in range(1000000):path = "C:\\Users\\Documents\\file.txt"normal_time = time.time() - startprint(f"原始字符串时间:{raw_time:.6f}秒")print(f"普通字符串时间:{normal_time:.6f}秒")print(f"性能差异:{normal_time/raw_time:.2f}倍")test_raw_string_performance()
9. 最佳实践
# 1. 文件路径使用原始字符串
file_path = r"C:\Users\Documents\file.txt"# 2. 正则表达式使用原始字符串
import re
pattern = r"\d{3}-\d{3}-\d{4}"# 3. 多行字符串使用原始字符串
sql_query = r"""
SELECT * FROM users 
WHERE age > 18 
ORDER BY name
"""# 4. 包含大量反斜杠的字符串使用原始字符串
windows_command = r"cmd /c dir C:\Users\*.*"# 5. 避免在原始字符串末尾使用反斜杠
# 错误:path = r"C:\Users\"
# 正确:path = r"C:\Users" + "\\"
10. 与其他字符串类型的对比
字符串类型前缀特点适用场景
普通字符串支持转义字符一般文本
原始字符串rR不转义反斜杠文件路径、正则表达式
字节字符串bB字节序列二进制数据
Unicode字符串uUUnicode字符国际化文本
11. 总结

原始字符串的优势:

  1. 简化路径表示:不需要双反斜杠
  2. 提高可读性:正则表达式更清晰
  3. 减少错误:避免转义字符错误
  4. 提高性能:解析速度更快

使用建议:

  1. 文件路径和目录路径
  2. 正则表达式模式
  3. 包含大量反斜杠的字符串
  4. 多行字符串
  5. 网络路径和 UNC 路径

注意事项:

  1. 原始字符串中的引号需要配对
  2. 末尾反斜杠需要特殊处理
  3. 某些转义序列在原始字符串中不起作用

python语法笔记之-浅拷贝(Shallow Copy)语法详解

问题代码

a = [1, [2, 3], 4]
b = a[:]
a[0] = 5
a[1][1] = 6

执行结果分析

print(f"a = {a}")  # a = [5, [2, 6], 4]
print(f"b = {b}")  # b = [1, [2, 6], 4]

语法详解

1. 浅拷贝的概念

浅拷贝(Shallow Copy) 是创建一个新对象,但它包含的是对原始对象中元素的引用。对于嵌套的可变对象,浅拷贝只复制引用,不复制对象本身。

2. 代码执行过程分析
# 步骤1:创建原始列表
a = [1, [2, 3], 4]
# a 包含:整数1,列表[2,3]的引用,整数4# 步骤2:浅拷贝
b = a[:]  # 等价于 b = a.copy() 或 b = list(a)
# b 包含:整数1的副本,列表[2,3]的引用,整数4的副本# 步骤3:修改不可变元素
a[0] = 5
# a 变成 [5, [2, 3], 4]
# b 仍然是 [1, [2, 3], 4] - 不受影响# 步骤4:修改嵌套的可变元素
a[1][1] = 6
# a 变成 [5, [2, 6], 4]
# b 变成 [1, [2, 6], 4] - 受影响!
3. 内存结构分析

浅拷贝前:

a → [1, [2, 3], 4]

浅拷贝后:

a → [1, [2, 3], 4]
b → [1, [2, 3], 4]  # 新列表,但包含对相同嵌套对象的引用

修改后:

a → [5, [2, 6], 4]  # 修改了第一个元素和嵌套列表
b → [1, [2, 6], 4]  # 第一个元素不变,但嵌套列表被共享修改
4. 不同拷贝方式的对比
import copy# 原始列表
original = [1, [2, 3], 4]# 1. 浅拷贝 - 切片操作
shallow1 = original[:]# 2. 浅拷贝 - copy() 方法
shallow2 = original.copy()# 3. 浅拷贝 - list() 构造函数
shallow3 = list(original)# 4. 浅拷贝 - copy.copy()
shallow4 = copy.copy(original)# 5. 深拷贝 - copy.deepcopy()
deep = copy.deepcopy(original)# 测试修改
original[0] = 10
original[1][0] = 20print(f"原始列表: {original}")    # [10, [20, 3], 4]
print(f"浅拷贝1: {shallow1}")     # [1, [20, 3], 4]
print(f"浅拷贝2: {shallow2}")     # [1, [20, 3], 4]
print(f"浅拷贝3: {shallow3}")     # [1, [20, 3], 4]
print(f"浅拷贝4: {shallow4}")     # [1, [20, 3], 4]
print(f"深拷贝: {deep}")          # [1, [2, 3], 4] - 完全独立
5. 实际应用示例

示例1:配置管理

# 默认配置
default_config = {'host': 'localhost','port': 8080,'database': {'name': 'mydb','user': 'admin'}
}# 创建环境特定配置(浅拷贝)
dev_config = default_config.copy()
dev_config['port'] = 3000
dev_config['database']['user'] = 'dev_user'print(f"默认配置: {default_config}")
print(f"开发配置: {dev_config}")
# 注意:database 配置被共享修改了!

示例2:游戏状态管理

# 游戏状态
game_state = {'player': {'health': 100, 'position': [10, 20]},'enemies': [{'health': 50, 'position': [5, 15]}],'score': 0
}# 保存游戏状态(浅拷贝)
saved_state = game_state.copy()# 修改当前状态
game_state['score'] = 100
game_state['player']['health'] = 80
game_state['enemies'][0]['health'] = 30print(f"当前状态: {game_state}")
print(f"保存状态: {saved_state}")
# 注意:嵌套对象被共享修改了!

示例3:列表操作

# 学生成绩列表
students = [{'name': 'Alice', 'grades': [85, 90, 88]},{'name': 'Bob', 'grades': [92, 87, 91]},{'name': 'Charlie', 'grades': [78, 85, 82]}
]# 创建备份(浅拷贝)
backup = students[:]# 修改原始数据
students[0]['name'] = 'Alice Smith'
students[1]['grades'][0] = 95print("原始数据:")
for student in students:print(f"  {student['name']}: {student['grades']}")print("备份数据:")
for student in backup:print(f"  {student['name']}: {student['grades']}")
# 注意:grades 列表被共享修改了!
6. 深拷贝 vs 浅拷贝
import copy# 复杂嵌套结构
nested_data = {'numbers': [1, 2, 3],'strings': ['a', 'b', 'c'],'nested': {'list': [10, 20, 30],'dict': {'x': 100, 'y': 200}}
}# 浅拷贝
shallow = nested_data.copy()# 深拷贝
deep = copy.deepcopy(nested_data)# 修改原始数据
nested_data['numbers'][0] = 999
nested_data['nested']['list'][0] = 888
nested_data['nested']['dict']['x'] = 777print("原始数据:")
print(f"  numbers: {nested_data['numbers']}")
print(f"  nested.list: {nested_data['nested']['list']}")
print(f"  nested.dict: {nested_data['nested']['dict']}")print("浅拷贝:")
print(f"  numbers: {shallow['numbers']}")
print(f"  nested.list: {shallow['nested']['list']}")
print(f"  nested.dict: {shallow['nested']['dict']}")print("深拷贝:")
print(f"  numbers: {deep['numbers']}")
print(f"  nested.list: {deep['nested']['list']}")
print(f"  nested.dict: {deep['nested']['dict']}")
7. 常见错误和注意事项

错误1:误以为浅拷贝是完全独立的

# 错误理解
a = [1, [2, 3], 4]
b = a[:]
a[1][0] = 999
print(f"a: {a}")  # [1, [999, 3], 4]
print(f"b: {b}")  # [1, [999, 3], 4] - 意外被修改!

错误2:嵌套列表的浅拷贝陷阱

# 嵌套列表
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
copy_matrix = matrix[:]# 修改一行
copy_matrix[0][0] = 999print("原始矩阵:")
for row in matrix:print(row)print("拷贝矩阵:")
for row in copy_matrix:print(row)
# 两个矩阵都被修改了!

注意事项:

# 1. 不可变对象不受影响
a = [1, "hello", (2, 3)]
b = a[:]
a[0] = 999
a[1] = "world"
# a[2] = (4, 5)  # 元组不可变,不能修改print(f"a: {a}")  # [999, 'world', (2, 3)]
print(f"b: {b}")  # [1, 'hello', (2, 3)] - 不受影响# 2. 可变对象被共享
a = [1, [2, 3], {'x': 10}]
b = a[:]
a[1].append(4)
a[2]['y'] = 20print(f"a: {a}")  # [1, [2, 3, 4], {'x': 10, 'y': 20}]
print(f"b: {b}")  # [1, [2, 3, 4], {'x': 10, 'y': 20}] - 受影响!
8. 性能考虑
import time
import copy# 创建大型嵌套结构
large_data = {'list': list(range(10000)),'nested': {'data': list(range(1000)),'more_data': list(range(1000))}
}# 测试浅拷贝性能
start = time.time()
shallow_copy = large_data.copy()
shallow_time = time.time() - start# 测试深拷贝性能
start = time.time()
deep_copy = copy.deepcopy(large_data)
deep_time = time.time() - startprint(f"浅拷贝时间: {shallow_time:.6f}秒")
print(f"深拷贝时间: {deep_time:.6f}秒")
print(f"性能差异: {deep_time/shallow_time:.2f}倍")
# 深拷贝通常比浅拷贝慢很多
9. 最佳实践
import copy# 1. 明确选择拷贝类型
def create_backup(data, deep=False):"""创建数据备份"""if deep:return copy.deepcopy(data)else:return data.copy()# 2. 处理嵌套结构
def safe_copy_nested_list(original):"""安全拷贝嵌套列表"""if not original:return []result = []for item in original:if isinstance(item, list):result.append(safe_copy_nested_list(item))else:result.append(item)return result# 3. 使用深拷贝避免意外修改
def update_config(base_config, updates):"""更新配置,避免修改原始配置"""config = copy.deepcopy(base_config)config.update(updates)return config# 使用示例
base_config = {'host': 'localhost', 'database': {'name': 'mydb'}}
updates = {'port': 8080, 'database': {'user': 'admin'}}new_config = update_config(base_config, updates)
print(f"原始配置: {base_config}")
print(f"新配置: {new_config}")
10. 实际应用场景

场景1:数据备份

# 用户数据
user_data = {'profile': {'name': 'Alice', 'age': 25},'preferences': {'theme': 'dark', 'language': 'en'},'history': ['page1', 'page2', 'page3']
}# 创建备份
backup = user_data.copy()# 修改原始数据
user_data['profile']['age'] = 26
user_data['history'].append('page4')print("原始数据:")
print(f"  年龄: {user_data['profile']['age']}")
print(f"  历史: {user_data['history']}")print("备份数据:")
print(f"  年龄: {backup['profile']['age']}")
print(f"  历史: {backup['history']}")

场景2:模板系统

# 邮件模板
email_template = {'subject': 'Welcome','body': 'Hello {name}, welcome to our service!','attachments': [],'settings': {'priority': 'normal', 'format': 'html'}
}# 创建个性化邮件
def create_personalized_email(template, name):email = template.copy()  # 浅拷贝email['body'] = email['body'].format(name=name)email['attachments'].append(f'{name}_welcome.pdf')return email# 使用模板
alice_email = create_personalized_email(email_template, 'Alice')
bob_email = create_personalized_email(email_template, 'Bob')print("Alice邮件:", alice_email)
print("Bob邮件:", bob_email)
print("原始模板:", email_template)

场景3:游戏状态管理

# 游戏状态
class GameState:def __init__(self):self.players = [{'health': 100, 'position': [0, 0]}]self.enemies = [{'health': 50, 'position': [10, 10]}]self.score = 0def save_state(self):"""保存游戏状态"""return {'players': self.players.copy(),'enemies': self.enemies.copy(),'score': self.score}def load_state(self, saved_state):"""加载游戏状态"""self.players = saved_state['players']self.enemies = saved_state['enemies']self.score = saved_state['score']# 使用示例
game = GameState()
saved = game.save_state()# 修改游戏状态
game.players[0]['health'] = 80
game.enemies[0]['position'][0] = 15print("当前状态:", game.players, game.enemies)
print("保存状态:", saved['players'], saved['enemies'])
11. 总结

浅拷贝的特点:

  1. 创建新对象:外层容器是新的
  2. 共享嵌套对象:嵌套的可变对象被共享
  3. 性能较好:比深拷贝快
  4. 内存节省:不复制嵌套对象

使用场景:

  1. 需要独立的外层容器
  2. 嵌套对象可以共享
  3. 性能要求较高
  4. 内存使用有限制

注意事项:

  1. 嵌套的可变对象会被共享修改
  2. 不可变对象不受影响
  3. 需要深拷贝时使用 copy.deepcopy()
  4. 理解数据结构的可变性

python语法笔记之-解包操作符(*)语法详解

问题代码

def fn(a, b):return a + blst = [1, 2]
f = fn(*lst)
print(f)

输出结果

3

语法详解

1. 解包操作符的概念

解包操作符(Unpacking Operator) * 用于将可迭代对象(如列表、元组)展开为独立的参数传递给函数。

2. 代码执行过程分析
def fn(a, b):return a + blst = [1, 2]
f = fn(*lst)  # 等价于 fn(1, 2)
print(f)      # 输出:3

执行步骤:

  1. 定义函数 fn(a, b),接受两个参数
  2. 创建列表 lst = [1, 2]
  3. 使用 *lst 将列表解包为独立参数
  4. 函数调用变为 fn(1, 2)
  5. 返回 1 + 2 = 3
3. 解包操作符的用法

基本用法:

# 1. 函数参数解包
def add(a, b, c):return a + b + cnumbers = [1, 2, 3]
result = add(*numbers)  # 等价于 add(1, 2, 3)
print(result)  # 6# 2. 列表解包
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = [*list1, *list2]  # [1, 2, 3, 4, 5, 6]
print(combined)# 3. 元组解包
point = (10, 20)
x, y = point  # 解包赋值
print(f"x: {x}, y: {y}")  # x: 10, y: 20
4. 实际应用示例

示例1:可变参数函数

def calculate_sum(*args):return sum(args)# 使用解包操作符
numbers = [1, 2, 3, 4, 5]
result = calculate_sum(*numbers)
print(result)  # 15# 等价于
result = calculate_sum(1, 2, 3, 4, 5)
print(result)  # 15

示例2:字典解包

def print_info(name, age, city):print(f"姓名: {name}, 年龄: {age}, 城市: {city}")# 使用字典解包
person = {'name': 'Alice', 'age': 25, 'city': 'Beijing'}
print_info(**person)  # 姓名: Alice, 年龄: 25, 城市: Beijing# 等价于
print_info(name='Alice', age=25, city='Beijing')

示例3:列表合并

# 合并多个列表
list1 = [1, 2, 3]
list2 = [4, 5, 6]
list3 = [7, 8, 9]# 使用解包操作符
merged = [*list1, *list2, *list3]
print(merged)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]# 等价于
merged = list1 + list2 + list3
print(merged)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]
5. 高级用法

示例1:函数装饰器

def log_function_call(func):def wrapper(*args, **kwargs):print(f"调用函数: {func.__name__}")print(f"参数: {args}, {kwargs}")result = func(*args, **kwargs)print(f"返回值: {result}")return resultreturn wrapper@log_function_call
def add_numbers(a, b, c):return a + b + c# 使用解包操作符
numbers = [1, 2, 3]
result = add_numbers(*numbers)

示例2:类方法调用

class Point:def __init__(self, x, y):self.x = xself.y = ydef distance_to(self, other):return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5# 创建点对象
p1 = Point(0, 0)
coords = [3, 4]
p2 = Point(*coords)  # 等价于 Point(3, 4)distance = p1.distance_to(p2)
print(f"距离: {distance}")  # 5.0

示例3:数据转换

# 将字符串转换为整数列表
number_strings = ['1', '2', '3', '4', '5']
numbers = [int(x) for x in number_strings]# 使用解包操作符计算最大值
max_value = max(*numbers)
print(f"最大值: {max_value}")  # 5# 使用解包操作符计算最小值
min_value = min(*numbers)
print(f"最小值: {min_value}")  # 1
6. 常见错误和注意事项

错误1:参数数量不匹配

def fn(a, b, c):return a + b + clst = [1, 2]  # 只有2个元素
try:result = fn(*lst)  # TypeError: fn() missing 1 required positional argument: 'c'
except TypeError as e:print(f"错误:{e}")

错误2:解包空列表

def fn(a, b):return a + bempty_list = []
try:result = fn(*empty_list)  # TypeError: fn() missing 2 required positional arguments: 'a' and 'b'
except TypeError as e:print(f"错误:{e}")

注意事项:

# 1. 解包操作符只能用于可迭代对象
try:result = fn(*123)  # TypeError: 'int' object is not iterable
except TypeError as e:print(f"错误:{e}")# 2. 解包操作符的位置很重要
def fn(a, b, c):return a + b + cnumbers = [1, 2, 3]
result = fn(*numbers)  # 正确
print(result)  # 6# 3. 可以与普通参数混合使用
def fn(a, b, c, d):return a + b + c + dnumbers = [1, 2]
result = fn(*numbers, 3, 4)  # 解包 + 普通参数
print(result)  # 10
7. 性能考虑
import time# 性能测试:解包操作符 vs 手动传递参数
def test_function(a, b, c, d, e):return a + b + c + d + e# 准备测试数据
numbers = [1, 2, 3, 4, 5]# 测试解包操作符
start = time.time()
for _ in range(1000000):result = test_function(*numbers)
unpack_time = time.time() - start# 测试手动传递参数
start = time.time()
for _ in range(1000000):result = test_function(1, 2, 3, 4, 5)
manual_time = time.time() - startprint(f"解包操作符时间: {unpack_time:.6f}秒")
print(f"手动传递时间: {manual_time:.6f}秒")
print(f"性能差异: {unpack_time/manual_time:.2f}倍")
8. 实际应用场景

场景1:数据处理

# 处理CSV数据
csv_data = [['Alice', '25', 'Beijing'],['Bob', '30', 'Shanghai'],['Charlie', '35', 'Guangzhou']
]def process_person(name, age, city):return f"{name} ({age}岁) 来自 {city}"# 使用解包操作符处理每一行
for row in csv_data:person_info = process_person(*row)print(person_info)

场景2:配置管理

# 数据库配置
db_config = {'host': 'localhost','port': 3306,'database': 'mydb','username': 'admin','password': 'password'
}def connect_database(host, port, database, username, password):return f"连接到 {database}{host}:{port} 使用 {username}"# 使用字典解包
connection_string = connect_database(**db_config)
print(connection_string)

场景3:数学计算

import math# 计算点到原点的距离
def distance_to_origin(x, y, z=0):return math.sqrt(x**2 + y**2 + z**2)# 2D点
point_2d = [3, 4]
distance_2d = distance_to_origin(*point_2d)
print(f"2D距离: {distance_2d}")  # 5.0# 3D点
point_3d = [3, 4, 5]
distance_3d = distance_to_origin(*point_3d)
print(f"3D距离: {distance_3d}")  # 7.0710678118654755
9. 与其他解包方式的对比
# 1. 列表解包
numbers = [1, 2, 3, 4, 5]
first, *middle, last = numbers
print(f"第一个: {first}")    # 1
print(f"中间: {middle}")     # [2, 3, 4]
print(f"最后一个: {last}")   # 5# 2. 字典解包
dict1 = {'a': 1, 'b': 2}
dict2 = {'c': 3, 'd': 4}
merged = {**dict1, **dict2}
print(merged)  # {'a': 1, 'b': 2, 'c': 3, 'd': 4}# 3. 字符串解包
word = "Hello"
letters = [*word]
print(letters)  # ['H', 'e', 'l', 'l', 'o']
10. 最佳实践
# 1. 使用解包操作符简化函数调用
def process_data(name, age, email, phone=None):return f"处理 {name} ({age}岁) 的数据,邮箱: {email}"# 从数据库获取的数据
user_data = ['Alice', 25, 'alice@example.com']# 使用解包操作符
result = process_data(*user_data)
print(result)# 2. 合并多个列表
def combine_lists(*lists):return [item for sublist in lists for item in sublist]list1 = [1, 2, 3]
list2 = [4, 5, 6]
list3 = [7, 8, 9]combined = combine_lists(list1, list2, list3)
print(combined)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]# 3. 动态函数调用
def dynamic_call(func, args):return func(*args)def add(a, b):return a + bdef multiply(a, b, c):return a * b * c# 动态调用不同函数
result1 = dynamic_call(add, [1, 2])
result2 = dynamic_call(multiply, [2, 3, 4])print(f"加法结果: {result1}")      # 3
print(f"乘法结果: {result2}")      # 24
11. 总结

解包操作符的优势:

  1. 简化代码:减少重复的参数传递
  2. 提高可读性:代码更简洁清晰
  3. 灵活性:支持动态参数传递
  4. 性能良好:与手动传递参数性能相近

使用场景:

  1. 函数参数传递
  2. 列表和字典合并
  3. 数据转换和处理
  4. 动态函数调用
  5. 配置管理

注意事项:

  1. 参数数量必须匹配
  2. 只能用于可迭代对象
  3. 解包操作符的位置很重要
  4. 可以与普通参数混合使用

python语法笔记之-字典和集合语法详解

问题代码

dicts = {}
dicts[(1, 2)] = ({3, (4, 5)})
print(dicts)

输出结果

{(1, 2): {3, (4, 5)}}

语法详解

1. 代码结构分析
dicts = {}                    # 创建空字典
dicts[(1, 2)] = ({3, (4, 5)})  # 添加键值对
print(dicts)                  # 输出字典内容

组成部分:

  • 键(Key)(1, 2) - 一个元组
  • 值(Value){3, (4, 5)} - 一个集合,包含整数3和元组(4, 5)
2. 数据类型详解

键的类型 - 元组:

key = (1, 2)
print(type(key))  # <class 'tuple'>
print(key)        # (1, 2)

值的类型 - 集合:

value = {3, (4, 5)}
print(type(value))  # <class 'set'>
print(value)        # {3, (4, 5)}
3. 字典键的要求

可哈希性(Hashable):

# 可哈希的类型(可以作为字典键)
valid_keys = {(1, 2): "元组","string": "字符串",123: "整数",3.14: "浮点数",True: "布尔值",None: "None值"
}# 不可哈希的类型(不能作为字典键)
try:invalid_dict = {[1, 2]: "列表",  # TypeError: unhashable type: 'list'{1, 2}: "集合",  # TypeError: unhashable type: 'set'{1: 2}: "字典"   # TypeError: unhashable type: 'dict'}
except TypeError as e:print(f"错误:{e}")
4. 集合的特点

无序性和唯一性:

# 集合的特点
set_example = {1, 2, 2, 3, 3, 3}  # 重复元素会被自动去除
print(set_example)  # {1, 2, 3}# 集合可以包含不同类型的元素
mixed_set = {1, "hello", (1, 2), 3.14}
print(mixed_set)  # {1, 3.14, 'hello', (1, 2)}
5. 实际应用示例

示例1:坐标映射

# 使用坐标作为键,存储相关信息
coordinate_data = {}# 添加坐标信息
coordinate_data[(0, 0)] = {"type": "origin", "visited": True}
coordinate_data[(1, 1)] = {"type": "point", "visited": False}
coordinate_data[(2, 3)] = {"type": "target", "visited": False}print(coordinate_data)
# {(0, 0): {'type': 'origin', 'visited': True}, 
#  (1, 1): {'type': 'point', 'visited': False}, 
#  (2, 3): {'type': 'target', 'visited': False}}

示例2:学生成绩管理

# 使用学生ID和课程作为键
student_scores = {}# 添加学生成绩
student_scores[("Alice", "Math")] = {85, 90, 88}
student_scores[("Bob", "English")] = {92, 87, 91}
student_scores[("Charlie", "Science")] = {78, 85, 82}print(student_scores)
# {('Alice', 'Math'): {88, 85, 90}, 
#  ('Bob', 'English'): {87, 91, 92}, 
#  ('Charlie', 'Science'): {82, 85, 78}}

示例3:游戏状态管理

# 游戏中的位置和状态
game_state = {}# 添加游戏位置信息
game_state[(10, 20)] = {"player", "enemy", "item"}
game_state[(15, 25)] = {"wall", "door"}
game_state[(5, 10)] = {"treasure", "trap"}print(game_state)
# {(10, 20): {'enemy', 'item', 'player'}, 
#  (15, 25): {'door', 'wall'}, 
#  (5, 10): {'trap', 'treasure'}}
6. 高级用法

示例1:嵌套数据结构

# 复杂的嵌套结构
complex_dict = {}# 添加复杂数据
complex_dict[(1, 2, 3)] = {"numbers": {1, 2, 3, 4, 5},"strings": {"hello", "world"},"tuples": {(1, 2), (3, 4), (5, 6)}
}print(complex_dict)
# {(1, 2, 3): {'numbers': {1, 2, 3, 4, 5}, 
#              'strings': {'hello', 'world'}, 
#              'tuples': {(1, 2), (3, 4), (5, 6)}}}

示例2:函数参数缓存

# 使用函数参数作为缓存键
function_cache = {}def expensive_function(a, b, c):# 检查缓存key = (a, b, c)if key in function_cache:return function_cache[key]# 模拟复杂计算result = a * b + cfunction_cache[key] = resultreturn result# 测试缓存
print(expensive_function(1, 2, 3))  # 5
print(expensive_function(1, 2, 3))  # 5 (从缓存获取)
print(function_cache)  # {(1, 2, 3): 5}

示例3:图数据结构

# 图的邻接表表示
graph = {}# 添加图的边
graph[(0, 1)] = {"weight": 5, "type": "road"}
graph[(1, 2)] = {"weight": 3, "type": "bridge"}
graph[(2, 0)] = {"weight": 7, "type": "tunnel"}print(graph)
# {(0, 1): {'weight': 5, 'type': 'road'}, 
#  (1, 2): {'weight': 3, 'type': 'bridge'}, 
#  (2, 0): {'weight': 7, 'type': 'tunnel'}}
7. 常见错误和注意事项

错误1:使用不可哈希类型作为键

try:invalid_dict = {}invalid_dict[[1, 2]] = "value"  # TypeError: unhashable type: 'list'
except TypeError as e:print(f"错误:{e}")

错误2:集合中的不可哈希元素

try:invalid_set = {1, [2, 3]}  # TypeError: unhashable type: 'list'
except TypeError as e:print(f"错误:{e}")

注意事项:

# 1. 元组作为键时,元组内的元素也必须是可哈希的
valid_tuple_key = (1, 2, "hello")  # 正确
try:invalid_tuple_key = (1, [2, 3])  # 错误:列表不可哈希dict_with_invalid_key = {invalid_tuple_key: "value"}
except TypeError as e:print(f"错误:{e}")# 2. 集合是无序的
set1 = {1, 2, 3}
set2 = {3, 1, 2}
print(set1 == set2)  # True# 3. 字典键的唯一性
test_dict = {}
test_dict[(1, 2)] = "first"
test_dict[(1, 2)] = "second"  # 覆盖前一个值
print(test_dict)  # {(1, 2): 'second'}
8. 性能考虑
import time# 性能测试:元组键 vs 字符串键
def test_dict_performance():# 测试元组键tuple_dict = {}start = time.time()for i in range(10000):tuple_dict[(i, i+1)] = ituple_time = time.time() - start# 测试字符串键string_dict = {}start = time.time()for i in range(10000):string_dict[f"{i}_{i+1}"] = istring_time = time.time() - startprint(f"元组键时间: {tuple_time:.6f}秒")print(f"字符串键时间: {string_time:.6f}秒")print(f"性能差异: {tuple_time/string_time:.2f}倍")test_dict_performance()
9. 实际应用场景

场景1:数据库查询结果缓存

# 缓存数据库查询结果
query_cache = {}def cached_query(table, conditions):# 创建缓存键cache_key = (table, tuple(sorted(conditions.items())))# 检查缓存if cache_key in query_cache:print("从缓存获取结果")return query_cache[cache_key]# 模拟数据库查询print("执行数据库查询")result = {"data": f"查询{table}表,条件{conditions}"}# 存储到缓存query_cache[cache_key] = resultreturn result# 测试缓存
result1 = cached_query("users", {"age": 25, "city": "Beijing"})
result2 = cached_query("users", {"age": 25, "city": "Beijing"})  # 从缓存获取

场景2:配置管理

# 多环境配置管理
config_cache = {}def get_config(environment, service, version):cache_key = (environment, service, version)if cache_key in config_cache:return config_cache[cache_key]# 模拟配置加载config = {"host": f"{environment}-{service}.example.com","port": 8080,"version": version}config_cache[cache_key] = configreturn config# 使用配置
prod_config = get_config("prod", "api", "v1.0")
dev_config = get_config("dev", "api", "v1.0")

场景3:游戏状态管理

# 游戏中的位置状态
position_states = {}def update_position_state(x, y, entities):position_key = (x, y)position_states[position_key] = set(entities)def get_position_state(x, y):position_key = (x, y)return position_states.get(position_key, set())# 更新位置状态
update_position_state(10, 20, ["player", "enemy", "item"])
update_position_state(15, 25, ["wall", "door"])# 获取位置状态
print(get_position_state(10, 20))  # {'enemy', 'item', 'player'}
print(get_position_state(15, 25))  # {'door', 'wall'}
10. 最佳实践
# 1. 使用有意义的键名
# 好的做法
user_sessions = {}
user_sessions[("user123", "session456")] = {"login_time": "2024-01-01", "status": "active"}# 2. 使用类型提示
from typing import Dict, Tuple, Set# 类型提示
coordinate_data: Dict[Tuple[int, int], Set[str]] = {}# 3. 使用默认值
def safe_get_position_data(x, y, default=None):position_key = (x, y)return coordinate_data.get(position_key, default)# 4. 使用字典推导式
# 创建坐标网格
grid = {(x, y): set() for x in range(5) for y in range(5)}
print(grid)
11. 总结

字典键值对的特点:

  1. 键必须是可哈希的:元组、字符串、数字等
  2. 值可以是任意类型:包括集合、列表、字典等
  3. 键的唯一性:相同键会覆盖前一个值
  4. 无序性:字典本身是无序的(Python 3.7+保持插入顺序)

集合的特点:

  1. 无序性:元素没有固定顺序
  2. 唯一性:自动去除重复元素
  3. 可哈希元素:集合中的元素必须是可哈希的
  4. 可变性:可以添加和删除元素

使用场景:

  1. 坐标映射和位置管理
  2. 缓存和性能优化
  3. 配置管理
  4. 图数据结构
  5. 游戏状态管理

注意事项:

  1. 确保键是可哈希的
  2. 注意集合中元素的类型
  3. 合理使用缓存避免内存泄漏
  4. 考虑性能影响

python语法笔记之-@property装饰器语法详解

问题代码

class Rectangle:__count = 0def __init__(self, width, height):Rectangle.__count += 1self.__width = widthself.__height = height@propertydef area(self):return self.__height * self.__widthrectangle = Rectangle(200, 100)
print(rectangle.area)  # 20000

语法详解

1. @property 装饰器的作用

@property 是一个内置装饰器,用于将方法转换为属性,让您可以像访问属性一样访问方法。

基本语法:

@property
def method_name(self):return computed_value
2. 代码执行分析
class Rectangle:__count = 0  # 类变量,记录创建的矩形数量def __init__(self, width, height):Rectangle.__count += 1  # 每次创建实例时计数加1self.__width = width    # 私有属性self.__height = height  # 私有属性@propertydef area(self):return self.__height * self.__width  # 计算面积# 创建实例
rectangle = Rectangle(200, 100)
print(rectangle.area)  # 20000 - 像访问属性一样访问方法

执行过程:

  1. 创建 Rectangle 实例,__count 变为 1
  2. 设置私有属性 __width = 200, __height = 100
  3. 调用 rectangle.area 时,自动执行 area() 方法
  4. 返回计算结果 200 * 100 = 20000
3. @property 的优势

传统方法 vs @property:

# 传统方法
class Rectangle1:def __init__(self, width, height):self.width = widthself.height = heightdef get_area(self):return self.width * self.heightrect1 = Rectangle1(200, 100)
print(rect1.get_area())  # 需要调用方法# 使用 @property
class Rectangle2:def __init__(self, width, height):self.width = widthself.height = height@propertydef area(self):return self.width * self.heightrect2 = Rectangle2(200, 100)
print(rect2.area)  # 像访问属性一样
4. 完整的属性装饰器

@property 的完整语法:

class Circle:def __init__(self, radius):self.__radius = radius@propertydef radius(self):"""获取半径"""return self.__radius@radius.setterdef radius(self, value):"""设置半径"""if value < 0:raise ValueError("半径不能为负数")self.__radius = value@radius.deleterdef radius(self):"""删除半径"""del self.__radius@propertydef area(self):"""计算面积"""import mathreturn math.pi * self.__radius ** 2@propertydef circumference(self):"""计算周长"""import mathreturn 2 * math.pi * self.__radius# 使用示例
circle = Circle(5)
print(circle.radius)        # 5 - 获取半径
print(circle.area)          # 78.54... - 计算面积
print(circle.circumference) # 31.42... - 计算周长circle.radius = 10          # 设置半径
print(circle.area)          # 314.16... - 面积自动更新
5. 实际应用示例

示例1:温度转换

class Temperature:def __init__(self, celsius):self.__celsius = celsius@propertydef celsius(self):"""摄氏度"""return self.__celsius@celsius.setterdef celsius(self, value):self.__celsius = value@propertydef fahrenheit(self):"""华氏度(只读属性)"""return self.__celsius * 9/5 + 32@propertydef kelvin(self):"""开尔文(只读属性)"""return self.__celsius + 273.15# 使用示例
temp = Temperature(25)
print(f"摄氏度: {temp.celsius}°C")      # 25°C
print(f"华氏度: {temp.fahrenheit}°F")   # 77.0°F
print(f"开尔文: {temp.kelvin}K")        # 298.15Ktemp.celsius = 30
print(f"华氏度: {temp.fahrenheit}°F")   # 86.0°F(自动更新)

示例2:银行账户

class BankAccount:def __init__(self, balance=0):self.__balance = balanceself.__transactions = []@propertydef balance(self):"""账户余额(只读)"""return self.__balance@propertydef is_overdrawn(self):"""是否透支(只读)"""return self.__balance < 0@propertydef transaction_count(self):"""交易次数(只读)"""return len(self.__transactions)def deposit(self, amount):"""存款"""if amount > 0:self.__balance += amountself.__transactions.append(f"存款: +{amount}")return Truereturn Falsedef withdraw(self, amount):"""取款"""if amount > 0 and self.__balance >= amount:self.__balance -= amountself.__transactions.append(f"取款: -{amount}")return Truereturn False# 使用示例
account = BankAccount(1000)
print(f"余额: {account.balance}")           # 1000
print(f"交易次数: {account.transaction_count}")  # 0account.deposit(500)
print(f"余额: {account.balance}")           # 1500
print(f"交易次数: {account.transaction_count}")  # 1account.withdraw(2000)
print(f"余额: {account.balance}")           # -500
print(f"是否透支: {account.is_overdrawn}")  # True

示例3:学生成绩管理

class Student:def __init__(self, name):self.__name = nameself.__scores = {}@propertydef name(self):"""学生姓名(只读)"""return self.__name@propertydef average_score(self):"""平均分(只读)"""if not self.__scores:return 0return sum(self.__scores.values()) / len(self.__scores)@propertydef highest_score(self):"""最高分(只读)"""if not self.__scores:return 0return max(self.__scores.values())@propertydef lowest_score(self):"""最低分(只读)"""if not self.__scores:return 0return min(self.__scores.values())@propertydef grade(self):"""等级(只读)"""avg = self.average_scoreif avg >= 90:return 'A'elif avg >= 80:return 'B'elif avg >= 70:return 'C'elif avg >= 60:return 'D'else:return 'F'def add_score(self, subject, score):"""添加成绩"""if 0 <= score <= 100:self.__scores[subject] = scorereturn Truereturn False# 使用示例
student = Student("张三")
student.add_score("数学", 85)
student.add_score("英语", 92)
student.add_score("物理", 78)print(f"姓名: {student.name}")
print(f"平均分: {student.average_score:.1f}")
print(f"最高分: {student.highest_score}")
print(f"最低分: {student.lowest_score}")
print(f"等级: {student.grade}")
6. 高级用法

示例1:缓存属性

class ExpensiveCalculation:def __init__(self, data):self.__data = dataself.__cached_result = None@propertydef expensive_result(self):"""昂贵的计算结果(带缓存)"""if self.__cached_result is None:# 模拟复杂计算import timetime.sleep(1)  # 模拟耗时操作self.__cached_result = sum(self.__data) * 2return self.__cached_resultdef clear_cache(self):"""清除缓存"""self.__cached_result = None# 使用示例
calc = ExpensiveCalculation([1, 2, 3, 4, 5])
print(calc.expensive_result)  # 第一次计算,耗时1秒
print(calc.expensive_result)  # 第二次访问,直接返回缓存结果

示例2:验证属性

class Person:def __init__(self, name, age):self.__name = nameself.__age = age@propertydef name(self):return self.__name@name.setterdef name(self, value):if not isinstance(value, str):raise TypeError("姓名必须是字符串")if len(value.strip()) == 0:raise ValueError("姓名不能为空")self.__name = value.strip()@propertydef age(self):return self.__age@age.setterdef age(self, value):if not isinstance(value, int):raise TypeError("年龄必须是整数")if value < 0 or value > 150:raise ValueError("年龄必须在0-150之间")self.__age = value@propertydef is_adult(self):"""是否成年(只读)"""return self.__age >= 18# 使用示例
person = Person("张三", 25)
print(f"姓名: {person.name}")
print(f"年龄: {person.age}")
print(f"是否成年: {person.is_adult}")# 修改属性
person.name = "李四"
person.age = 30# 验证错误
try:person.age = -5
except ValueError as e:print(f"错误: {e}")try:person.name = ""
except ValueError as e:print(f"错误: {e}")

示例3:计算属性链

class Rectangle:def __init__(self, width, height):self.__width = widthself.__height = height@propertydef width(self):return self.__width@width.setterdef width(self, value):if value <= 0:raise ValueError("宽度必须大于0")self.__width = value@propertydef height(self):return self.__height@height.setterdef height(self, value):if value <= 0:raise ValueError("高度必须大于0")self.__height = value@propertydef area(self):"""面积"""return self.__width * self.__height@propertydef perimeter(self):"""周长"""return 2 * (self.__width + self.__height)@propertydef is_square(self):"""是否为正方形"""return self.__width == self.__height@propertydef diagonal(self):"""对角线长度"""import mathreturn math.sqrt(self.__width ** 2 + self.__height ** 2)# 使用示例
rect = Rectangle(3, 4)
print(f"宽度: {rect.width}")
print(f"高度: {rect.height}")
print(f"面积: {rect.area}")
print(f"周长: {rect.perimeter}")
print(f"是否为正方形: {rect.is_square}")
print(f"对角线长度: {rect.diagonal:.2f}")# 修改尺寸,所有计算属性自动更新
rect.width = 5
print(f"新面积: {rect.area}")
print(f"新周长: {rect.perimeter}")
7. 常见错误和注意事项

错误1:忘记 @property 装饰器

class WrongExample:def __init__(self, value):self.__value = valuedef area(self):  # 没有 @propertyreturn self.__value ** 2obj = WrongExample(5)
# print(obj.area)  # TypeError: 'int' object is not callable
print(obj.area())  # 必须调用方法

错误2:在 setter 中忘记验证

class BadExample:def __init__(self, age):self.__age = age@propertydef age(self):return self.__age@age.setterdef age(self, value):self.__age = value  # 没有验证# 可能导致无效数据
obj = BadExample(25)
obj.age = -100  # 没有验证,可能导致问题

注意事项:

# 1. @property 方法不能接受参数(除了self)
class Example:@propertydef method(self, param):  # 错误:不能有参数return param# 2. @property 方法通常应该是幂等的
class GoodExample:def __init__(self, data):self.__data = data@propertydef processed_data(self):# 好的:幂等操作return sorted(self.__data)@propertydef bad_method(self):# 坏的:非幂等操作self.__data.append(0)  # 修改了对象状态return self.__data
8. 性能考虑
import timeclass PerformanceTest:def __init__(self, data):self.__data = data@propertydef expensive_calculation(self):# 模拟昂贵计算time.sleep(0.1)return sum(self.__data)def regular_method(self):# 普通方法time.sleep(0.1)return sum(self.__data)# 性能测试
test = PerformanceTest([1, 2, 3, 4, 5])# 多次访问 @property
start = time.time()
for _ in range(10):result = test.expensive_calculation
property_time = time.time() - start# 多次调用普通方法
start = time.time()
for _ in range(10):result = test.regular_method()
method_time = time.time() - startprint(f"@property 时间: {property_time:.3f}秒")
print(f"普通方法时间: {method_time:.3f}秒")
9. 最佳实践
# 1. 使用 @property 进行数据验证
class ValidatedProperty:def __init__(self, value):self.__value = value@propertydef value(self):return self.__value@value.setterdef value(self, new_value):if not isinstance(new_value, (int, float)):raise TypeError("值必须是数字")self.__value = new_value# 2. 使用 @property 进行计算
class ComputedProperty:def __init__(self, x, y):self.__x = xself.__y = y@propertydef distance_from_origin(self):import mathreturn math.sqrt(self.__x ** 2 + self.__y ** 2)# 3. 使用 @property 提供只读属性
class ReadOnlyProperty:def __init__(self, data):self.__data = data@propertydef data(self):return self.__data.copy()  # 返回副本,防止外部修改# 4. 使用 @property 进行类型转换
class TypeConversion:def __init__(self, value):self.__value = value@propertydef as_string(self):return str(self.__value)@propertydef as_int(self):return int(self.__value)@propertydef as_float(self):return float(self.__value)
10. 总结

@property 装饰器的特点:

  1. 将方法转换为属性:可以像访问属性一样访问方法
  2. 自动计算:每次访问时都会重新计算
  3. 封装性:隐藏内部实现细节
  4. 验证性:可以在 setter 中进行数据验证
  5. 只读性:可以创建只读属性

使用场景:

  1. 计算属性:基于其他属性计算得出的值
  2. 数据验证:在设置属性时进行验证
  3. 只读属性:防止外部修改的属性
  4. 类型转换:提供不同格式的数据访问
  5. 缓存属性:带缓存的昂贵计算

注意事项:

  1. @property 方法不能接受参数(除了self)
  2. 通常应该是幂等操作
  3. 避免在 @property 中修改对象状态
  4. 考虑性能影响,特别是昂贵计算
  5. 合理使用 setter 和 deleter

优势:

  1. 更自然的语法:像访问属性一样访问方法
  2. 更好的封装:隐藏内部实现
  3. 数据验证:确保数据有效性
  4. 向后兼容:可以改变实现而不影响接口

python语法笔记之-下划线命名约定语法详解

问题代码

class Example:def __init__(self):self._foo = "单下划线属性"        # 单下划线前缀self.__bar = "双下划线属性"       # 双下划线前缀self.__baz__ = "双下划线前后缀"   # 双下划线前后缀def _private_method(self):return "单下划线方法"def __private_method(self):return "双下划线方法"def __str__(self):return "魔法方法"obj = Example()
print(obj._foo)                    # 可以访问
print(obj._Example__bar)           # 通过改写名称访问
print(obj.__baz__)                 # 可以访问
print(obj._private_method())       # 可以调用
print(obj._Example__private_method())  # 通过改写名称调用
print(str(obj))                    # 调用魔法方法

语法详解

1. 三种下划线命名约定的区别

单下划线前缀 _foo

  • 含义:内部使用,不推荐外部访问
  • 访问性:可以正常访问
  • 名称改写:无
  • 继承:子类可以访问

双下划线前缀 __foo

  • 含义:私有成员
  • 访问性:不能直接访问
  • 名称改写_ClassName__foo
  • 继承:子类不能直接访问

双下划线前后缀 __foo__

  • 含义:魔法方法/特殊方法
  • 访问性:可以正常访问
  • 名称改写:无
  • 继承:子类可以访问
2. 代码执行分析
class Example:def __init__(self):self._foo = "单下划线属性"        # 内部属性self.__bar = "双下划线属性"       # 私有属性self.__baz__ = "双下划线前后缀"   # 魔法属性def _private_method(self):return "单下划线方法"             # 内部方法def __private_method(self):return "双下划线方法"             # 私有方法def __str__(self):return "魔法方法"                 # 魔法方法# 创建实例
obj = Example()# 单下划线:可以正常访问
print(obj._foo)                    # "单下划线属性"
print(obj._private_method())       # "单下划线方法"# 双下划线:不能直接访问
# print(obj.__bar)                # AttributeError
# print(obj.__private_method())   # AttributeError# 双下划线:通过改写名称访问
print(obj._Example__bar)           # "双下划线属性"
print(obj._Example__private_method())  # "双下划线方法"# 双下划线前后缀:可以正常访问
print(obj.__baz__)                 # "双下划线前后缀"
print(str(obj))                    # "魔法方法"
3. 详细对比分析

单下划线前缀 _foo

class SingleUnderscore:def __init__(self):self._internal_attr = "内部属性"self.public_attr = "公有属性"def _internal_method(self):return "内部方法"def public_method(self):return "公有方法"obj = SingleUnderscore()# 可以正常访问
print(obj._internal_attr)      # "内部属性"
print(obj._internal_method())  # "内部方法"# 查看对象属性
print(dir(obj))  # 包含 _internal_attr 和 _internal_method

双下划线前缀 __foo

class DoubleUnderscore:def __init__(self):self.__private_attr = "私有属性"self.public_attr = "公有属性"def __private_method(self):return "私有方法"def public_method(self):return "公有方法"obj = DoubleUnderscore()# 不能直接访问
try:print(obj.__private_attr)
except AttributeError as e:print(f"错误: {e}")  # 'DoubleUnderscore' object has no attribute '__private_attr'try:print(obj.__private_method())
except AttributeError as e:print(f"错误: {e}")  # 'DoubleUnderscore' object has no attribute '__private_method'# 通过改写名称访问
print(obj._DoubleUnderscore__private_attr)    # "私有属性"
print(obj._DoubleUnderscore__private_method()) # "私有方法"# 查看对象属性
print(dir(obj))  # 包含 _DoubleUnderscore__private_attr 和 _DoubleUnderscore__private_method

双下划线前后缀 __foo__

class MagicUnderscore:def __init__(self):self.__magic_attr__ = "魔法属性"self.public_attr = "公有属性"def __str__(self):return "魔法方法"def __len__(self):return 42def public_method(self):return "公有方法"obj = MagicUnderscore()# 可以正常访问
print(obj.__magic_attr__)  # "魔法属性"
print(str(obj))           # "魔法方法"
print(len(obj))           # 42# 查看对象属性
print(dir(obj))  # 包含 __magic_attr__, __str__, __len__ 等
4. 继承中的行为差异

单下划线在继承中:

class Parent:def __init__(self):self._internal_attr = "父类内部属性"self.public_attr = "父类公有属性"def _internal_method(self):return "父类内部方法"class Child(Parent):def __init__(self):super().__init__()self._child_attr = "子类内部属性"def access_parent_internal(self):# 子类可以访问父类的单下划线成员print(self._internal_attr)      # "父类内部属性"print(self._internal_method())  # "父类内部方法"print(self._child_attr)         # "子类内部属性"child = Child()
child.access_parent_internal()# 外部也可以访问
print(child._internal_attr)      # "父类内部属性"
print(child._child_attr)         # "子类内部属性"

双下划线在继承中:

class Parent:def __init__(self):self.__private_attr = "父类私有属性"self.public_attr = "父类公有属性"def __private_method(self):return "父类私有方法"class Child(Parent):def __init__(self):super().__init__()self.__private_attr = "子类私有属性"  # 不同的名称改写def access_parent_private(self):# 子类不能直接访问父类的双下划线成员try:print(self.__private_attr)except AttributeError as e:print(f"错误: {e}")# 但可以通过改写名称访问print(self._Parent__private_attr)      # "父类私有属性"print(self._Child__private_attr)       # "子类私有属性"print(self._Parent__private_method())  # "父类私有方法"child = Child()
child.access_parent_private()# 外部访问
print(child._Parent__private_attr)  # "父类私有属性"
print(child._Child__private_attr)   # "子类私有属性"

双下划线前后缀在继承中:

class Parent:def __init__(self):self.__magic_attr__ = "父类魔法属性"def __str__(self):return "父类魔法方法"class Child(Parent):def __init__(self):super().__init__()self.__magic_attr__ = "子类魔法属性"  # 覆盖父类的魔法属性def __str__(self):return "子类魔法方法"  # 覆盖父类的魔法方法def access_magic(self):# 子类可以访问父类的魔法成员print(self.__magic_attr__)  # "子类魔法属性"(被覆盖)print(str(self))           # "子类魔法方法"(被覆盖)child = Child()
child.access_magic()# 外部也可以访问
print(child.__magic_attr__)  # "子类魔法属性"
print(str(child))           # "子类魔法方法"
5. 实际应用示例

示例1:数据封装

class BankAccount:def __init__(self, account_number, balance=0):self._account_number = account_number  # 内部属性self.__balance = balance               # 私有属性self.__transactions = []               # 私有属性def _validate_amount(self, amount):"""验证金额(内部方法)"""return isinstance(amount, (int, float)) and amount > 0def __add_transaction(self, transaction):"""添加交易记录(私有方法)"""self.__transactions.append(transaction)def deposit(self, amount):"""存款(公有方法)"""if self._validate_amount(amount):self.__balance += amountself.__add_transaction(f"存款: +{amount}")return Truereturn Falsedef withdraw(self, amount):"""取款(公有方法)"""if self._validate_amount(amount) and self.__balance >= amount:self.__balance -= amountself.__add_transaction(f"取款: -{amount}")return Truereturn Falsedef get_balance(self):"""获取余额(公有方法)"""return self.__balancedef get_transactions(self):"""获取交易记录(公有方法)"""return self.__transactions.copy()# 使用示例
account = BankAccount("12345", 1000)# 可以访问内部属性
print(account._account_number)  # "12345"# 不能直接访问私有属性
try:print(account.__balance)
except AttributeError:print("不能直接访问私有属性")# 通过公有方法访问
print(account.get_balance())  # 1000account.deposit(500)
account.withdraw(200)
print(account.get_transactions())  # ['存款: +500', '取款: -200']

示例2:配置管理

class Config:def __init__(self):self._config = {}           # 内部配置字典self.__defaults = {         # 私有默认值'host': 'localhost','port': 8080,'debug': False}self.__load_defaults()      # 私有方法def __load_defaults(self):"""加载默认配置(私有方法)"""self._config.update(self.__defaults)def _validate_key(self, key):"""验证配置键(内部方法)"""return isinstance(key, str) and key.strip()def set(self, key, value):"""设置配置(公有方法)"""if self._validate_key(key):self._config[key] = valuereturn Truereturn Falsedef get(self, key, default=None):"""获取配置(公有方法)"""return self._config.get(key, default)def get_all(self):"""获取所有配置(公有方法)"""return self._config.copy()# 使用示例
config = Config()# 可以访问内部属性
print(config._config)  # {'host': 'localhost', 'port': 8080, 'debug': False}# 不能直接访问私有属性
try:print(config.__defaults)
except AttributeError:print("不能直接访问私有属性")# 通过公有方法访问
config.set('host', 'example.com')
print(config.get('host'))  # 'example.com'

示例3:魔法方法使用

class Vector:def __init__(self, x, y):self.__x = x  # 私有属性self.__y = y  # 私有属性def __str__(self):"""字符串表示(魔法方法)"""return f"Vector({self.__x}, {self.__y})"def __repr__(self):"""详细字符串表示(魔法方法)"""return f"Vector(x={self.__x}, y={self.__y})"def __add__(self, other):"""加法运算(魔法方法)"""if isinstance(other, Vector):return Vector(self.__x + other.__x, self.__y + other.__y)return NotImplementeddef __eq__(self, other):"""相等比较(魔法方法)"""if isinstance(other, Vector):return self.__x == other.__x and self.__y == other.__yreturn Falsedef __len__(self):"""长度(魔法方法)"""return 2def get_x(self):"""获取x坐标(公有方法)"""return self.__xdef get_y(self):"""获取y坐标(公有方法)"""return self.__y# 使用示例
v1 = Vector(3, 4)
v2 = Vector(1, 2)# 魔法方法的使用
print(str(v1))      # "Vector(3, 4)"
print(repr(v1))     # "Vector(x=3, y=4)"
print(v1 + v2)      # Vector(4, 6)
print(v1 == v2)     # False
print(len(v1))      # 2# 不能直接访问私有属性
try:print(v1.__x)
except AttributeError:print("不能直接访问私有属性")# 通过公有方法访问
print(v1.get_x())  # 3
print(v1.get_y())  # 4
6. 常见错误和注意事项

错误1:误解双下划线的私有性

class Example:def __init__(self):self.__private_attr = "私有属性"obj = Example()# 错误:认为完全无法访问
# print(obj.__private_attr)  # AttributeError# 正确:通过改写名称可以访问
print(obj._Example__private_attr)  # "私有属性"

错误2:在外部代码中过度使用内部成员

class Library:def __init__(self):self._books = []self.__max_books = 100def _is_full(self):return len(self._books) >= self.__max_booksdef add_book(self, book):if not self._is_full():self._books.append(book)return Truereturn False# 错误用法:直接访问内部成员
library = Library()
# library._books.append("新书")  # 不推荐:绕过了验证逻辑
# print(library._is_full())     # 不推荐:直接调用内部方法# 正确用法:使用公有接口
library.add_book("新书")  # 推荐:通过公有方法

注意事项:

# 1. 单下划线不是真正的私有
class Example:def __init__(self):self._data = "内部数据"obj = Example()
print(obj._data)  # 可以访问# 2. 双下划线会进行名称改写
class Example:def __init__(self):self.__data = "私有数据"obj = Example()
# print(obj.__data)  # AttributeError
print(obj._Example__data)  # 可以通过改写后的名称访问# 3. 继承中的名称改写
class Parent:def __init__(self):self.__data = "父类私有数据"class Child(Parent):def __init__(self):super().__init__()self.__data = "子类私有数据"  # 不同的名称改写child = Child()
print(child._Parent__data)  # "父类私有数据"
print(child._Child__data)   # "子类私有数据"# 4. 魔法方法可以正常访问
class Example:def __init__(self):self.__magic__ = "魔法属性"def __str__(self):return "魔法方法"obj = Example()
print(obj.__magic__)  # "魔法属性"
print(str(obj))       # "魔法方法"
7. 最佳实践
# 1. 使用单下划线表示内部成员
class GoodExample:def __init__(self):self._internal_data = []  # 内部数据self.public_data = []     # 公有数据def _internal_method(self):return "内部方法"          # 内部方法def public_method(self):return "公有方法"          # 公有方法# 2. 使用双下划线表示真正的私有成员
class SecureExample:def __init__(self):self.__private_data = []  # 私有数据self.public_data = []     # 公有数据def __private_method(self):return "私有方法"          # 私有方法def public_method(self):return "公有方法"          # 公有方法# 3. 使用双下划线前后缀定义魔法方法
class MagicExample:def __init__(self, data):self.__data = datadef __str__(self):return f"MagicExample({self.__data})"def __len__(self):return len(self.__data)def __getitem__(self, index):return self.__data[index]# 4. 提供公有接口访问私有成员
class DataManager:def __init__(self):self.__data = []self.__max_size = 100def add_item(self, item):"""添加项目(公有接口)"""if len(self.__data) < self.__max_size:self.__data.append(item)return Truereturn Falsedef get_items(self):"""获取所有项目(公有接口)"""return self.__data.copy()  # 返回副本def get_count(self):"""获取项目数量(公有接口)"""return len(self.__data)# 5. 文档化内部成员
class Calculator:def __init__(self):self.__history = []  # 计算历史记录(私有)def __add_to_history(self, operation, result):"""添加操作到历史记录(私有方法)"""self.__history.append((operation, result))def add(self, a, b):"""加法运算(公有方法)"""result = a + bself.__add_to_history(f"{a} + {b}", result)return resultdef get_history(self):"""获取计算历史(公有方法)"""return self.__history.copy()
8. 总结

三种下划线命名约定的对比:

类型语法含义访问性名称改写继承
单下划线前缀_foo内部使用可以访问子类可访问
双下划线前缀__foo私有成员不能直接访问_ClassName__foo子类不能直接访问
双下划线前后缀__foo__魔法方法可以访问子类可访问

使用建议:

  1. 单下划线前缀 _foo:用于内部成员,表示"不推荐外部访问"
  2. 双下划线前缀 __foo:用于真正的私有成员,防止意外访问
  3. 双下划线前后缀 __foo__:用于魔法方法和特殊属性

注意事项:

  1. Python中没有真正的私有成员,所有成员都可以通过某种方式访问
  2. 双下划线前缀通过名称改写实现"私有",但改写后的名称仍然可以访问
  3. 单下划线前缀只是一种命名约定,不提供任何访问限制
  4. 魔法方法通常由Python解释器自动调用,不应该手动调用

最佳实践:

  1. 使用单下划线表示内部成员
  2. 使用双下划线表示真正的私有成员
  3. 提供公有接口访问私有成员
  4. 文档化内部成员的用途和限制
  5. 避免在外部代码中直接访问内部成员

python语法笔记之-format()方法语法详解

基本语法

str.format(*args, **kwargs)

语法详解

1. 基本用法
# 位置参数
"{} {}".format("Hello", "World")  # "Hello World"# 索引参数
"{0} {1}".format("Hello", "World")  # "Hello World"
"{1} {0}".format("Hello", "World")  # "World Hello"# 关键字参数
"{name} {age}".format(name="张三", age=25)  # "张三 25"
2. 格式说明符
# 数字格式
"{:.2f}".format(3.14159)      # "3.14"
"{:d}".format(42)             # "42"
"{:x}".format(255)            # "ff"# 对齐和宽度
"{:>10}".format("Hello")      # "     Hello"
"{:<10}".format("Hello")      # "Hello     "
"{:^10}".format("Hello")      # "  Hello   "# 填充字符
"{:*>10}".format("Hello")     # "*****Hello"
"{:0<10}".format("Hello")     # "Hello00000"
3. 常用格式
# 字符串
"{:s}".format("text")         # "text"# 整数
"{:d}".format(42)             # "42"
"{:b}".format(42)             # "101010"
"{:o}".format(42)             # "52"
"{:x}".format(42)             # "2a"# 浮点数
"{:.2f}".format(3.14159)      # "3.14"
"{:.2e}".format(1234.56)      # "1.23e+03"
"{:.2%}".format(0.1234)       # "12.34%"
4. 复合格式
# 组合使用
"{:>10.2f}".format(3.14159)   # "      3.14"
"{:*<10s}".format("Hello")    # "Hello*****"
"{:0>8x}".format(255)         # "000000ff"
5. 字典和对象
# 字典
person = {"name": "张三", "age": 25}
"{name} {age}".format(**person)  # "张三 25"# 对象属性
class Person:def __init__(self, name, age):self.name = nameself.age = agep = Person("李四", 30)
"{0.name} {0.age}".format(p)  # "李四 30"
6. 总结

format() 方法特点:

  • 支持位置参数和关键字参数
  • 提供丰富的格式说明符
  • 支持数字、字符串、对齐等格式化
  • % 操作符更灵活

常用格式说明符:

  • s - 字符串
  • d - 十进制整数
  • f - 浮点数
  • x - 十六进制
  • b - 二进制
  • o - 八进制
  • > - 右对齐
  • < - 左对齐
  • ^ - 居中对齐

python语法笔记之-浅拷贝与深拷贝语法详解

问题代码

import copy
a = [1, 2, 3, 4, ['a', 'b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(5)
a[4].append('c')

语法详解

1. 三种复制方式的区别

直接赋值 b = a

  • 创建引用,指向同一个对象
  • 修改任一变量都会影响另一个

浅拷贝 copy.copy(a)

  • 创建新对象,但嵌套对象仍共享引用
  • 修改顶层元素不影响原对象,修改嵌套对象会影响原对象

深拷贝 copy.deepcopy(a)

  • 创建完全独立的新对象
  • 修改任何元素都不会影响原对象
2. 代码执行分析
import copy# 原始列表
a = [1, 2, 3, 4, ['a', 'b']]
print(f"原始列表 a: {a}")  # [1, 2, 3, 4, ['a', 'b']]# 直接赋值
b = a
print(f"直接赋值 b: {b}")  # [1, 2, 3, 4, ['a', 'b']]# 浅拷贝
c = copy.copy(a)
print(f"浅拷贝 c: {c}")    # [1, 2, 3, 4, ['a', 'b']]# 深拷贝
d = copy.deepcopy(a)
print(f"深拷贝 d: {d}")    # [1, 2, 3, 4, ['a', 'b']]# 修改原始列表
a.append(5)        # 添加顶层元素
a[4].append('c')   # 修改嵌套列表print(f"修改后 a: {a}")    # [1, 2, 3, 4, ['a', 'b', 'c'], 5]
print(f"修改后 b: {b}")    # [1, 2, 3, 4, ['a', 'b', 'c'], 5] (受影响)
print(f"修改后 c: {c}")    # [1, 2, 3, 4, ['a', 'b', 'c']] (嵌套对象受影响)
print(f"修改后 d: {d}")    # [1, 2, 3, 4, ['a', 'b']] (完全独立)
3. 内存结构分析
import copya = [1, 2, 3, 4, ['a', 'b']]# 直接赋值 - 同一对象
b = a
print(f"a is b: {a is b}")  # True# 浅拷贝 - 新对象,但嵌套对象共享
c = copy.copy(a)
print(f"a is c: {a is c}")  # False
print(f"a[4] is c[4]: {a[4] is c[4]}")  # True# 深拷贝 - 完全独立
d = copy.deepcopy(a)
print(f"a is d: {a is d}")  # False
print(f"a[4] is d[4]: {a[4] is d[4]}")  # False
4. 不同数据类型的拷贝行为
import copy# 列表
list_a = [1, 2, [3, 4]]
list_b = copy.copy(list_a)
list_c = copy.deepcopy(list_a)# 字典
dict_a = {'a': 1, 'b': [2, 3]}
dict_b = copy.copy(dict_a)
dict_c = copy.deepcopy(dict_a)# 元组(不可变,但可能包含可变元素)
tuple_a = (1, 2, [3, 4])
tuple_b = copy.copy(tuple_a)
tuple_c = copy.deepcopy(tuple_a)# 集合
set_a = {1, 2, 3}
set_b = copy.copy(set_a)
set_c = copy.deepcopy(set_a)
5. 实际应用场景

浅拷贝适用场景:

# 配置管理
config = {'host': 'localhost','port': 8080,'options': {'timeout': 30}
}# 创建配置副本
dev_config = copy.copy(config)
dev_config['host'] = 'dev.example.com'
dev_config['options']['timeout'] = 60# 原配置不受影响(顶层),但嵌套对象受影响
print(config['host'])        # 'localhost'
print(config['options']['timeout'])  # 60 (受影响)

深拷贝适用场景:

# 游戏状态
game_state = {'player': {'health': 100, 'inventory': ['sword', 'shield']},'enemies': [{'type': 'goblin', 'health': 50}]
}# 保存游戏状态
saved_state = copy.deepcopy(game_state)# 修改当前状态
game_state['player']['health'] = 80
game_state['enemies'][0]['health'] = 30# 保存的状态完全独立
print(saved_state['player']['health'])  # 100
print(saved_state['enemies'][0]['health'])  # 50
6. 性能考虑
import copy
import time# 创建大型嵌套结构
def create_large_structure(depth, width):if depth == 0:return [i for i in range(width)]return [create_large_structure(depth - 1, width) for _ in range(width)]large_data = create_large_structure(3, 10)# 测试浅拷贝性能
start = time.time()
shallow_copy = copy.copy(large_data)
shallow_time = time.time() - start# 测试深拷贝性能
start = time.time()
deep_copy = copy.deepcopy(large_data)
deep_time = time.time() - startprint(f"浅拷贝时间: {shallow_time:.6f}秒")
print(f"深拷贝时间: {deep_time:.6f}秒")
print(f"深拷贝是浅拷贝的 {deep_time/shallow_time:.1f} 倍")
7. 常见错误和注意事项

错误1:误解浅拷贝

import copyoriginal = [1, 2, [3, 4]]
shallow = copy.copy(original)# 错误:认为浅拷贝完全独立
shallow[2].append(5)
print(original[2])  # [3, 4, 5] (受影响)

错误2:循环引用

import copy# 创建循环引用
a = [1, 2]
a.append(a)# 深拷贝可以处理循环引用
b = copy.deepcopy(a)
print(b)  # [1, 2, [...]]

注意事项:

# 1. 不可变对象的拷贝
import copy# 字符串、数字、元组(不包含可变元素)的拷贝
string_a = "hello"
string_b = copy.copy(string_a)
string_c = copy.deepcopy(string_a)
print(string_a is string_b)  # True
print(string_a is string_c)  # True# 2. 自定义对象的拷贝
class Person:def __init__(self, name, friends=None):self.name = nameself.friends = friends or []person1 = Person("Alice")
person1.friends.append("Bob")# 浅拷贝
person2 = copy.copy(person1)
person2.name = "Charlie"
person2.friends.append("David")print(person1.name)      # "Alice"
print(person1.friends)   # ["Bob", "David"] (受影响)# 深拷贝
person3 = copy.deepcopy(person1)
person3.friends.append("Eve")print(person1.friends)   # ["Bob", "David"]
print(person3.friends)   # ["Bob", "David", "Eve"]
8. 最佳实践
import copy# 1. 选择合适的拷贝方式
def process_data(data, need_deep_copy=False):if need_deep_copy:return copy.deepcopy(data)else:return copy.copy(data)# 2. 使用列表推导式进行浅拷贝
original = [1, 2, [3, 4]]
shallow = [item for item in original]  # 等价于 copy.copy()# 3. 使用切片进行浅拷贝
shallow_slice = original[:]  # 等价于 copy.copy()# 4. 使用dict()和list()进行浅拷贝
dict_copy = dict(original_dict)
list_copy = list(original_list)# 5. 自定义深拷贝
def custom_deep_copy(obj):if isinstance(obj, dict):return {key: custom_deep_copy(value) for key, value in obj.items()}elif isinstance(obj, list):return [custom_deep_copy(item) for item in obj]elif isinstance(obj, (int, float, str, bool, type(None))):return objelse:return copy.deepcopy(obj)
9. 总结

三种复制方式的对比:

方式语法对象独立性嵌套对象独立性性能适用场景
直接赋值b = a最快需要共享对象
浅拷贝copy.copy(a)简单数据结构
深拷贝copy.deepcopy(a)复杂嵌套结构

使用建议:

  1. 直接赋值:需要共享对象时使用
  2. 浅拷贝:简单数据结构,不包含嵌套可变对象时使用
  3. 深拷贝:复杂嵌套结构,需要完全独立时使用

注意事项:

  1. 浅拷贝只复制顶层对象,嵌套对象仍共享引用
  2. 深拷贝可以处理循环引用
  3. 不可变对象的拷贝通常返回原对象
  4. 深拷贝性能较慢,特别是大型嵌套结构

python语法笔记之-闭包语法详解

问题代码

def adder(x):def wrapper(y):return x + yreturn wrapper
adder5 = adder(5)
print(adder5(adder5(6)))  # 16

语法详解

1. 闭包基本语法
def outer_function(x):      # 外部函数def inner_function(y):  # 内部函数return x + y        # 访问外部变量xreturn inner_function   # 返回内部函数
2. 代码执行分析
def adder(x):def wrapper(y):return x + yreturn wrapper# 创建闭包
adder5 = adder(5)          # x=5,返回wrapper函数
result = adder5(6)         # y=6,返回5+6=11
final = adder5(adder5(6))  # adder5(6)=11,然后adder5(11)=16
print(final)               # 16
3. 闭包特点
  • 内部函数:定义在外部函数内部
  • 访问外部变量:内部函数可以访问外部函数的变量
  • 返回函数:外部函数返回内部函数
  • 保持状态:闭包会"记住"外部变量的值
4. 常见用法
# 计数器
def counter():count = 0def increment():nonlocal countcount += 1return countreturn increment# 配置函数
def multiply_by(factor):def multiply(x):return x * factorreturn multiply# 装饰器基础
def decorator(func):def wrapper(*args, **kwargs):print("开始执行")result = func(*args, **kwargs)print("执行结束")return resultreturn wrapper
5. 总结

闭包语法要点:

  • 外部函数定义内部函数
  • 内部函数访问外部变量
  • 外部函数返回内部函数
  • 闭包保持外部变量的状态

使用场景:

  • 函数工厂
  • 装饰器
  • 状态保持
  • 配置函数

http://www.dtcms.com/a/297920.html

相关文章:

  • 《剑指offer》-数据结构篇-链表
  • GDB调试命令学习
  • spring boot项目使用Spring Security加密
  • k8s开启审计日志
  • 【SSL证书校验问题】通过 monkey-patch 关掉 SSL 证书校验
  • Fluent遇上AI:深度学习重塑计算流体动力学的未来
  • 【记录】C++生产者 / 消费者 案例
  • 刷题日记0725
  • 篇五 网络通信硬件之PHY,MAC, RJ45
  • PytorchLightning最佳实践基础篇
  • 谷歌母公司Alphabet发布超预期业绩,提高全年资本支出至850亿美元
  • 从 Elastic 到 ClickHouse:日志系统性能与成本优化之路
  • 【大模型实战】提示工程(Prompt Engineering)
  • 优秀案例:基于python django的智能家居销售数据采集和分析系统设计与实现,使用混合推荐算法和LSTM算法情感分析
  • 九联UNT413AS_晶晨S905L3S芯片_2+8G_安卓9.0_线刷固件包
  • 短剧小程序系统开发:构建影视娱乐生态新格局
  • Spring Boot License 认证系统
  • C#(数据类型)
  • k8s的存储之secerts
  • Python数据可视化利器:Matplotlib全解析
  • 智能制造——解读39页MOM数字化工厂平台解决方案【附全文阅读】
  • Linux网络配置全攻略:IP、路由与双机通信
  • 北京-4年功能测试2年空窗-报培训班学测开-第六十天-准备项目中
  • 图的遍历:深度优先与广度优先
  • SpringBoot学习路径二--Spring Boot自动配置原理深度解析
  • Qt 状态机框架:复杂交互逻辑的处理
  • R 语言绘制六种精美热图:转录组数据可视化实践(基于 pheatmap 包)
  • 从零开始学习Dify-数据库数据可视化(五)
  • java的设计模式及代理模式
  • 负载均衡:提升业务性能的关键技术