Существует ли способ циклично выполниться через и выполнить все функции в классе Python?

Я имею

class Foo():
    function bar():
        pass

    function foobar():
        pass

Вместо того, чтобы выполнять каждую функцию один за другим следующим образом:

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

существует ли встроенный способ циклично выполниться через и выполнить каждую функцию в последовательности, в которой они записаны в классе?

9
задан badp 8 April 2010 в 06:39
поделиться

4 ответа

Нет. Вы можете получить доступ к Foo .__ dict __ и вызывать каждое значение по очереди (обнаруживая ошибки для невызываемых элементов), но порядок не сохраняется.

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

Предполагается, что ни одна из функций не принимает параметры, как в вашем примере.

8
ответ дан 4 December 2019 в 08:32
поделиться

Поскольку Python хранит методы (и другие атрибуты) класса в словаре, который принципиально неупорядочен, это невозможно.

Если вас не волнует порядок, используйте класс __ dict __ :

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

Это также работает, если функция принимает дополнительные параметры - просто поместите их после экземпляра класса.

5
ответ дан 4 December 2019 в 08:32
поделиться
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
10
ответ дан 4 December 2019 в 08:32
поделиться

Пока вас интересует только 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__')])
1
ответ дан 4 December 2019 в 08:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: