在 Python 中,__init__
和 __new__
是两个在类的实例化过程中发挥重要作用的方法,但它们各自的作用和使用场景是不同的。
概念区别
__new__
__new__
是一个静态方法,用于创建实例。它是类的实例化过程中被调用的第一个方法。__new__
接受类本身(cls)和其他参数,并返回一个实例。一般情况下,除非你有特殊需求,你可能很少需要覆盖 __new__
方法,写一些底层框架代码的时候可能会用上。
__init__
__init__
是实例初始化方法。它在 __new__
创建实例后被调用,用于初始化实例的属性和设置状态。__init__
返回 None,它不负责返回实例,也就是说__init__
中的self
参数其实是__new__
方法的返回值。
以下是一个简单示例,展示了__new__
和 __init__
的使用与区别:
class MyClass:
def __new__(cls, *args, **kwargs):
print("Calling __new__")
instance = super(MyClass, cls).__new__(cls)
# 在这里,你可以控制实例的创建,比如使用单例模式或者工厂模式
return instance
def __init__(self, value):
print("Calling __init__")
self.value = value
# 创建实例
my_instance = MyClass(42)
# Outputs
# Calling __new__
# Calling __init__
__new__
方法首先被调用,负责创建实例,然后 __init__
方法负责初始化实例。
常用使用场景
__new__
的使用
new 方法在 Python 中可以用于控制类的实例创建过程,包括实现单例模式、工厂模式、缓存实例以及预防不合适的实例化等。以下是每个使用场景的代码示例:
单例模式
在单例模式中,__new__
方法确保类只会有一个实例,并返回同一个实例给每次实例化调用,这个是__new__
最常用的场景。
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
# 使用示例
s1 = Singleton()
s2 = Singleton()
print(s1 == s2) # 输出 True,说明两者是同一个实例
工厂模式
在工厂模式中,new 方法可以根据传入的参数返回不同类型的实例。
class AuthStrategy:
def authenticate(self):
raise NotImplementedError
class WechatStrategy(AuthStrategy):
def authenticate(self):
return "Wechat authenticate"
class EmailStrategy(AuthStrategy):
def authenticate(self):
return "Email authenticate"
class AnimalFactory:
def __new__(cls, auth_type):
if auth_type == 'wechat':
return WechatStrategy()
elif auth_type == 'email':
return EmailStrategy()
else:
raise ValueError("Unknown animal type")
# 使用示例
w = AnimalFactory('wechat')
e = AnimalFactory('email')
print(w.authenticate()) # 输出 "Wechat authenticate"
print(e.authenticate()) # 输出 "Email authenticate"
缓存实例
在缓存实例中,new 方法可以缓存创建的实例,并在重复创建时返回缓存的实例。
class CacheObject:
_cache = {}
def __new__(cls, key):
if key in cls._cache:
return cls._cache[key]
else:
instance = super(CacheObject, cls).__new__(cls)
cls._cache[key] = instance
return instance
# 使用示例
obj1 = CacheObject('key1')
obj2 = CacheObject('key1')
print(obj1 == obj2) # 输出 True,说明两者是同一个实例
预防不合适的实例化
在预防不合适的实例化场景中,new 方法可以通过抛出异常来防止实例化不合适的对象。
class RestrictedInstantiation:
def __new__(cls, flag):
if not flag:
raise ValueError("flag必须为True")
return super(RestrictedInstantiation, cls).__new__(cls)
# 使用示例
try:
restricted_instance = RestrictedInstantiation(False)
except ValueError as e:
print(e) # 输出 "flag必须为True"
a = RestrictedInstantiation(True)
print("成功创建") # 这将被打印,因为 flag 是 True
以上示例展示了 __new__
方法在不同使用场景中的应用,包括单例模式、工厂模式、缓存实例和预防不合适的实例化。
__init__
的使用
__init__
方法在 Python 中用于初始化类的实例。这是类实例化后的第一个方法,它主要用于设置实例的属性和初始化实例的状态,将接下来可能需要的数据或者资源(文件)都准备好。以下是 __init__
方法的不同使用场景及代码示例:
初始化实例属性
__init__
方法通常用于初始化实例的属性,以便实例在创建时具备必要的状态。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# 使用示例
person = Person("Mike", 30)
print(person.name) # 输出 "Mike"
print(person.age) # 输出 30
参数验证和处理
__init__
方法可以用于验证和处理传入的参数,以确保实例属性符合预期。
import re
class Account:
# 定义正则表达式来验证电子邮件格式
EMAIL_PTN = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
def __init__(self, email):
if not self.is_valid_email(email):
raise ValueError("不正确email格式")
self.email = email
@staticmethod
def is_valid_email(email: str) -> bool:
# 使用正则表达式匹配电子邮件地址
return re.match(Account.EMAIL_PTN, email) is not None
# 使用示例
try:
account = Account("111")
except ValueError as e:
print(e) # 输出 "不正确email格式"
valid_account = Account("xmishu@xmishu.com")
print(valid_account.email) # 输出 "xmishu@xmishu.com"
计算派生属性
__init__
方法可以用于根据输入参数计算派生附加属性,从而在实例创建时提供额外的信息。
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
self.area = length * width # 计算面积
self.perimeter = 2 * (length + width) # 计算周长
# 使用示例
rect = Rectangle(4, 30)
print(rect.area) # 输出 120
print(rect.perimeter) # 输出 68
通过这些例子,你可以看到 __init__
方法在初始化实例属性、验证和处理参数、计算派生属性等场景中的应用。
总结
__new__
是一个静态方法,用于创建实例(不一定是新的)并返回这个实例;__init__
是实例初始化方法,设置属性初始状态,它返回的是None。