有没有办法循环并执行Python类中的所有函数?

时间:2010-04-08 05:51:15

标签: python reflection class

我有

class Foo():
    function bar():
        pass

    function foobar():
        pass

不是逐个执行每个函数,而是如下:

x = Foo()
x.bar()
x.foobar()

是否有一种内置的方法来循环并执行它们在类中编写的顺序中的每个函数?

7 个答案:

答案 0 :(得分:9)

def assignOrder(order):
  @decorator
  def do_assignment(to_func):
    to_func.order = order
    return to_func
  return do_assignment

class Foo():

  @assignOrder(1)
  def bar(self):
    print "bar"

  @assignOrder(2)
  def foo(self):
    print "foo"

  #don't decorate functions you don't want called
  def __init__(self):
    #don't call this one either!
    self.egg = 2

x = Foo()
functions = sorted(
             #get a list of fields that have the order set
             [
               getattr(x, field) for field in dir(x)
               if hasattr(getattr(x, field), "order")
             ],
             #sort them by their order
             key = (lambda field: field.order)
            )
for func in functions:
  func()

@assignOrder(1)上方有趣的def bar(self)行触发了这种情况:

Foo.bar = assignOrder(1)(Foo.bar)

assignOrder(1)返回一个函数,它接受另一个函数,更改它(添加字段order并将其设置为1)并返回它。然后在它装饰的函数上调用该函数(因此设置其order字段);结果取代了原来的功能。

这是一种更高级,更具可读性和更易于维护的说法:

  def bar(self):
    print "bar"
  Foo.bar.order = 1

答案 1 :(得分:8)

没有。您可以访问Foo.__dict__,并依次调用每个值(捕获不可调用成员的错误),但不保留订单。

for callable in Foo.__dict__.values():
    try:
        callable()    
    except TypeError:
        pass

这假设没有一个函数采用参数,如您的示例所示。

答案 2 :(得分:5)

由于Python将类的方法(和其他属性)存储在字典中,这基本上是无序的,所以这是不可能的。

如果您不关心订单,请使用班级__dict__

x = Foo()
results = []
for name, method in Foo.__dict__.iteritems():
    if callable(method):
        results.append(method(x))

如果函数需要额外的参数,这也可以工作 - 只需将它们放在类的实例之后。

答案 3 :(得分:1)

只要你对Python 3.x感兴趣(并且从你的类声明中的空括号中我猜你可能会这样),那么实际上有一种简单的方法可以在没有装饰器的情况下执行此操作:Python 3允许您在定义类时提供类似对象的字典。

以下代码来自PEP3115,除了我添加的最后几行以按顺序打印方法:

# The custom dictionary
class member_table(dict):
  def __init__(self):
     self.member_names = []

  def __setitem__(self, key, value):
     # if the key is not already defined, add to the
     # list of keys.
     if key not in self:
        self.member_names.append(key)

     # Call superclass
     dict.__setitem__(self, key, value)

# The metaclass
class OrderedClass(type):

   # The prepare function
   @classmethod
   def __prepare__(metacls, name, bases): # No keywords in this case
      return member_table()

   # The metaclass invocation
   def __new__(cls, name, bases, classdict):
      # Note that we replace the classdict with a regular
      # dict before passing it to the superclass, so that we
      # don't continue to record member names after the class
      # has been created.
      result = type.__new__(cls, name, bases, dict(classdict))
      result.member_names = classdict.member_names
      return result

class MyClass(metaclass=OrderedClass):
  # method1 goes in array element 0
  def method1(self):
     pass

  # method2 goes in array element 1
  def method2(self):
     pass

x = MyClass()
print([name for name in x.member_names if hasattr(getattr(x, name), '__call__')])

答案 4 :(得分:1)

可能有一种最短的方法(类名是 C ):

for func in filter(lambda x: callable(x), C.__dict__.values()):
    pass # here func is the next function, you can execute it here

过滤器表达式返回C类的所有函数。

或者在一行中:

[func() for func in filter(lambda x: callable(x), C.__dict__.values())]

你可以通过一些更复杂的表达方式以某种方式命令这些函数,例如,通过字典的词典顺序。

答案 5 :(得分:0)

这有效并保留了订单:

class F:

    def f1(self, a):
        return (a * 1)

    def f2(self, a):
        return (a * 2)

    def f3(self, a):
        return (a * 3)

    allFuncs = [f1, f2, f3]

def main():
    myF = F()
    a = 10
    for f in myF.allFuncs:
        print('{0}--> {1}'.format(a, f(myF, a)))

输出为:

10--> 10
10--> 20
10--> 30

注意:使用此功能代替F.__dict__.values()的优势在于,您可以在此处列出自己喜欢被调用的那些功能的列表,而不必全部调用。 / p>

答案 6 :(得分:0)

我遇到了一个与您的问题有关的问题,但可能会帮助其他人解决与我遇到的情况相同的问题。

<块引用>

我在尝试什么:

我在 python 中学习 datetime 模块并创建了一个对象。现在,要从该对象中获取详细信息,我需要手动按 Tab 键,获取可用方法/属性的列表,然后键入它们,最后在获取结果之后。其他时间也需要重复!

<块引用>

我需要什么:

由于混合了方法(可调用)和属性(无法调用),我需要自动使用或调用所有这些方法(se),并在单个循环中查看它们的结果。

<块引用>

我的尝试:

我只是做了一个简单的 for 循环,它迭代 dir(datetimeobj)...让我告诉你如何...

# Creating an Obj
date = datetime.datetime(2020,1,29,12,5)

# Printing (But won't work, discussing 'why' in a bit)
for method in dir(date):
    if callable(method):
        print(f"{method}() -->  {date.method()}")
    else:
        print(f"{method}   -->  {date.method}")

看起来不错,对吧!它应该工作......但是,不 - 它不会。 执行这段代码会报错...

##Error: 'datetime.datetime' 对象没有属性 'method'


<块引用>

问题:

啊哈!我们正在尝试调用字符串 method,因此 date.method() / date.method 无效。

<块引用>

走向解决方案:

我尽量不在这里讨论太久...因为给出的代码是不言自明的,但请看这个...

dir_without_dunders = [method for method in dir(date) if not method.startswith('_')]

for method in dir_without_dunders:
    RealMethod = eval(f'date.{method}')
    try:
        if callable(RealMethod):
            print(f"{method}() -->  {RealMethod()}")
        else:
            print(f"{method} --> {RealMethod}")
    except:
        continue

代码摘要:
• 为您创建了dir_without_dunders...
• 使用另一个变量 RealMethod,因为 method 将包含字符串(名称),只是为了使打印更清晰、更合理
• 主要的解决方案是使用eval(f'date.{method}') 即hack
• 为什么使用try 块? - 因为不是所有的方法都可以不带参数调用,而且需要不同的参数集和数量,所以我只调用了那些可以简单调用的方法!

就是这样。 适用于此日期时间对象调用,因为它具有大多数参数集为空的方法。