簡體   English   中英

`A.__new__(B)` 的用例,即 python 中的“使用一個 class 制作另一個”

[英]Use cases for `A.__new__(B)` i.e. “using one class to make another” in python

我拿

A.__new__(B)

意思是“使用A對象創建方法來制作(未初始化的) B對象”。

在哪些用例中我可以/應該使用這些能力?

更多細節

問題是何時可以使用some_cls.__new__(some_other_cls)功能

但是由於響應者聲稱__new__的使用可能被誤導,我將展示一個我(可能被誤導)認為使用__new__可能是一個好主意的情況。

實際的上下文是 json 序列化scikit-learn模型的上下文,使得邊緣設備可以反序列化並運行目標方法(例如“預測”)。 這里有兩個重要方面:(1) scikit-learn估計器類的__init__采用與 model 的擬合有關的參數,但運行predict方法所需的屬性是在fit方法中動態生成的,以及(2)輕量級序列化 Z20F35E630DAF44DFA4C3 更可取並且邊緣設備可能正在運行輕量級 function (不是原來的scikit-learn方法。

我希望下面的代碼足夠忠實地說明這種情況:

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'

下面是一些序列化代碼:

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()

但是我們甚至不需要原來的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()

等效地,以函數形式...

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()

我想不出您為什么要直接調用__new__的任何原因。 但是,如果您要問為什么可能從__new__返回不同的類型,一個示例是返回代理 object 或基於傳遞的構造函數 arguments 的不同實現。 換句話說,它可以用作工廠模式的替代品。

編輯:一個例子,根據要求:

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))

我會在 class 本身中保留您如何(反)序列化 object 的詳細信息。 然后反序列化可以解碼 JSON blob 並提取需要傳遞給__init__的值。 例如:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM