Python - инициализация объекта класса внутри функции - PullRequest
0 голосов
/ 13 июня 2011

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

def build_row(table, cols):
    """Build a class that creates instances of specific rows"""
    class DataRow:
        """Generic data row class, specialized by surrounding function"""
        def __init__(self, data):
            """Uses data and column names to inject attributes"""
            assert len(data)==len(self.cols)
            for colname, dat in zip(self.cols, data):
                setattr(self, colname, dat)
        def __repr__(self):
            return "{0}_record({1})".format(self.table, ", ".join(["{0!r}".format(getattr(self, c)) for c in self.cols]))
    DataRow.table = table
    DataRow.cols = cols.split()
    return DataRow

Когда определяется длина «данных» и как она гарантированно равна длине «self.cols»? Кто-нибудь, пожалуйста, объясните это поведение?

Ответы [ 3 ]

1 голос
/ 13 июня 2011

Это может иметь больше смысла для вас, если вы замените ссылки на self.cols и self.table на self.__class__.cols и self.__class__.table. Эта путаница вызвана доступом к атрибутам класса через объект self, как будто они являются атрибутами экземпляра, и почему мне не особенно нравится эта идиома кодирования. При взгляде на код в __init__, где атрибутам экземпляра обычно присваиваются их значения, становится неприятно сразу увидеть утверждение, что читает значение self.cols - где, черт возьми, self.cols получает инициализирован ?! С другой стороны, если вы измените это утверждение на:

assert len(data)==len(self.__class__.cols)

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

DataRow.cols = cols.split()

задолго до того, как будет создан какой-либо экземпляр - вот почему этот утверждение работает.

Автор этого кода может рассмотреть возможность преобразования в более актуальную namedtuple конструкцию.

1 голос
/ 13 июня 2011

data присваивается значение, когда вы создаете экземпляр класса, возвращаемого функцией build_row().

Это не гарантированно такой же длины, как self.cols;возможно, вы никогда не создаете экземпляр класса и поэтому не видите ошибки.

0 голосов
/ 13 июня 2011

Когда вы определили DataRow, имена столбцов задаются в переменной self.cols. Итак, когда вы создаете экземпляр класса, вы должны заполнить каждый столбец.

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

Способ сделать это - установить атрибут с именем столбца, который не является лучшим вариантом, потому что если у вас есть столбец с именем cols или table или даже __repr__, он может сломать ваш код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...