动态类创作类型和__slots__?(Dynamic class creation with typ

2019-10-22 18:47发布

当一个类中创建结果对象,是有可能使用__slots__在这个例子吗? 我以为我可以得到它通过传递工作'__slots__'到字典的第三个参数type

class GeocodeResult(object):
    """class to handle Reverse Geocode Result"""

    __slots__ = ['geometry', 'response', 'spatialReference',
                'candidates', 'locations', 'address', 'type', 'results']

    def __init__(self, res_dict, geo_type):
        RequestError(res_dict)
        self.response = res_dict
        self.type = 'esri_' + geo_type
        self.spatialReference = None
        self.candidates = []
        self.locations = []
        self.address = []
        if 'spatialReference' in self.response:
            self.spatialReference = self.response['spatialReference']

        # more stuff

    @property
    def results(self):
        results = []
        for result in self.address + self.candidates + self.locations:
            result['__slots__'] = ['address', 'score', 'location', 'attributes']
            results.append(type('GeocodeResult.result', (object,), result))
        return results

    def __len__(self):
        """get length of results"""
        return len(self.results)

对于results属性,我想建立小,重量轻的对象的列表与4个属性: ['address', 'score', 'location', 'attributes']

最终的目标是创建的,我甚至可以在插槽得到,但它仍然保持__dict__ 。 因为有可能是数百个结果的对象,我想只有上面列出节省空间的四个属性。

例:

>>> rev = GeocodeResult(r, 'reverseGeocode')
>>> result = rev.results[0]
>>> result.__slots__
['address', 'score', 'location', 'attributes']
>>> hasattr(result, '__dict__')
True
>>> 

是否有这样做的更好的办法? 还是我必须定义一个明确的类来处理呢?

Answer 1:

不,我不认为有任何方式使用的三个参数的形式type来创建一个对象__slots__ ; 每次的文档 :

所述字典的字典[第三参数]是包含用于类定义体的命名空间,成为__dict__属性。

我不知道你需要 ,虽然, 为什么不定义类__slots__一次,因为它们都似乎是相同的,只是返回实例的列表? 这就是说,我会倾向于使用collections.namedtuple此; 他们非常轻巧,还是给通过属性访问它的内容:

class GeocodeResult(object):
    """class to handle Reverse Geocode Result"""

    ...

    Result = namedtuple(
        'Result', 
        'address score location attributes',
    )

    @property
    def results(self):
        results = []
        for result in self.address + self.candidates + self.locations:
            results.append(self.Result(...))  # pass in the four relevant attributes
        return result

    ...

你可以简化属性有点用列表理解了。



Answer 2:

这是完全有可能与插槽动态创建类:

>>> C = type('C', (), {'__slots__': ('a', 'b')})
>>> C.a
<member 'a' of 'C' objects>
>>> dir(C())
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'a', 'b']
>>> vars(C())
Traceback (most recent call last):
  ...
TypeError: vars() argument must have __dict__ attribute

工作在Python 3和2。

你看到hasattr(result, '__dict__')评价True在你的榜样,因为通过返回的列表GecodeResult.results是一个类型列表,而不是实例的列表。 如果你说的result().__dict__ ,你会得到一个AttributeError

(另外值得注意的:在该列表中的每个类型股份名称“GeocodeResult.result”,但它们不是同一类型的results[0].__class__ == results[1].__class__False 。)

作为jonrsharpe指出,最好是只定义类型一次,并重新使用它,并且namedtuple是完美的工作,所以与坚持:)



文章来源: Dynamic class creation with type and __slots__?