[英]Use cases for `A.__new__(B)` i.e. “using one class to make another” in python
I take我拿
A.__new__(B)
to mean "use the A
object-creating method to make an (uninitialized) B
object".意思是“使用A
对象创建方法来制作(未初始化的) B
对象”。
What are some use cases where I can/should use such abilities?在哪些用例中我可以/应该使用这些能力?
The question is about when could one use the some_cls.__new__(some_other_cls)
capabilities问题是何时可以使用some_cls.__new__(some_other_cls)
功能
But since responders claim that the very use of __new__
is probably misled, I will show a situation where I'm (possibly misled) to think that using __new__
might be a good idea.但是由于响应者声称__new__
的使用可能被误导,我将展示一个我(可能被误导)认为使用__new__
可能是一个好主意的情况。
The actual context is that of json-serializing scikit-learn
models in such a way that an edge device can deserialize and run a target method (eg 'predict').实际的上下文是 json 序列化scikit-learn
模型的上下文,使得边缘设备可以反序列化并运行目标方法(例如“预测”)。 Two important aspects here: (1) scikit-learn
estimator classes' __init__
takes parameters concerning the fitting of a model, but the attributes needed to run the predict
method are dynamically made in fit
method, and (2) a light weight serialized model is preferable, and the edge device is probably running a light weight function (not the original scikit-learn
method.这里有两个重要方面:(1) scikit-learn
估计器类的__init__
采用与 model 的拟合有关的参数,但运行predict
方法所需的属性是在fit
方法中动态生成的,以及(2)轻量级序列化 Z20F35E630DAF44DFA4C3 更可取并且边缘设备可能正在运行轻量级 function (不是原来的scikit-learn
方法。
I hope the code below illustrates this situation sufficiently faithfully:我希望下面的代码足够忠实地说明这种情况:
class Greeter:
def __init__(self, greet):
self.greet = greet
def fit(self, this):
self.greet_this_ = self.greet + ' ' + this
def __call__(self):
if not hasattr(self, 'greet_this_'):
raise ValueError("Greeter not fit")
return self.greet_this_
obj = Greeter("hello")
obj.fit('world')
assert obj() == 'hello world'
Here's some serialization code:下面是一些序列化代码:
import json
def serialize(obj, needed_attrs):
return json.dumps({a: getattr(obj, a) for a in needed_attrs})
class MethodLess: ...
def deserialize(obj_json, cls=MethodLess):
obj = cls.__new__(cls) # make the (unintialized) instance
# Note: couldn't do obj = cls() because cls might need some inputs
for k, v in json.loads(obj_json).items(): # fill it with it's attributes
setattr(obj, k, v)
return obj
obj_json = serialize(obj, ['greet_this_'])
deserialized_obj = deserialize(obj_json, cls=Greeter)
assert deserialized_obj() == 'hello world' == obj()
But we don't even need the original class, just the method we need to call.但是我们甚至不需要原来的class,只需要我们需要调用的方法。
class MinimalGreeter:
def __call__(self):
if not hasattr(self, 'greet_this_'):
raise ValueError("Greeter not fit")
return self.greet_this_
obj_json = serialize(obj, ['greet_this_'])
deserialized_obj = deserialize(obj_json, cls=MinimalGreeter)
assert deserialized_obj() == 'hello world' == obj()
Equivalently, in functional form...等效地,以函数形式...
def call(self):
if not hasattr(self, 'greet_this_'):
raise ValueError("Greeter not fit")
return self.greet_this_
obj_json = serialize(obj, ['greet_this_'])
deserialized_obj = deserialize(obj_json, cls=MethodLess)
assert call(deserialized_obj) == 'hello world' == call(obj) == obj()
I can't think of any reason why you would want to call __new__
directly.我想不出您为什么要直接调用__new__
的任何原因。 But if you are asking why you might return a different type from __new__
, one example would be to return a proxy object or a different implementation based on what constructor arguments are passed.但是,如果您要问为什么可能从__new__
返回不同的类型,一个示例是返回代理 object 或基于传递的构造函数 arguments 的不同实现。 In other words it can be used as an alternative to the factory pattern.换句话说,它可以用作工厂模式的替代品。
EDIT: An example, as requested:编辑:一个例子,根据要求:
class _StandardSolver:
def solve(self, x):
print('Using standard algorithm')
return x + 1
class _SpecialSolver:
def solve(self, x):
print('Using special algorithm')
return x * x # Imagine this algorithm is much more complicated, relying on a lot of class state, etc.
class ComplicatedProblemSolver:
def __new__(cls, use_special_algo, *args, **kwargs):
if use_special_algo:
return _SpecialSolver(*args, **kwargs)
else:
return _StandardSolver(*args, **kwargs)
if __name__ == '__main__':
solver = ComplicatedProblemSolver(use_special_algo=True)
print('Solution:', solver.solve(5))
I would keep the details of how you (de)serialize an object in the class itself.我会在 class 本身中保留您如何(反)序列化 object 的详细信息。 Then deserialization can decode the JSON blob and extract the values necessary to be passed to __init__
.然后反序列化可以解码 JSON blob 并提取需要传递给__init__
的值。 For example:例如:
import json
class Greeter:
def __init__(self, greet):
self.greet = greet
def fit(self, this):
self.greet_this_ = self.greet + ' ' + this
def __call__(self):
if not hasattr(self, 'greet_this_'):
raise ValueError("Greeter not fit")
return self.greet_this_
def to_json(self):
return json.dumps({'greet': self.greet, 'greet_this_': self.greet_this_)
@classmethod
def from_json(cls, obj_json):
d = json.loads(obj_json)
obj = cls(d['greet'])
obj.fit(d['greet_this_'])
return obj
obj = Greeter("hello")
obj.fit('world')
assert obj() == 'hello world'
obj_json = obj.to_json()
deserialized_obj = Greeter.from_json(obj_json)
assert deserialized_obj() == 'hello world' == obj()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.