2010-09-24 4 views
3

Я пытаюсь взять класс python (в IronPython), применить его к некоторым данным и отобразить его в сетке. Результаты функций становятся столбцами на сетке, и я хотел бы, чтобы порядок функций был порядком столбцов. Есть ли способ определить порядок функций python класса в том порядке, в котором они были объявлены в исходном коде? Я возьму ответы, которые используют либо IronPython, либо обычный python.Определить порядок объявления функций Python/IronPython

Так, например, если у меня есть класс:

class foo: 
    def c(self): 
     return 3 
    def a(self): 
     return 2 
    def b(self): 
     return 1 

Я хотел бы (без разбора исходного кода сам) получить обратно список [c, a, b]. Есть идеи?

В качестве предостережения IronPython используется для хранения ссылок на функции в том порядке, в котором они были объявлены. В .NET 4 они изменили это поведение, чтобы соответствовать python (который всегда перечисляет их в алфавитном порядке).

+0

Я удивляюсь, почему это помечено C# –

+0

Я использовал, чтобы сделать это в .NET 3.5 с IronPython, но они изменили способ GetMemberNames() в PythonType списки имен членов, чтобы соответствовать реализации питон Dict в .NET 4 . –

ответ

2

В Python 2.X (IronPython в настоящее время на Python 2) ответ, к сожалению, нет. Python создает словарь членов класса перед созданием объекта класса. После создания класса нет «записи» заказа.

В метафайлах Python 3 (которые используются для создания классов) улучшены, и вместо стандартного словаря можно использовать пользовательский объект для сбора членов класса по мере создания класса. Это позволяет вам узнать заказ.

Однако, для IronPython есть хак, который может работать. Словари Python по своей сути неупорядочены - то есть итерация по членам словаря возвращает их в произвольном (но стабильном) порядке. В IronPython использовал в том случае, если в качестве случая реализации итерация вернет элементы в том порядке, в котором они были вставлены. (Обратите внимание, что это не может не быть.)

Вы можете попробовать:

members = list(c.__dict__) # or c.__dict__.keys() 

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

Другой (лучше, но сложнее) подход - использовать модуль ast (или анализатор IronPython) и пройти AST, чтобы найти записи. Не очень сложно, но больше работы.

+0

Вы уверены, что можете использовать метаклассы? Я плохо разбираюсь с ними, но я думал, что Python сначала проанализирует определение класса в dict, а затем передаст это как аргумент метакласса для построения. Но мне было бы интересно увидеть, что я ошибаюсь! – katrielalex

+0

@katrielalex: В Python 3 метакласс может реализовать функцию '__prepare__', которая будет вызываться для создания словаря для пространства имен новых классов - см. Http://www.python.org/dev/peps/pep-3115/ –

+0

Благодаря! Я закончил подклассификацию PythonWalker от IronPython, чтобы понять структуру класса (переопределяя Walk() и PostWalk()). То, как я это делаю сейчас, я могу получить больше функций, чем хочу (в случае вложенных функций), но это не повредит моему конкретному приложению. –

2

Почему вы не можете разобрать код самостоятельно? Это легко:

import inspect 
import ast 

class Foo: 
    def c(self): 
     pass 

    def a(self): 
     pass 

    def b(self): 
     pass 

code = ast.parse(inspect.getsource(Foo)) 

class FunctionVisitor(ast.NodeVisitor): 
    def visit_FunctionDef(self, node): 
     print(node.name) 

FunctionVisitor().visit(code) 

выходы

c 
a 
b 
+0

+1 beat me to – aaronasterling

+0

Было очень полезно! Я не хотел самостоятельно разбирать код, но прохождение по дереву синтаксиса было не слишком плохим. –

1

Другим решением является использование декоратора, чтобы добавить их в список.

def make_registry(): 
    def register(f): 
     register.funcs.append(f) 
     return f 
    register.funcs = [] 
    return register 

register = make_registery() 

class Foo(object): 

    @register 
    def one(self): 
     pass 

    @register 
    def two(self): 
     pass 

    @register 
    def three(self): 
     pass 

    def utility_method_that_shouldnt_be_run_in_the_sequence(self): 
     pass 

print register.funcs 
Смежные вопросы