Я имею
class Foo():
function bar():
pass
function foobar():
pass
Вместо того, чтобы выполнять каждую функцию один за другим следующим образом:
x = Foo()
x.bar()
x.foobar()
существует ли встроенный способ циклично выполниться через и выполнить каждую функцию в последовательности, в которой они записаны в классе?
Нет. Вы можете получить доступ к Foo .__ dict __
и вызывать каждое значение по очереди (обнаруживая ошибки для невызываемых элементов), но порядок не сохраняется.
for callable in Foo.__dict__.values():
try:
callable()
except TypeError:
pass
Предполагается, что ни одна из функций не принимает параметры, как в вашем примере.
Поскольку Python хранит методы (и другие атрибуты) класса в словаре, который принципиально неупорядочен, это невозможно.
Если вас не волнует порядок, используйте класс __ dict __
:
x = Foo()
results = []
for name, method in Foo.__dict__.iteritems():
if callable(method):
results.append(method(x))
Это также работает, если функция принимает дополнительные параметры - просто поместите их после экземпляра класса.
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
Пока вас интересует только 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__')])