如果你学习 Python 有一段时间了,你可能会遇到一些比较迷惑功能。它们看起来比较复杂,实际非常好用的技巧。
这些功能都是非常出色的工具,只要你了解它们,就能让你的代码更简洁、更高效、更优雅。
我们用简单的语言分解其中的 10 个功能。
1. 装饰器:函数的超能力
装饰器看起来像魔法。
你在函数上方添加一个 @something
,突然间,函数的行为就变了。这是怎么回事呢?
装饰器可以让你在不修改代码的情况下修改或扩展函数或方法的行为。
将它们视为添加额外功能的一种方式。
示例:
def greet_decorator(func):
def wrapper():
print("Hello!")
func()
print("Goodbye!")
return wrapper
@greet_decorator
def say_name():
print("My name is Python.")
say_name()
当你调用 say_name()
时,它将被封装在装饰器的 wrapper
函数中。它会打印 “Hello!”,运行 say_name
,然后打印 “Goodbye!”。
装饰器非常适合日志记录、身份验证或测量执行时间。
2. 生成器 懒惰而高效的迭代器
生成器使用 yield
而不是 return
,而且它们不会同时运行。有什么意义?
生成器只在需要时才一次生成一个项目。
这对于处理大型数据集或无限序列非常有用,而且不会占用内存。
def count_up_to(n):
count = 1
while count <= n:
yield count
count += 1
for number in count_up_to(5):
print(number)
count_up_to
并不是创建一个完整的数字列表,而是即时生成数字。
这就像一个神奇的水龙头,能根据你的要求倒出数字。
3. 上下文管理器和 with
语句:像专家一样处理资源
with
语句似乎是一种打开文件的花哨方法。
为什么不直接使用 open()
就可以了呢?
上下文管理器会自动处理设置和清理工作,防止资源泄漏,比如忘记关闭文件。
with open("example.txt", "r") as file:
content = file.read()
print(content)
文件被打开、读取,然后在退出 with
块时自动关闭。
不再调用file.close()
,不再意外锁定文件。
你甚至可以使用 contextlib
或在类中定义 __enter__
和 __exit__
方法来创建自己的上下文管理器。
方便管理数据库连接或网络资源。
4. 推导式
列表推导式和它们的同类(dict、set 和生成器理解)看起来像难以理解的速记。
但综合法能让你简洁地创建集合,通常能取代多行代码。
squares = [x**2 for x in range(10) if x % 2 == 0]
print(squares) # Output: [0, 4, 16, 36, 64]
这个单行本为 0 到 9 之间的偶数建立了一个正方形列表。
一旦你掌握了它们的窍门,你就会想,如果没有它们,你是怎么生活的。
5. 海象运算符(:=
):表达式中的赋值
它在代码中看起来就像一个侧向的笑脸。它到底在做什么?
作为表达式的一部分,海象运算符可以为变量赋值。
这可以让你的代码更简短、更易读。
numbers = [10, 20, 30, 40]
if (n := len(numbers)) > 3:
print(f"Too many numbers ({n})!")
len(numbers)
结果将赋值给 n
,并在条件中使用。无需计算两次。
6. 类型提示:让代码更易于阅读和调试
Python 是一种动态类型语言,那么我们为什么要添加类型呢?
类型提示提高了代码的可读性,并能及早发现错误。它们不会在运行时强制执行,但可以帮助列式器和集成开发环境等工具。
def greet(name: str) -> str:
return f"Hello, {name}!"
print(greet("Python"))
类型提示告诉你 name
应该是字符串,函数返回字符串。
这就像是为未来的你(或你的队友)提供了一个指南。
7. Metaclasses元类 控制类的行为
元类就像是 “类中之类”。
元类可以让你控制类的创建方式。它们对于执行规则或注入行为非常有用。
class Meta(type):
def __new__(cls, name, bases, dct):
if 'required_attribute' not in dct:
raise TypeError("Missing required_attribute")
return super().__new__(cls, name, bases, dct)
class MyClass(metaclass=Meta):
required_attribute = True
元类在创建 MyClass
时会检查 required_attribute
是否存在。如果不存在,就会引发错误。
这就像是类的质量控制。
8. @staticmethod
和 @classmethod
装饰器:灵活的类方法
既然普通方法也能正常工作,我们为什么还需要它们呢?
这些装饰器提供了定义方法的不同方法,这些方法不需要访问实例属性(@staticmethod
),也不需要使用类本身(@classmethod
)。
class MyClass:
@staticmethod
def static_method():
return "I don’t need an instance!"
@classmethod
def class_method(cls):
return f"I work with {cls}!"
print(MyClass.static_method())
print(MyClass.class_method())
static_method
不关心类或实例,而 class_method
可以访问它所属的类。
这对实用函数或替代构造函数很有用。
9. __slots__
:在类中节省内存
__slots__
看起来限制了灵活性,这与 Python 的动态特性背道而驰。
通过定义 __slots__
,你可以告诉 Python 为属性分配固定数量的内存,从而在大型应用程序中节省内存。
class MyClass:
__slots__ = ['name', 'age']
def __init__(self, name, age):
self.name = name
self.age = age
MyClass
的实例只能有 name
和 age
属性,而且占用内存更少。
非常适合有许多对象的情况。
10. Descriptors描述符 可重复使用的属性逻辑
它们涉及的方法如 __get__
、__set__
和 __delete__
,让人感觉晦涩难懂。
但描述符可以让你重复使用管理属性的逻辑。可以把它们看作高级属性装饰器。
class Descriptor:
def __get__(self, instance, owner):
return instance._value
def __set__(self, instance, value):
instance._value = value * 2
class MyClass:
attr = Descriptor()
def __init__(self, value):
self._value = value
obj = MyClass(10)
obj.attr = 20
print(obj.attr) # Output: 40
描述符在赋值前会将数值加倍,这样就不必在多个地方重复这一逻辑。