2015-04-21 3 views
1

При создании объектов результата в классе можно использовать __slots__ в этом примере? Я думал, что я мог заставить его работать, передавая '__slots__' в словарь для третьего аргумента type:Создание динамического класса с типом и __slots__?

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

Есть ли лучший способ сделать это? Или мне нужно определить явный класс для этого?

ответ

1

Нет, я не думаю, что есть способ использовать трехпараметрическую форму type для создания объекта с помощью __slots__; за the docs:

Dict словаря [третьего параметра] является пространством имен, содержащий определения для тела класса и становится атрибутом __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 

    ... 

Вы могли бы упростить свойству немного с list comprehension тоже.

+1

Это сработало красиво! Мне удалось значительно уменьшить размер объектов результата, используя namedtuple. Спасибо! – crmackey

7

Это вполне возможно динамически создавать классы с прорезями:

>>> 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 идеально подходит для работы, поэтому придерживайтесь этого:

+0

Интересно, это полезно знать. Спасибо, что поделился!И да, я все еще придерживаюсь 'namedtuple', он работает хорошо для меня. – crmackey

Смежные вопросы