动态 class 创建类型和 __slots__?
Dynamic class creation with type and __slots__?
在 class 中创建结果对象时,是否可以在此示例中使用 __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__
。由于可能有数百个结果对象,我只想保存上面列出的四个属性 space.
示例:
>>> rev = GeocodeResult(r, 'reverseGeocode')
>>> result = rev.results[0]
>>> result.__slots__
['address', 'score', 'location', 'attributes']
>>> hasattr(result, '__dict__')
True
>>>
有更好的方法吗?或者我是否必须定义一个明确的 class 来处理这个问题?
我不确定您是否需要动态创建它;为什么不用 __slots__
定义 class 一次,因为它们看起来都一样,只是 return 个实例列表?
或者,我倾向于为此使用 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 稍微简化 属性。
动态创建 类 插槽是完全可能的:
>>> 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 非常适合这项工作,所以请坚持使用:)
在 class 中创建结果对象时,是否可以在此示例中使用 __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__
。由于可能有数百个结果对象,我只想保存上面列出的四个属性 space.
示例:
>>> rev = GeocodeResult(r, 'reverseGeocode')
>>> result = rev.results[0]
>>> result.__slots__
['address', 'score', 'location', 'attributes']
>>> hasattr(result, '__dict__')
True
>>>
有更好的方法吗?或者我是否必须定义一个明确的 class 来处理这个问题?
我不确定您是否需要动态创建它;为什么不用 __slots__
定义 class 一次,因为它们看起来都一样,只是 return 个实例列表?
或者,我倾向于为此使用 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 稍微简化 属性。
动态创建 类 插槽是完全可能的:
>>> 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 非常适合这项工作,所以请坚持使用:)