flyfish
@ 符号在 Python 中用于装饰器语法糖,提供了一种简洁而强大的方式来修改或扩展函数和方法的行为。
Meta Llama 3 里面有
@staticmethod
@dataclass
@torch.inference_mode()
@staticmethod静态方法属于类,而不是类的实例。可以在不创建类的实例的情况下调用静态方法。
在 Python 中,@staticmethod 是一个装饰器,用于定义静态方法。静态方法属于类,而不是类的实例。也就是说,可以在不创建类的实例的情况下调用静态方法。静态方法通常用于实现与类相关,但不依赖于实例状态的方法。
静态方法有以下特点:
假设我们有一个类 MathOperations,它包含一些数学运算的方法。某些运算,比如计算两个数的和,可以独立于实例存在。我们可以将这样的函数定义为静态方法。
class MathOperations:
@staticmethod
def add(a, b):
return a + b
@staticmethod
def multiply(a, b):
return a * b
# 调用静态方法
result_add = MathOperations.add(3, 5)
result_multiply = MathOperations.multiply(4, 6)
print(f"Addition Result: {result_add}") # 输出: Addition Result: 8
print(f"Multiplication Result: {result_multiply}") # 输出: Multiplication Result: 24
在这个例子中:
静态方法适用于以下情况:
class DateUtils:
@staticmethod
def is_leap_year(year):
if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
return True
else:
return False
@staticmethod
def days_in_month(month, year):
days_in_month = [31, 29 if DateUtils.is_leap_year(year) else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
return days_in_month[month - 1]
# 调用静态方法
print(DateUtils.is_leap_year(2020)) # 输出: True
print(DateUtils.days_in_month(2, 2020)) # 输出: 29
print(DateUtils.days_in_month(2, 2021)) # 输出: 28
在这个例子中:
顺便介绍
@property:用于将方法转换为属性,允许以属性的方式访问和设置方法的值。
@contextmanager:用于创建上下文管理器,简化资源管理。
@classmethod:用于定义类方法,允许在类本身而不是实例上调用方法。
@property 装饰器用于将类的方法转换为属性。它允许你使用类似于访问属性的语法来调用方法。这对于封装对象的内部数据并控制其访问和修改非常有用。
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("Radius cannot be negative")
self._radius = value
@property
def area(self):
return 3.14159 * self._radius ** 2
# 使用属性
circle = Circle(5)
print(circle.radius) # 输出: 5
print(circle.area) # 输出: 78.53975
circle.radius = 10
print(circle.area) # 输出: 314.159
try:
circle.radius = -5 # 将引发 ValueError
except ValueError as e:
print(e) # 输出: Radius cannot be negative
在这个示例中,radius 和 area 都是属性。通过 @property 和 @radius.setter,我们能够控制对 _radius 属性的访问和修改。
@contextmanager 是 contextlib 模块中的一个装饰器,用于简化上下文管理器的创建。它允许你使用 with 语句,提供一种干净的方式来管理资源(如文件、网络连接等)。
from contextlib import contextmanager
@contextmanager
def open_file(file_name, mode):
f = open(file_name, mode)
try:
yield f
finally:
f.close()
# 使用上下文管理器
with open_file('test.txt', 'w') as f:
f.write('Hello, World!')
# 自动关闭文件
在这个示例中,open_file 函数使用 @contextmanager 装饰器将其转换为一个上下文管理器。with 语句在进入和退出时分别调用 yield 之前和之后的代码,从而确保文件在使用后被自动关闭。
@classmethod 装饰器用于定义类方法。类方法的第一个参数是类本身(通常命名为 cls),而不是实例。类方法可以用于创建工厂方法或执行需要访问类本身而不是实例的操作。
class MyClass:
class_variable = 0
def __init__(self, instance_variable):
self.instance_variable = instance_variable
@classmethod
def increment_class_variable(cls):
cls.class_variable += 1
return cls.class_variable
# 使用类方法
print(MyClass.class_variable) # 输出: 0
MyClass.increment_class_variable()
print(MyClass.class_variable) # 输出: 1
instance = MyClass(10)
print(instance.increment_class_variable()) # 输出: 2
在这个示例中,increment_class_variable 是一个类方法,它操作类变量 class_variable。通过 @classmethod 装饰器,我们可以在不创建类实例的情况下调用该方法。
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
# 调用函数
say_hello()
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
在这个示例中:
你可以将多个装饰器应用到同一个函数或方法上。这时,装饰器从内向外依次应用。
def decorator1(func):
def wrapper():
print("Decorator 1")
func()
return wrapper
def decorator2(func):
def wrapper():
print("Decorator 2")
func()
return wrapper
@decorator1
@decorator2
def say_hello():
print("Hello!")
# 调用函数
say_hello()
Decorator 1
Decorator 2
Hello!
在这个示例中,say_hello 函数首先被 decorator2 装饰,然后再被 decorator1 装饰。调用 say_hello 时,会先执行 decorator1 的代码,再执行 decorator2 的代码,最后执行原始函数。
@torch.inference_mode() 是 PyTorch 提供的一个装饰器,用于将特定的代码块包裹在推理模式中。推理模式主要用于前向传播(inference)而不需要计算梯度,从而提高性能和节省内存。
功能和作用
禁用梯度计算:推理模式会禁用梯度计算,从而减少内存消耗和计算开销。与 torch.no_grad() 类似,但提供了一些额外的优化。
优化内存使用:在推理模式下,PyTorch 会进行一些内部优化,进一步减少内存使用。
只用于前向传播:适用于不需要反向传播的场景,如模型推理和评估。
使用方法
你可以将 @torch.inference_mode() 装饰器应用于函数,从而使得该函数在推理模式下执行。
import torch
# 创建一个简单的神经网络模型
class SimpleModel(torch.nn.Module):
def __init__(self):
super(SimpleModel, self).__init__()
self.linear = torch.nn.Linear(10, 1)
def forward(self, x):
return self.linear(x)
model = SimpleModel()
# 创建输入张量
input_tensor = torch.randn(1, 10)
@torch.inference_mode()
def predict(model, input_tensor):
return model(input_tensor)
# 调用推理函数
output = predict(model, input_tensor)
print(output)
在这个示例中,predict 函数被 @torch.inference_mode() 装饰,这意味着在执行该函数时,梯度计算被禁用,从而节省内存和计算资源。
与 torch.no_grad() 的区别
虽然 @torch.inference_mode() 和 torch.no_grad() 都用于禁用梯度计算,但 torch.inference_mode() 进行了一些额外的优化,使得它在推理时更高效。
示例:使用 torch.no_grad()
def predict_no_grad(model, input_tensor):
with torch.no_grad():
return model(input_tensor)
# 调用推理函数
output_no_grad = predict_no_grad(model, input_tensor)
print(output_no_grad)
两者的主要区别在于,torch.inference_mode() 作为装饰器可以直接应用于函数,使得代码更加简洁,而 torch.no_grad() 则需要使用 with 语句显式地包裹代码块。