pickle 如何创建一个实例来无视构造函数?
How does pickle create an instance in defiance of the constructor?
我的最终目标是让 class 具有常规构造函数,但还有第二个构造函数,可用于创建 class.
的部分实例化版本
class Foo(object):
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
def create_partial(self, **kwargs):
self.foo = kwargs.get('foo', None)
self.bar = kwargs.get('bar', None)
我注意到 pickle 以某种方式实现了这一点。您可以编写仅处理其中一个参数的 __getstate__
和 __setstate__
函数,它会忽略您尚未定义其中一个参数的事实。例如
class Foo(object):
def__init__(self, foo, bar):
self.foo = foo
self.bar = bar
def __getstate__(self):
return {'foo': self.foo}
def __setstate__(self, d):
self.foo = d['foo']
然后我可以 pickle 和 unpickle 一个实例来得到一个半实例化的对象
myfoo = pickle.loads(pickle.dumps(Foo(1,2)))
print(myfoo.foo) # 1
print(myfoo.bar) # throws AttributeError
type(myfoo) # __main__.Foo
所以,我的问题是,它如何设法获得 class 的空白实例,将其实例化一半并让它仍然报告其类型为 Foo,此外,如果没有必须经过泡菜?
P.S。我知道想要做这件事很疯狂,但我想知道如何
您可以调用 Foo.__new__(Foo)
来创建您的对象,而无需通过 __init__
。
当您 运行 Foo()
时,我们认为这是调用 Foo.__init__()
。但实际上,在此之前还有一个额外的步骤,即创建对象。 foo = Foo(a, b, c)
大致相当于
foo = Foo.__new__(Foo, a, b, c)
foo.__init__(a, b, c)
__new__
是一个很少使用的魔术方法,它实际上构造对象。您几乎不需要重写它(重写它的最常见用例是在子类化 float
等内置类型时),并且大多数 类 继承默认值 object.__new__
。我们可以直接调用后一个函数。
# Assuming that Foo doesn't override __new__
myfoo = Foo.__new__(Foo)
# Or, to be extra safe
myfoo = object.__new__(Foo)
请注意,__new__
将预期的类型作为第一个参数,因此即使我们调用 object.__new__
,我们仍然会得到 Foo
,因为我们将 Foo
传递为参数。在此过程中没有施工人员受到伤害。
我的最终目标是让 class 具有常规构造函数,但还有第二个构造函数,可用于创建 class.
的部分实例化版本class Foo(object):
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
def create_partial(self, **kwargs):
self.foo = kwargs.get('foo', None)
self.bar = kwargs.get('bar', None)
我注意到 pickle 以某种方式实现了这一点。您可以编写仅处理其中一个参数的 __getstate__
和 __setstate__
函数,它会忽略您尚未定义其中一个参数的事实。例如
class Foo(object):
def__init__(self, foo, bar):
self.foo = foo
self.bar = bar
def __getstate__(self):
return {'foo': self.foo}
def __setstate__(self, d):
self.foo = d['foo']
然后我可以 pickle 和 unpickle 一个实例来得到一个半实例化的对象
myfoo = pickle.loads(pickle.dumps(Foo(1,2)))
print(myfoo.foo) # 1
print(myfoo.bar) # throws AttributeError
type(myfoo) # __main__.Foo
所以,我的问题是,它如何设法获得 class 的空白实例,将其实例化一半并让它仍然报告其类型为 Foo,此外,如果没有必须经过泡菜?
P.S。我知道想要做这件事很疯狂,但我想知道如何
您可以调用 Foo.__new__(Foo)
来创建您的对象,而无需通过 __init__
。
当您 运行 Foo()
时,我们认为这是调用 Foo.__init__()
。但实际上,在此之前还有一个额外的步骤,即创建对象。 foo = Foo(a, b, c)
大致相当于
foo = Foo.__new__(Foo, a, b, c)
foo.__init__(a, b, c)
__new__
是一个很少使用的魔术方法,它实际上构造对象。您几乎不需要重写它(重写它的最常见用例是在子类化 float
等内置类型时),并且大多数 类 继承默认值 object.__new__
。我们可以直接调用后一个函数。
# Assuming that Foo doesn't override __new__
myfoo = Foo.__new__(Foo)
# Or, to be extra safe
myfoo = object.__new__(Foo)
请注意,__new__
将预期的类型作为第一个参数,因此即使我们调用 object.__new__
,我们仍然会得到 Foo
,因为我们将 Foo
传递为参数。在此过程中没有施工人员受到伤害。