Подтвердить что ты не робот

Проверяете ли пользователи в порядке?

inspect.getmembers(object[, predicate])

Возвращает все члены объекта в списке пар (имя, значение), отсортированных по имени.

Я хочу использовать этот метод, но я не хочу, чтобы члены сортировались. Я хочу, чтобы они вернулись в том же порядке, в каком они были определены. Есть ли альтернатива этому методу?


Случай использования:

Создание такой формы:

class RegisterForm(Form):
    username = Field(model_field='username', filters=validators.minlength(3))
    password1 = Field(model_field='password', widget=widgets.PasswordInput)
    password2 = Field(widget=widgets.PasswordInput)
    first_name = Field(model_field='first_name')
    last_name = Field(model_field='last_name')
    address = SubForm(form=AddressForm, model_field='address')

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

4b9b3361

Ответ 1

Вы можете копаться, чтобы найти номер строки для методов, не уверены в других членах:

import inspect

class A:
    def one(self):
        pass

    def two(self):
        pass

    def three(self):
        pass

    def four(self):
        pass

def linenumber_of_member(m):
    try:
        return m[1].im_func.func_code.co_firstlineno
    except AttributeError:
        return -1

a = A()
l = inspect.getmembers(a)
print l
l.sort(key=linenumber_of_member)
print l

печатает:

[('__doc__', None), ('__module__', '__main__'), ('four', <bound method A.four of <__main__.A instance at 0x0179F738>>), ('one', <bound method A.one of <__main__.A instance at 0x0179F738>>), ('three', <bound method A.three of <__main__.A instance at 0x0179F738>>), ('two', <bound method A.two of <__main__.A instance at 0x0179F738>>)]
[('__doc__', None), ('__module__', '__main__'), ('one', <bound method A.one of <__main__.A instance at 0x0179F738>>), ('two', <bound method A.two of <__main__.A instance at 0x0179F738>>), ('three', <bound method A.three of <__main__.A instance at 0x0179F738>>), ('four', <bound method A.four of <__main__.A instance at 0x0179F738>>)]

Ответ 2

Атрибуты (методы и другие элементы) объекта обычно просматриваются через специальный атрибут __dict__ объекта, который является стандартным словарем Python. Это не гарантирует никакого конкретного заказа.

Если атрибут не найден в объекте __dict__, вместо этого выполняется поиск класса (где обычно находятся методы) и так далее, пока не пройдена целая цепочка наследования.

Вот пример пользовательской проверки, выполненной в интерактивном приглашении, чтобы проиллюстрировать это (Python 3.1):

>>> class Klass():
...     def test(self):
...             pass
...
>>> k = Klass()
>>> k.__dict__
{}
>>> k.__class__.__dict__.items()
[('test', <function test at 0x00000000024113C8>), ('__dict__', <attribute '__dic
t__' of 'Klass' objects>), ('__module__', '__main__'), ('__weakref__', <attribut
e '__weakref__' of 'Klass' objects>), ('__doc__', None)]

Я бы поместил конструктор (__init__) в Klass и установил атрибут через self, который появился бы в k.__dict__.

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

См. нижнюю часть этой страницы для Пример OrderedClass.

Не знаю, какая версия Python у вас есть, поэтому я принял последнюю версию.

Ответ 3

Я не думаю, что у Python 2.6 есть метод __prepare__, поэтому я не могу поменять значение по умолчанию dict для упорядоченного. Я могу, однако, заменить его с помощью методов metaclass и __new__. Вместо проверки номеров строк я считаю, что проще и эффективнее использовать счетчик создания.

class MetaForm(type):
    def __new__(cls, name, bases, attrs):
        attrs['fields'] = OrderedDict(
            sorted(
                [(name, attrs.pop(name)) for name, field in attrs.items() if isinstance(field, Field)],
                key=lambda t: t[1].counter
            )
        )
        return type.__new__(cls, name, bases, attrs)

class Form(object):
    __metaclass__ = MetaForm

class Field(object):
    counter = 0
    def __init__(self):
        self.counter = Field.counter
        Field.counter += 1

Ответ 4

В отношении ответа Ned Batchelder выше, в Python 3 строки номера метода m могут быть получены с помощью m.__func__.__code__.co_firstlineno

https://docs.python.org/3/library/inspect.html

Ответ 5

members = []
for name, obj in inspect.getmembers(module):
    source, start_line = inspect.getsourcelines(obj)
    members.append([name, obj, start_line])

def _line_order(value):
    return value[2]

members.sort(key = _line_order)