len(object)还是hasattr(object, __iter__}?
(以下内容与python3有关,如果这很重要的话。)
这是我写的代码(简化版):
class MyClass: def __init__(self): self.__some_var = [] @property def some_var(self): return self.__some__var @some_var.setter def some_var(self, new_value): if hasattr(new_value, '__iter__'): self.__some_var = new_value else: self.__some_var.append(new_value)
我想在设置值的时候,如果有多个“值”(也就是说,如果new_value是一个可迭代的对象,在我的情况下是一些不可迭代的对象),就进行替换;如果只有一个“值”,就进行添加。我对hasattr的性能有点担心,所以我在想是否应该使用这个设置器:
@some_var.setter def some_var(self, *args): if len(args) > 1: self.__some_var = args else: self.__some_var.append(args)
谢谢你的关注!
3 个回答
0
从效率的角度来看:
- hasattr() 在最糟糕的情况下是 O(1),也就是常数时间。
- append() 在最糟糕的情况下也是 O(1),同样是常数时间。
2
另一种选择可能是鸭子类型:
在这里,我假设你想要把可迭代对象评估出来(也就是变成一个列表),因为它可能是一个迭代器,你需要立即展开它以便保存。
@some_var.setter
def some_var(self, new_value):
try:
self.__some_var = list(new_value)
except TypeError:
self.__some_var.append(new_value)
在这里,我们期望如果 new_value
不是可迭代的,使用 list()
会抛出 ValueError
。针对你在 S.Lott 的回答下的评论,我觉得使用 hasattr 其实也不算是真正的鸭子类型风格。
4
使用 hasattr
并不会带来什么“性能损失”。它的速度非常快,你几乎很难去测量它的影响。
请不要为自己的属性使用 __
(双下划线)。这样会让其他人感到困惑。
通常来说,使用 collections
中的抽象基类来处理这类事情是最好的选择。
if isinstance( arg, collections.Sequence ):
self._some_var = list(arg)
else:
self._some_var.append( arg )
这样做会让你的代码更有效,因为它能更清晰地表达你的意图。