Python编程练习小结
变量是编程中的一个基本概念,用来存储数据。在 Python 中,变量的使用非常灵活,可以存储不同类型的数据,如整数、浮点数、字符串、列表、字典等。以下是 Python 中变量的一些基本用法和规则:
1. 变量的命名规则
变量名必须以字母或下划线 _ 开头,不能以数字开头。
变量名可以包含字母、数字和下划线,但不能包含空格或其他特殊字符。
变量名对大小写敏感,例如 myVar 和 myvar 是两个不同的变量。
2. 变量的声明和赋值
在 Python 中,无需显式声明变量的类型,只需直接赋值即可创建变量。变量的类型由赋给它的值决定。
# 整数
a = 10
# 浮点数
b = 3.14
# 字符串
c = "Hello, World!"
# 列表
d = [1, 2, 3, 4, 5]
# 字典
e = {
"name": "Alice", "age": 25}
3. 变量类型的动态性
Python 是动态类型语言,变量的类型可以在程序运行过程中发生改变。
x = 10 # x 是一个整数
x = "Hello" # 现在 x 是一个字符串
4. 变量的使用
可以通过变量名来访问和操作存储在变量中的数据。
# 使用变量进行计算
a = 5
b = 3
c = a + b # c 的值是 8
# 使用变量打印输出
print(c) # 输出 8
# 修改变量的值
a = a + 1 # 现在 a 的值是 6
print(a) # 输出 6
5. 全局变量和局部变量
全局变量:在函数外部定义的变量,可以在整个程序中访问。
局部变量:在函数内部定义的变量,只能在函数内部访问。
# 全局变量
x = 10
def my_function():
# 局部变量
y = 5
print("局部变量 y:", y)
print("全局变量 x:", x)
my_function()
print("全局变量 x:", x)
# print(y) # 这行会报错,因为 y 是局部变量,无法在函数外部访问
6. 修改全局变量
如果需要在函数内部修改全局变量,可以使用 global 关键字。
x = 10
def my_function():
global x
x = 5 # 修改全局变量 x
my_function()
print("全局变量 x:", x) # 输出 5
python: 好的,我们继续深入了解 Python 中变量的高级用法和一些最佳实践。
7. 多变量赋值
Python 允许一次性给多个变量赋值,这在某些情况下非常方便。
# 同时给多个变量赋值
a, b, c = 1, 2, 3
# 交换两个变量的值
a, b = b, a
# 使用列表或元组进行赋值
data = [4, 5, 6]
x, y, z = data
print(a, b, c) # 输出:2 1 3
print(x, y, z) # 输出:4 5 6
8. 解包(Unpacking)
解包是一种从数据结构(如列表、元组或字典)中提取元素并赋值给变量的操作。
# 解包元组
t = (1, 2, 3)
a, b, c = t
print(a, b, c) # 输出:1 2 3
# 解包字典
d = {
'name': 'Alice', 'age': 25}
name, age = d.values()
print(name, age) # 输出:Alice 25
# 使用 * 解包剩余元素
numbers = [1, 2, 3, 4, 5]
first, *rest = numbers
print(first) # 输出:1
print(rest) # 输出:[2, 3, 4, 5]
9. 变量作用域(Scope)
变量的作用域决定了变量在程序中的可见性和生命周期。主要有以下几种作用域:
局部作用域(Local Scope):在函数内部定义的变量,其作用域仅限于函数内部。
全局作用域(Global Scope):在函数外部定义的变量,可以在整个模块中访问。
内置作用域(Built-in Scope):Python 内置的名字空间,例如 print、len 等函数。
x = "global"
def my_function():
x = "local"
print(x) # 输出:local
my_function()
print(x) # 输出:global
使用 nonlocal 关键字可以在嵌套函数中修改外围函数的变量。
def outer_function():
x = "outer"
def inner_function():
nonlocal x
x = "inner"
print(x) # 输出:inner
inner_function()
print(x) # 输出:inner
outer_function()
**
- 常量**
在 Python 中没有真正的常量,但可以通过约定来定义常量。通常使用全大写字母来表示常量,表示这些变量的值不应改变。
PI = 3.14159
GRAVITY = 9.8
# 尽管这只是一个约定,实际上它们的值仍然可以被改变
PI = 3.14 # 不推荐这么做
11. 类型注解(Type Hints)
Python 3.5 引入了类型注解,可以用来明确变量的类型,有助于代码的可读性和静态类型检查。
# 类型注解
a: int = 10
b: float = 3.14
c: str = "Hello"
d: list = [1, 2, 3]
e: dict = {
"name": "Alice", "age": 25}
# 函数的类型注解
def greet(name: str) -> str:
return "Hello, " + name
print(greet("World")) # 输出:Hello, World
12. 可变和不可变对象
Python 中的对象分为可变对象和不可变对象。可变对象的值可以改变,而不可变对象一旦创建,其值就不能改变。
不可变对象:整数、浮点数、字符串、元组等。
可变对象:列表、字典、集合等。
# 不可变对象示例
x = 10
x = 20 # 创建了新的整数对象,x 不再指向 10
# 可变对象示例
my_list = [1, 2, 3]
my_list.append(4) # 修改了列表对象
python: 让我们继续深入探讨 Python 中变量的更多高级用法和最佳实践。
13. 变量的生命周期
变量的生命周期指的是变量在内存中存在的时间。在 Python 中,变量的生命周期通常由其作用域决定。
局部变量:在函数执行期间存在,一旦函数执行完毕,局部变量就会被销毁。
全局变量:在整个程序的执行期间存在,直到程序结束或显式删除它。
def my_function():
local_var = "I'm local" # 局部变量
print(local_var)
my_function()
# print(local_var) # 这行代码会报错,因为 local_var 已经被销毁
14. 内存管理和垃圾回收
Python 使用自动内存管理和垃圾回收机制来管理变量的内存。Python 的垃圾回收机制主要通过引用计数和循环垃圾收集来实现。
引用计数:每个对象都维护一个引用计数,当引用计数为零时,内存会被释放。
循环垃圾收集:用于检测和处理引用计数无法解决的循环引用问题。
import sys
a = []
b = a
print(sys.getrefcount(a)) # 输出 3,因为 a 和 b 都引用了同一个对象,另一个引用来自 getrefcount 的参数
del a
print(sys.getrefcount(b)) # 输出 2,因为 a 被删除,但 b 仍然引用对象
15. 全局变量的修改和访问
在函数内部访问和修改全局变量时,需要使用 global 关键字。如果在函数内部修改全局变量而不使用 global,将会创建一个新的局部变量。
x = 10
def modify_global():
global x
x = 5 # 修改全局变量 x
modify_global()
print(x) # 输出 5
16. 闭包(Closure)
闭包是一种函数,能够捕获和记住其所在环境的变量。即使闭包所在的环境已经销毁,闭包仍然可以访问这些变量。
def outer_function():
x = 10
def inner_function():
print(x) # 访问外部函数的变量
return inner_function
closure = outer_function()
closure() # 输出 10
17. 非局部变量(Nonlocal)
在嵌套函数中,使用 nonlocal 关键字可以修改外层(但不是全局)作用域中的变量。
def outer_function():
x = "outer"
def inner_function():
nonlocal x
x = "inner" # 修改外层作用域中的变量
print(x) # 输出:inner
inner_function()
print(x) # 输出:inner
outer_function()
18. 变量的类型转换
在 Python 中,可以使用内置函数进行显式类型转换,例如 int(), float(), str(), list(), dict() 等。
# 类型转换示例
a = "123"
b = int(a) # 转换为整数
print(b) # 输出 123
c = "3.14"
d = float(c) # 转换为浮点数
print(d) # 输出 3.14
e = 42
f = str(e) # 转换为字符串
print(f) # 输出 "42"
19. 深拷贝和浅拷贝
在处理复杂数据结构(如嵌套列表或字典)时,理解深拷贝和浅拷贝非常重要。
浅拷贝:复制对象,但不复制嵌套的对象。
深拷贝:递归复制所有对象,包括嵌套的对象。
import copy
# 浅拷贝示例
original = [1, [2, 3], 4]
shallow_copy = copy.copy(original)
shallow_copy[1][0] = 999
print(original) # 输出:[1, [999, 3], 4]
print(shallow_copy) # 输出:[1, [999, 3], 4]
# 深拷贝示例
original = [1, [2, 3], 4]
deep_copy = copy.deepcopy(original)
deep_copy[1][0] = 999
print(original) # 输出:[1, [2, 3], 4]
print(deep_copy) # 输出:[1, [999, 3], 4]
20. 变量的最佳实践
以下是一些变量使用的最佳实践,帮助编写更清晰、可维护的代码:
命名规范:使用有意义的名称,并遵循命名规则。常量使用全大写,变量使用小写字母和下划线。
避免使用全局变量:尽量使用局部变量和参数传递,减少全局变量的使用,以提高代码的可维护性和可测试性。
保持函数简洁:函数应尽量简洁,避免使用过多的局部变量。
使用类型注解:使用类型注解提高代码可读性和帮助静态类型检查。
遵循 PEP 8:遵循 PEP 8 编码规范,提高代码一致性和可读性。
21. 引用和对象
Python 变量实际上是对对象的引用。这意味着多个变量可以引用同一个对象,而不是像 C 或 Java 中那样存储实际的值。
a = [1, 2, 3]
b = a # b 和 a 都引用同一个列表对象
b.append(4)
print(a) # 输出:[1, 2, 3, 4]
print(b) # 输出:[1, 2, 3, 4]
22. 变量命名冲突和命名空间
命名空间是一种将名字与对象绑定的方式。在 Python 中,有几个命名空间层级:
内置命名空间:包含 Python 内建的函数和异常,例如 print、len。
全局命名空间:模块级的命名空间。
局部命名空间:函数或方法内的命名空间。
命名空间的搜索顺序是:局部命名空间 -> 全局命名空间 -> 内置命名空间。
# 示例
def my_function():
print(len) # len 是内置函数
len = 5
print(len) # len 现在是局部变量
my_function()
23. 使用 locals() 和 globals()
locals() 函数返回当前局部命名空间中的所有变量,globals() 函数返回全局命名空间中的所有变量。
x = 10
def my_function():
y = 5
print("局部命名空间:", locals())
print("全局命名空间:", globals())
my_function()
24. 文档字符串(Docstrings)
使用文档字符串可以为模块、函数、类或方法编写文档。文档字符串通常放在定义的开头,并使用三引号(""" 或 ''')包裹。
def greet(name: str) -> str:
"""
生成一个问候字符串。
参数:
name (str): 要问候的人的名字。
返回:
str: 包含问候的字符串。
"""
return "Hello, " + name
print(greet.__doc__)
25. 注释
良好的注释可以极大提高代码的可读性。注释应该简洁明了,解释代码的意图而不是代码本身。
# 这是一个单行注释
"""
这是一个多行注释
用于解释较复杂的代码
"""
# 示例代码
def factorial(n: int) -> int:
"""
计算 n 的阶乘。
参数:
n (int): 要计算阶乘的非负整数。
返回:
int: n 的阶乘。
"""
if n == 0:
return 1
else:
return n * factorial(n - 1)
26. Lambda 函数和匿名函数
Lambda 函数是一种简洁的匿名函数,可以在需要简单函数的地方使用。
# Lambda 函数示例
add = lambda x, y: x + y
print(add(2, 3)) # 输出:5
# 使用 lambda 函数作为参数
numbers = [1, 2, 3, 4, 5]
squared_numbers = map(lambda x: x ** 2, numbers)
print(list(squared_numbers)) # 输出:[1, 4, 9, 16, 25]
- 内置函数和高阶函数
Python 提供了许多内置函数,如 sum(), min(), max(), len() 等。高阶函数是接受函数作为参数或返回函数的函数,例如 map(), filter(), reduce()。
# 高阶函数示例
from functools import reduce
numbers = [1, 2, 3, 4, 5]
# 使用 map 将所有元素平方
squared = list(map(lambda x: x ** 2, numbers))
print(squared) # 输出:[1, 4, 9, 16, 25]
# 使用 filter 筛选偶数
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # 输出:[2, 4]
# 使用 reduce 求和
total = reduce(lambda x, y: x + y, numbers)
print(total) # 输出:15
- 列表推导式和生成器表达式
列表推导式和生成器表达式是创建列表和生成器的简洁方式。
# 列表推导式
squares = [x ** 2 for x in range(10)]
print(squares) # 输出:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 生成器表达式
squares_gen = (x ** 2 for x in range(10))
print(list(squares_gen)) # 输出:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
29. 可变默认参数
在定义函数时,避免使用可变对象作为默认参数,因为它们在函数调用之间会被共享。
# 错误示例
def append_to_list(value, my_list=[]):
my_list.append(value)
return my_list
print(append_to_list(1)) # 输出:[1]
print(append_to_list(2)) # 输出:[1, 2]
# 正确示例
def append_to_list(value, my_list=None):
if my_list is None:
my_list = []
my_list.append(value)
return my_list
print(append_to_list(1)) # 输出:[1]
print(append_to_list(2)) # 输出:[2]
30. 可迭代对象和迭代器
在 Python 中,任何实现了 iter() 方法的对象都是可迭代的。迭代器是实现了 next() 方法的对象,可以逐个返回元素。
# 可迭代对象示例
class MyIterable:
def __iter__(self):
self.current = 0
return self
def __next__(self):
if self.current < 5:
self.current += 1
return self.current
else:
raise StopIteration
my_iterable = MyIterable()
for item in my_iterable:
print(item) # 输出:1 2 3 4 5
python: 让我们继续探讨一些更高级的 Python 变量和相关概念。
31. 数据类(Data Classes)
数据类是 Python 3.7 引入的一种用于存储数据的类。它自动生成常见的特殊方法(如 init, repr, eq 等),使代码更简洁。
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
p1 = Point(10, 20)
p2 = Point(10, 20)
print(p1) # 输出:Point(x=10, y=20)
print(p1 == p2) # 输出:True
32. 命名元组(Named Tuples)
命名元组是 collections 模块中的一种数据结构,类似于元组,但可以通过名称访问元素。
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x) # 输出:10
print(p.y) # 输出:20
33. 可调用对象
在 Python 中,除了函数,任何实现了 call 方法的对象都是可调用的。这使得类实例也可以像函数一样调用。
class Adder:
def __init__(self, value):
self.value = value
def __call__(self, x):
return self.value + x
add5 = Adder(5)
print(add5(10)) # 输出:15
34. 元编程
元编程是一种写代码的代码,即在运行时动态地创建或修改代码。元编程包括装饰器和元类。
装饰器
装饰器是一种函数,用于修改或增强其他函数的行为。
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Calling function:", func.__name__)
result = func(*args, **kwargs)
print("Function called:", func.__name__)
return result
return wrapper
@my_decorator
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Alice")
元类
元类是用于创建类的类。你可以通过定制元类来控制类的创建和行为。
class Meta(type):
def __new__(cls, name, bases, dct):
print(f"Creating class {name}")
return super().__new__(cls, name, bases, dct)
class MyClass(metaclass=Meta):
pass
# 输出:Creating class MyClass
35. 上下文管理器
上下文管理器是一种用于管理资源的对象,常用于文件操作和网络连接等场景。上下文管理器使用 with 语句,并通过实现 enter 和 exit 方法来管理资源。
class MyContext:
def __enter__(self):
print("Entering context")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting context")
with MyContext():
print("Inside context")
# 输出:
# Entering context
# Inside context
# Exiting context
36. 生成器和协程
生成器
生成器是一种特殊的迭代器,通过 yield 关键字返回值。每次调用生成器的 next() 方法时,它会执行到下一个 yield 语句,返回该值并暂停执行。生成器非常适用于处理大数据流,因为它们一次只生成一个值,而不是一次性生成所有值。
def my_generator():
yield 1
yield 2
yield 3
gen = my_generator()
print(next(gen)) # 输出:1
print(next(gen)) # 输出:2
print(next(gen)) # 输出:3
# print(next(gen)) # 这行会引发 StopIteration 异常,因为生成器已耗尽
生成器表达式是创建生成器的一种简洁方式,类似于列表推导式,但使用圆括号。
gen_exp = (x * x for x in range(5))
print(list(gen_exp)) # 输出:[0, 1, 4, 9, 16]
协程
协程是一种用于并发编程的生成器扩展,可以在执行中间暂停并在以后继续执行。协程通过 yield 关键字将控制权交回调用方,并通过 send() 方法接收值。
def my_coroutine():
while True:
value = (yield)
print(f"Received: {value}")
coro = my_coroutine()
next(coro) # 启动协程
coro.send(10) # 输出:Received: 10
coro.send(20) # 输出:Received: 20
coro.close() # 关闭协程
37. 异步编程
Python 的 asyncio 模块支持异步编程,使得编写高效的 I/O 操作和并发任务变得更容易。关键字 async 用于定义异步函数,await 用于等待异步操作。
import asyncio
async def say_hello():
print("Hello")
await asyncio.sleep(1)
print("World")
# 获取事件循环并运行异步函数
asyncio.run(say_hello())
38. 属性和描述符
属性
属性(Property)是通过 property 函数或装饰器定义的,允许控制对实例属性的访问。
class MyClass:
def __init__(self, value):
self._value = value
@property
def value(self):
return self._value
@value.setter
def value(self, new_value):
if new_value < 0:
raise ValueError("Value cannot be negative")
self._value = new_value
obj = MyClass(10)
print(obj.value) # 输出:10
obj.value = 20
print(obj.value) # 输出:20
# obj.value = -10 # 这行会引发 ValueError
38.描述符
描述符是实现了 get, set, 和 delete 方法的类,提供了一种高级的属性管理机制。
class Descriptor:
def __get__(self, instance, owner):
return instance._value
def __set__(self, instance, value):
if value < 0:
raise ValueError("Value cannot be negative")
instance._value = value
class MyClass:
value = Descriptor()
def __init__(self, value):
self._value = value
obj = MyClass(10)
print(obj.value) # 输出:10
obj.value = 20
print(obj.value) # 输出:20
# obj.value = -10 # 这行会引发 ValueError
39. 函数注解
函数注解是一种提供函数参数和返回值元数据的方法,可以使用注解提高代码可读性和支持静态类型检查。
def greet(name: str) -> str:
return f"Hello, {name}"
print(greet("Alice")) # 输出:Hello, Alice
print(greet.__annotations__) # 输出:{
'name': <class 'str'>, 'return': <class 'str'>}
40. 枚举
枚举(Enum)类是用于定义一组命名常量的类,提供了更清晰和安全的代码。
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
print(Color.RED) # 输出:Color.RED
print(Color.RED.name) # 输出:RED
print(Color.RED.value) # 输出:1
41. 上下文管理器装饰器
contextlib 模块提供了一个方便的 @contextmanager 装饰器,用于简化上下文管理器的创建。
from contextlib import contextmanager
@contextmanager
def my_context():
print("Entering context")
yield
print("Exiting context")
with my_context():
print("Inside context")
42. 属性装饰器
属性装饰器是创建只读属性的简便方法,使用 @property 装饰器创建。
class MyClass:
def __init__(self, value):
self._value = value
@property
def value(self):
return self._value
obj = MyClass(10)
print(obj.value) # 输出:10
# obj.value = 20 # 这行会引发 AttributeError,因为 value 是只读属性
python: 好的,让我们继续探讨更多高级的 Python 变量和相关概念。
43. 依赖注入
依赖注入是一种设计模式,旨在将类的依赖关系从类内部移到外部管理。它可以通过构造函数注入、属性注入或方法注入实现,便于单元测试和模块解耦。
class Service:
def greet(self):
return "Hello, World!"
class Client:
def __init__(self, service: Service):
self.service = service
def do_something(self):
return self.service.greet()
service = Service()
client = Client(service)
print(client.do_something()) # 输出:Hello, World!
44. 多重继承和 MRO(方法解析顺序)
多重继承是指一个类可以继承多个父类。在 Python 中,多重继承的顺序由 C3 线性化(MRO)算法决定。使用 mro() 方法可以查看类的 MRO。
class A:
def say_hello(self):
print("Hello from A")
class B(A):
def say_hello(self):
print("Hello from B")
class C(A):
def say_hello(self):
print("Hello from C")
class D(B, C):
pass
d = D()
d.say_hello() # 输出:Hello from B
print(D.mro()) # 输出:[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
45. 抽象基类
抽象基类(ABC)用于定义接口和抽象方法。通过继承 abc.ABC 并使用 @abstractmethod 装饰器,可以创建抽象基类,要求子类实现这些方法。
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def sound(self):
pass
class Dog(Animal):
def sound(self):
return "Bark"
class Cat(Animal):
def sound(self):
return "Meow"
dog = Dog()
cat = Cat()
print(dog.sound()) # 输出:Bark
print(cat.sound()) # 输出:Meow
46. 单例模式
单例模式是一种设计模式,确保一个类只有一个实例。可以通过重写 new 方法或使用装饰器来实现。
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2) # 输出:True
47. 组合和聚合
组合和聚合是面向对象设计中的两种关系,表示类之间的“有”关系。组合表示强关联,即部件不能独立存在;聚合表示弱关联,即部件可以独立存在。
# 组合示例
class Engine:
def start(self):
print("Engine started")
class Car:
def __init__(self):
self.engine = Engine()
def drive(self):
self.engine.start()
print("Car is driving")
car = Car()
car.drive()
# 输出:
# Engine started
# Car is driving
# 聚合示例
class Wheel:
def rotate(self):
print("Wheel is rotating")
class Bike:
def __init__(self, wheels):
self.wheels = wheels
def ride(self):
for wheel in self.wheels:
wheel.rotate()
print("Bike is riding")
wheels = [Wheel(), Wheel()]
bike = Bike(wheels)
bike.ride()
# 输出:
# Wheel is rotating
# Wheel is rotating
# Bike is riding
48. 元编程和装饰器
装饰器是一种高阶函数,用于修改或增强函数或方法的行为。元编程是一种编写操作代码的代码的方式,装饰器是元编程的一个重要工具。
函数装饰器
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Before calling function")
result = func(*args, **kwargs)
print("After calling function")
return result
return wrapper
@my_decorator
def say_hello(name):
print(f"Hello, {name}")
say_hello("Alice")
# 输出:
# Before calling function
# Hello, Alice
# After calling function
类装饰器
def my_class_decorator(cls):
class Wrapper:
def __init__(self, *args, **kwargs):
self.wrapped = cls(*args, **kwargs)
def __getattr__(self, name):
return getattr(self.wrapped, name)
def new_method(self):
print("New method added by decorator")
return Wrapper
@my_class_decorator
class MyClass:
def method(self):
print("Original method")
obj = MyClass()
obj.method() # 输出:Original method
obj.new_method() # 输出:New method added by decorator
49. 动态属性
动态属性允许在运行时动态地添加或修改属性,可以通过 getattr, setattr, 和 delattr 方法实现。
class DynamicAttributes:
def __init__(self):
self.__dict__['attributes'] = {
}
def __getattr__(self, name):
return self.attributes.get(name, None)
def __setattr__(self, name, value):
self.attributes[name] = value
def __delattr__(self, name):
if name in self.attributes:
del self.attributes[name]
dyn = DynamicAttributes()
dyn.foo = 42
print(dyn.foo) # 输出:42
del dyn.foo
print(dyn.foo) # 输出:None
50. 操作符重载
操作符重载允许类重定义常见运算符的行为,例如加法、减法等。
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __repr__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # 输出:Vector(4, 6)