第八章类与对象(创建不调用 init 方法的实例)

创建不调用 init 方法的实例

问题

       你想创建一个实例,但是希望绕过执行 __init__() 方法。

解决方案

       可以通过 __new__() 方法创建一个未初始化的实例。例如考虑如下这个类:

class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day

def __str__(self):
return f'{self.year}年{self.month}月{self.day}日'

  下面演示如何不调用 __init__() 方法来创建这个 Date 实例:

d = object.__new__(Date)  #为对象d开辟内存地址
print(d.year)
# AttributeError: 'Date' object has no attribute 'year'

  结果可以看到,这个 Date 实例的属性 year 还不存在,所以你需要手动初始化:

data = {"year": 2021, "month": 1, "day": 19}
for k, v in data.items():
    setattr(d, k, v)
print(d)
# 2021年1月19日
print(d.day)
# 19

讨论

       当我们在反序列对象或者实现某个类方法构造函数时需要绕过 __init__() 方法来创建对象。例如,对于上面的 Date 来讲,有时候你可能会像下面这样定义一个新的构造函数 today() :

from time import localtime


class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    def __str__(self):
        return f'{self.year}年{self.month}月{self.day}日'

    @classmethod
    def today(cls):
        d = object.__new__(cls)
        t = localtime()
        d.year = t.tm_year
        d.month = t.tm_mon
        d.day = t.tm_mday
        return d


print(Date.today())
# 2021年1月19日

  同样,在你反序列化 JSON 数据时产生一个如下的字典对象:

data = { 'year': 2021, 'month': 1, 'day': 19 }

  如果你想将它转换成一个 Date 类型实例,可以使用上面的技术。

       当你通过这种非常规方式来创建实例的时候,最好不要直接去访问底层实例字典,除非你真的清楚所有细节。否则的话,如果这个类使用了 __slots__ 、properties、descriptors 或其他高级技术的时候代码就会失效。而这时候使用 setattr() 方法会让你的代码变得更加通用。

posted @ 2021-01-19 09:14  wangshanglinju  阅读(189)  评论(0)    收藏  举报