使用函数属性来存储延迟(潜在)处理的结果
我正在做一些碰撞检测,我非常想在两个不同的上下文中使用相同的函数。在一种情况下,我希望它是这样的
def detect_collisions(item, others):
return any(collides(item, other) for other in others)
,而在另一种情况下,我希望它是
def get_collisions(item, others):
return [other for other in others if collides(item, other)]
我真的很讨厌在这里编写两个函数的想法。仅仅保持他们的名字简单是一个问题,而使碰撞检测的接口复杂化则是另一个问题。所以我在想:
def peek(gen):
try:
first = next(gen)
except StopIteration:
return False
else:
return it.chain((first,), gen)
def get_collisions(item, others):
get_collisions.all = peek(other for other in others if collides(item, other))
return get_collisions.all
现在,当我只想进行检查时,我可以说:
if get_collisions(item, others):
# aw snap
或者
if not get_collisions(item, others):
# w00t
在我真正想检查它们的其他上下文中,我可以这样做:
if get_collisions(item, others):
for collision in get_collisions.all:
# fix it
并且在这两种情况下,我不再进行任何处理比我需要的。
我认识到这比前两个函数的代码更多,但它还有以下优点:
将碰撞检测接口保留为树,节点位于顶层而不是中层。这看起来更简单。
使用方便的查看功能来连接自己。如果我再使用它一次,那么我实际上编写的代码就会更少。 (回应 YAGNI,如果我有的话,我会的)
所以。如果你是众所周知的杀人狂,知道我住在哪里,那么如果我写了上面的代码,我会期待你来访吗?如果是这样,您会如何处理这种情况?
I'm doing some collision detection and I would very much like to use the same function in two different contexts. In one context, I would like for it to be something like
def detect_collisions(item, others):
return any(collides(item, other) for other in others)
and in another, I would like it to be
def get_collisions(item, others):
return [other for other in others if collides(item, other)]
I really hate the idea of writing two functions here. Just keeping their names straight is one turnoff and complicating the interface to the collision detecting is another. so I was thinking:
def peek(gen):
try:
first = next(gen)
except StopIteration:
return False
else:
return it.chain((first,), gen)
def get_collisions(item, others):
get_collisions.all = peek(other for other in others if collides(item, other))
return get_collisions.all
Now when I just want to do a check, I can say:
if get_collisions(item, others):
# aw snap
or
if not get_collisions(item, others):
# w00t
and in the other context where I actually want to examine them, I can do:
if get_collisions(item, others):
for collision in get_collisions.all:
# fix it
and in both cases, I don't do any more processing than I need to.
I recognize that this is more code than the first two functions but it also has the advantage of:
Keeping my interface to the collision detection as a tree with the node at the top level instead of a mid level. This seems simpler.
Hooking myself up with a handy peek function. If I use it one other time, then I'm actually writing less code. (In response to YAGNI, if I have it, I will)
So. If you were the proverbial homicidal maniac that knows where I live, would I be expecting a visit from you if I wrote the above code? If so, how would you approach this situation?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
只需让
get_collisions
返回一个生成器:然后,如果您想进行检查:
Just make
get_collisions
return a generator:Then, if you want to do a check:
这与我们在
我从来没有真正关心过您接受多个关键字并具有不同命名函数的建议,具体取决于您是否希望通过
any()
或all()
处理所有结果 - 但是喜欢使用关键字参数的想法,它允许单个函数同时在两个或多个位置使用。这就是我最终得到的结果:通过将所有丑陋的细节放在一个单独的函数中,它不会以某种方式影响
get_collisions()
中的代码,并且也可以在其他地方使用。This is very similar to what we were discussing in "pythonic way to rewrite an assignment in an if statement", but this version only handles one positional or one keyword argument per call so one can always retrieve the actual valued cached (not just whether is a True value in the Pythonian boolean sense or not).
I never really cared for your proposal to accept multiple keywords and have differently named functions depending on whether you wanted all the results put through
any()
orall()
-- but liked the idea of using keyword arguments which would allow a single function to be used in two or more spots simultaneously. Here's what I ended up with:By putting all the ugly details in a separate function, it doesn't affect the code in
get_collisions()
one way or the other, and is also available for use elsewhere.