获取某属性值为特定值的类实例
我相信我在找的这个东西一定有个专门的名字,如果没有,那也一定有很好的理由说明我想做的事情其实是个傻事。
不过无论如何,我在想有没有一种(半)内置的方法,可以找到某个类的实例,并且这个实例的某个属性被设置为特定的值。
举个例子:
class Klass(object):
def __init__(self, value):
self.value = value
def square_value(self):
return self.value * self.value
>>> a = Klass(1)
>>> b = Klass(2)
>>> instance = find_instance([a, b], value=1)
>>> instance.square_value()
1
>>> instance = find_instance([a, b], value=2)
>>> instance.square_value()
4
我知道我可以写一个函数,去遍历所有的Klass实例,然后返回那些属性值符合要求的实例。但另一方面,我觉得这种功能应该在Python里已经存在了,如果没有,那一定有很好的理由说明它不应该存在。换句话说,我在这里想做的事情,可能有更好的方法来实现。
(当然,我并不是在找一种方法来计算平方值。上面的例子只是我想寻找的构造的一个示例。)
2 个回答
如果你只想找到一个匹配的实例,Ord的答案有一个更高效的版本,代码如下:
def find_instance(fn, objs):
all_matches = (o for o in objs if fn(objs))
return next(all_matches, None)
instance = find_instance(lambda x: x.value == 1, [a, b])
这个方法会在找到第一个匹配项后立即停止搜索(如果你的测试函数比较耗时或者列表很大,这样做很不错),如果没有找到匹配项,就会返回None
。
需要注意的是,next
这个函数是在Python 2.6版本中新增的;在更早的版本中,我记得你需要这样做:
try:
return all_matches.next()
except StopIteration:
return None
当然,如果你只是想做一次,你可以用一行代码来实现:
instance = next((o for o in [a, b] if o.value == 1), None)
后者的好处是不会进行很多函数调用,所以可能会稍微快一点,尽管这个速度差别可能微不足道。
使用过滤器:
filter(lambda obj: obj.value == 1, [a, b])
过滤器会返回一个符合你指定条件的对象列表。文档链接:http://docs.python.org/library/functions.html#filter
简单来说,filter(fn, list)
会遍历 list
中的每一个项目,然后对每个项目应用 fn
这个函数。它会把所有 fn
返回为真的项目收集起来,放进一个列表中,然后返回这个列表。
注意:过滤器总是会返回一个列表,即使只有一个对象符合条件。所以如果你只想返回第一个符合条件的对象,你需要做一些额外的操作,比如:
def find_instance(fn, objs):
all_matches = filter(fn, objs)
if len(all_matches) == 0:
return False # no matches
else:
return all_matches[0]
或者,更好的方法是:
def find_instance(fn, objs):
all_matches = filter(fn, objs)
return len(all_matches) > 0 and all_matches[0] # uses the fact that 'and' returns its second argument if its first argument evaluates to True.
然后,你可以这样调用这个函数:
instance = find_instance(lambda x: x.value == 1, [a, b])
这样,instance
就会是 a
。