Как использовать эквивалентный метод __post_init__ с обычным классом? - PullRequest
1 голос
/ 15 марта 2019

Я хотел бы сохранить сущность, использованную в моем коде, и избегать множественных вхождений.Таким образом, моя идея заключалась в том, чтобы использовать метод __init__ для сбора основных данных для моего класса, а затем использовать своего рода метод __post_init__ для вычисления идентификатора из моего объекта класса.Вот код:

class Worker(Base):
    __tablename__='worker'
    id = Column(Integer,primary_key=True)
    profile=Column(String(100),nullable=False)
    useragent=Column(String(100),nullable=False)
    def __init__(self,useragent,profile):
        """ specify the main information"""
        print('init')
        self.profile= profile
        self.useragent=useragent
    def __post_init__(self):
        """ compute an id based on self, the worker"""
        self.id=id(self)
        print('dans post init')

В этом примере можно использовать метод __init__, но он не запускает метод __post_init__, как мы могли бы ожидать, например, с использованием класса данных.

Как я мог запустить этот метод сразу после выполнения метода __init__?

1 Ответ

2 голосов
/ 15 марта 2019

Метод __post_init__ специфичен для библиотеки dataclasses, поскольку метод __init__ в классах dataclass генерируется, и его переопределение полностью исключает цель его генерации.

SQLAlchemy, с другой стороны, предоставляет реализацию __init__ для базового класса модели (сгенерированного для вас с помощью declarative_base()). Вы можете безопасно использовать этот метод самостоятельно после установки значений по умолчанию, набрав super().__init__(). Учтите, что SQLAlchemy -обеспечиваемый метод __init__ принимает только ключевые аргументы:

def __init__(self, useragent, profile):
    """specify the main information"""
    id = generate_new_id(self)
    super().__init__(id=id, useragent=useragent, profile=profile)

Если вам нужно подождать, пока другие столбцы получат обновленные значения вначале (поскольку, возможно, они определяют функции Python как default), то вы также можете запускать функции после вызова super().__init__() и просто назначить self:

def __init__(self, useragent, profile):
    """specify the main information"""
    super().__init__(useragent=useragent, profile=profile)
    self.id = generate_new_id(self)

Примечание: вы не хотите использовать встроенную функцию id() для генерации идентификаторов для данных, вставленных в SQL, возвращаемые функцией значения не гарантируются как уникальные . Они уникальны только для набора всех активных объектов Python и только в текущем процессе. В следующий раз, когда вы запустите Python или когда объекты будут удалены из памяти, значения могут и будут использоваться повторно, и вы не можете контролировать, какие значения будут сгенерированы в следующий раз или в другом процессе.

Если вы когда-либо создавали строки с уникальными комбинациями столбцов useragent и profile, то вам нужно определить UniqueConstraint в аргументах таблицы . Не пытайтесь обнаружить уникальность на уровне Python, поскольку вы не можете гарантировать, что другой процесс не выполнит такую ​​же проверку одновременно. База данных находится в гораздо лучшем положении, чтобы определить, есть ли у вас повторяющиеся значения, не рискуя условиями гонки:

class Worker(Base):
    __tablename__='worker'
    id = Column(Integer, primary_key=True, autoincrement=True)
    profile = Column(String(100), nullable=False)
    useragent = Column(String(100), nullable=False)

    __table_args__ = (
        UniqueConstraint("profile", "useragent"),
    )

или вы можете использовать составной первичный ключ на основе двух столбцов; первичные ключи (составные или иные) всегда должны быть уникальными:

class Worker(Base):
    __tablename__='worker'
    profile = Column(String(100), primary_key=True, nullable=False)
    useragent = Column(String(100), primary_key=True, nullable=False)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...