【问题标题】:Using Introspection To Find An Object's Methods, Then Filtering使用自省查找对象的方法,然后进行过滤
【发布时间】:2012-02-05 01:18:59
【问题描述】:

我的 Python 模块中有一个类,用于处理小部件。它有几种方法可以做到这一点,但我不提前知道哪些方法(如果有的话)会真正起作用,我以后可能会想出新的方法来处理小部件。此外,frobbing 小部件可能很昂贵。所以我想让我的类的一个实例能够查看自己,找到它具有的所有用于 frobb 小部件的方法,并开始尝试 frobb 小部件直到它成功,此时它应该停止关心它还没有尝试过的方法。

class WidgetFrobber:
    def simpleFrobAttempt(widget, data):
        # fastest way, might not work
    def cleverFrobAttempt(widget, data):
        # fiddly, fast, and doesn't always work
    def boringFrobAttempt(widget, data):
        # works most of the time, often slow
    def desperateFrobAttempt(widget, data):
        # doesn't always work, pathetically slow

有了这个,我想定义一个类的方法来查找名为 ^[a-z]+FrobAttempt$ 的方法,列出它们,并尝试 frob 小部件,直到成功 frobbed 小部件(此时它应该停止关心其他方法)或者它用完了可能的方法。由于这是我的代码,我可以确保 whateverFrobAttempt 方法都具有相同的命名约定和所需的参数。 最好对方法列表进行排序,以便首先尝试平均速度较高的方法,但如果以随机顺序尝试它们也是可以接受的。

有没有一种健全的方法可以做到这一点,当添加新的weirdFrobAttempt 方法时,它们会被自动尝试,还是我最好只维护这些方法的硬编码列表并对其进行迭代?

【问题讨论】:

  • 显式注册机制怎么样?一个小部件可以调用register_frobbing_method() 来注册一个新的 frobbing 方法。这将避免任何黑魔法并使过程明确。
  • 您应该完全扩展该想法并使其成为答案。 :)
  • 您可以使用dir(WidgetFrobber)获取类属性列表,或在实例上调用dir获取实例属性。但 Sven Marnach 的建议更好。
  • WidgetFrobber 类的意义何在?为什么小部件不能自检?
  • Ekhumoro:这些小部件正在自我欺骗。这只是一个需要付出多少努力的问题——破解一个小部件是昂贵的,所以我不想在已经成功后继续尝试。

标签: python oop metaprogramming introspection


【解决方案1】:

我喜欢 sven 的想法。这很 hacky,但是如果存储方法名称的全局列表是可以的,那么我们可以这样做:

FROB_METHOD_REGISTER = []
def frob_method(fn):
    def decorate_frob(fn):
        FROB_METHOD_REGISTER.add(fn.__name__)
        return fn
    return decorate_frob

class WidgetFrobber:
    def get_frob_methods(self):
        return [getattr(self, method) for method in FROB_METHOD_REGISTER]

    @frob_method
    def simpleFrobAttempt(widget, data):
        # fastest way, might not work
    @frob_method
    def cleverFrobAttempt(widget, data):
        # fiddly, fast, and doesn't always work
    @frob_method
    def boringFrobAttempt(widget, data):
        # works most of the time, often slow
    @frob_method
    def desperateFrobAttempt(widget, data):
        # doesn't always work, pathetically slow

那么你就可以了

for method in my_widget_frobber.get_frob_methods():
    #do your thing

不确定这是否是最好的或最 Pythonic 的方法,如果有一些方法严格比其他方法更好,我很想让装饰器使用某种优先级队列/排名模式。

可以使用__dict__。例如

[fn for name, fn in WidgetFrobber.__dict__.iteritems() if "FrobAttempt" in name]

会给你你正在寻找的一组方法,但我会建议使用像 __dict__ 这样的东西,如果有一种方法可以构建更清晰且不访问的代码蟒蛇内部。而且几乎总是应该有。

【讨论】:

  • 哦,嘿,这个装饰器的想法是我没有想到的!我在想一些需要更多努力的事情,但我喜欢这个想法。只需将 @_frob_method 添加到新的 whateverFrobAttempt 方法中,就需要付出完全合理的努力。
  • 实际上这行不通,我开始怀疑它行不通,基于stackoverflow.com/questions/3885459 以及关于在类构造期间而不是在实例构造期间应用装饰器的一点。 :(
  • 哎呀,是的。 stackoverflow.com/questions/1263451 也是,很抱歉应该抓住这个。我仍然不喜欢访问内部的想法。修改为可行的东西,但非常hacky。
  • 是的,“改变架构”似乎很有可能是正确的答案。没关系。我问这个问题是因为我开始使用__dict__ 并说“等一下,这似乎不对。”
  • 我很想看看你的解决方案,偶尔我们会遇到非常相似的问题并在模块级别使用装饰器技巧/
猜你喜欢
  • 2015-12-26
  • 1970-01-01
  • 2018-11-05
  • 1970-01-01
  • 2010-09-24
  • 1970-01-01
  • 1970-01-01
  • 2012-04-18
相关资源
最近更新 更多