你为什么使用 Python?对很多人来说,答案可能只是因为大家都在用,但这真的不应该成为使用它的理由。Python 是一种功能强大的通用编程语言,拥有简洁的语法,并以其独特的Pythonic数据与逻辑处理方式而闻名。正因如此,它才成为数据科学、机器学习和 AI 领域的首选语言。
Python 很容易上手,但需要花上很多年精进技能,深入理解语言核心,才能从初学者成长为编写高效、可维护系统的专业开发者。
本文探讨五个必知的Python概念,帮助大家成为具有Pythonic编程思想的开发者。
1. 列表推导式(List Comprehensions)与生成器表达式(Generator Expressions)
Python 以可读性著称。列表推导式允许你用一行代码替代臃肿的循环。不过,更专业的技巧在于:知道什么时候该使用生成器表达式,从而节省内存。
笨重的写法(For 循环)
先看看这种低效、缺乏 Python 风格的写法:
numbers = range(1000000)squared_list = []for n in numbers: if n % 2 == 0: squared_list.append(n ** 2)
Pythonic 写法(列表推导式)
现在看看更符合 Python 风格的解决方案:
# 更简洁,执行更快squared_list = [n ** 2 for n in numbers if n % 2 == 0]# 必须掌握的进阶技巧:生成器表达式# 如果只需要遍历一次,不需要整个列表常驻内存:squared_gen = (n ** 2 for n in numbers if n % 2 == 0)
输出:
List size: 4,167,352 bytesGenerator size: 200 bytes
为什么这很重要?不仅仅是因为Python 就该这么写。
- 列表推导式通常比 .append() 更快
- 生成器表达式(使用圆括号)是“惰性计算”的:它们一次只生成一个元素,因此可以处理超大规模数据,而不会耗尽系统内存。
下面看看如何逐个获取生成器中的值:
numbers = range(1000000)squared_gen = (n ** 2 for n in numbers if n % 2 == 0)# 只有在请求时才会计算值,而不是一次性全部生成print(next(squared_gen))print(next(squared_gen))print(next(squared_gen))
输出:
2. 装饰器(Decorators)
装饰器是一种无需修改函数或类代码,就能改变其行为的方法。你可以把它理解为“包裹函数的包装器”。
笨重的写法
如果你想记录多个函数的执行时间,可能会在每个函数手动加入计时代码:
import timedef process_data(): start = time.time() # ... function logic ... end = time.time() print(f"process_data took {end - start:.4f}s")def train_model(): start = time.time() # ... function logic ... end = time.time() print(f"train_model took {end - start:.4f}s")def generate_report(): start = time.time() # ... function logic ... end = time.time() print(f"generate_report took {end - start:.4f}s")
同样的代码重复出现很多次。
Pythonic 写法
下面是更优雅的解决方案:
import timefrom functools import wrapsdef timer_decorator(func): @wraps(func) def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print(f"{func.__name__} took {end - start:.4f}s") return result return wrapper@timer_decoratordef heavy_computation(): return sum(range(10**7))heavy_computation()
输出:
heavy_computation took 0.0941s
可以看到,timer_decorator() 包裹了 heavy_computation() 函数。
当后者被调用时,它自动获得了前者提供的计时功能。
装饰器体现了 “DRY(Don't Repeat Yourself,不要重复自己)” 原则。
在生产环境,它们广泛用于:
- 日志记录(logging)
- 身份验证(authentication)
- 缓存(caching)
3. 上下文管理器(Context Managers)与 with 语句
管理文件、数据库连接、网络套接字等资源时,最容易产生 Bug。
例如,如果你忘记关闭文件,可能会:
- 导致内存泄漏
- 锁定文件,影响其他进程使用
笨重的写法
f = open("data.txt", "w")try: f.write("Hello World")finally: # 很容易忘记! f.close()
Pythonic 写法
with 语句能更优雅地完成同样的事:
# 即使发生错误,文件也会被自动关闭with open("data.txt", "w") as f: f.write("Hello World")
这种写法不仅更简洁,而且逻辑更清晰,更重要的是:
- 初始化(setup)
- 清理(teardown)
都会被可靠地自动处理。
在数据工程任务中,这对于:
- SQL 数据库连接
- 大规模 IO(输入输出)任务
尤其重要。
4. 精通 *args 与 **kwargs
有时候,你并不知道函数会接收多少参数。
Python 使用“打包操作符(packing operators)”优雅地解决了这个问题。
即使你还是初学者,也可能已经见过它们。
Pythonic 示例
def make_profile(name, *tags, **metadata): # name 是普通命名参数 print(f"User: {name}") # tags 是元组 print(f"Tags: {tags}") # metadata 是字典 print(f"Details: {metadata}")make_profile( "Alice", "DataScientist", "Pythonist", location="NY", seniority="Senior")
输出:
User: AliceTags: ('DataScientist', 'Pythonist')Details: {'location': 'NY', 'seniority': 'Senior'}
这里:
用于收集额外的位置参数(非关键字参数),并打包成一个元组,适用于不确定会传入多少个参数时。
用于收集额外的关键字参数,并打包成一个字典,适用于可选配置、命名参数。
这是像 Scikit-Learn 或 Matplotlib 这类灵活库背后的核心机制之一。它让函数能够接收任意数量的配置参数,从而使代码更具扩展性和适应性。
5. Dunder 方法(魔术方法 / Magic Methods)
Dunder是 “double underscore(双下划线)” 的缩写,例如__init__。
官方称其为特殊方法(special methods),但大多数开发者更喜欢称它们为魔术方法(magic methods)。
这些方法让你的自定义对象能够模拟 Python 内置对象的行为。
Pythonic 示例
class Dataset: def __init__(self, data): self.data = data def __len__(self): return len(self.data) def __str__(self): return f"Dataset with {len(self.data)} items"# 创建数据集实例my_data = Dataset([1, 2, 3])# 调用 __len__print(len(my_data))# 调用 __str__print(my_data)
输出:
通过实现内置的 __len__ 与 __str__ 方法,我们的自定义类自动获得了很多实用能力。
Dunder 方法是 Python 对象协议(object protocol)的核心。
例如:
等方法可以让你的类表现得像:
- 列表(list)
- 字典(dict)
- 函数(function)
从而构建出更自然、更直观的 API。
总结
掌握这五个概念,意味着你正在从写脚本迈向构建软件。
通过:
- 使用列表推导式提升性能
- 使用装饰器保持逻辑整洁
- 使用上下文管理器保证资源安全
- 使用 *args/**kwargs 提升灵活性
- 使用 Dunder 方法增强对象能力
你将为进一步深入 Python 打下坚实基础。
参考
https://www.kdnuggets.com/5-must-know-python-concepts