Оказва се, че методът по подразбиране reduce_ex (почти съм сигурен, че това е този в object(), но не е задължително.), който идва по линията, когато имате активен sqlalchemy, добавя член _sa_instance_state
към 'състоянието', върнато в API reduce_ex, който PyYAML използва за извършване на сериализация.
Когато сериализирате обект, идващ от заявка на SqlAlchemy, това по същество е скрита част от метаданните на обекта, която е достъпна за по-нататъшни операции.
Това е този обект, в който сериализаторът на PyYAML се проваля. Можете да проверите това, като изпълните сериализацията си в PDB и видите две извиквания към represent_object във вашия стек за повиквания, дори и за сравнително прости резултати от обект на заявка на SQLAlchemy.
Тази връзка към екземпляр на заявка се използва, доколкото разбирам, за захранване на методи с възможност да се върнете към заявката, която генерира даден обект от живота на същия интерпретатор на python.
Ако се интересувате от тази функционалност (неща като session.new & session.dirty), ще трябва да внедрите поддръжка за това в сериализатора на PyYAML.
Ако не ви пука и просто искате вашите декларирани членове, можете да използвате базов клас, който „скрива“ тази връзка от извиквания към reduce* – имайте предвид, че това също ще наруши разширението на сериализатора на SQLAlchemy както и, така че обмислете внимателно плановете си.
Пример за базов клас за прилагане на тази промяна е:
DeclBase = declarative_base()
class Base(DeclBase):
__abstract__ = True
def __reduce_ex__(self, proto):
ret = super(Base, self).__reduce_ex__(proto)
ret = ( ret[0], ret[1], dict(ret[2]) ) + ret[3:]
ret[2].pop('_sa_instance_state', None) # remove bad yamly from reduce state
return ret
След това това ще ви позволи да обикаляте вашите обекти в/из yaml, въпреки че двупосочното пътуване ще ги разграничи от всички висящи транзакции или заявки. Това също може да има взаимодействия, ако използвате лениво заредени членове, например. Уверете се, че сериализирате всичко, което очаквате.
ЗАБЕЛЕЖКА/РЕДАКТИРАНЕ: Избрах да използвам reduce_ex тук, за да съм съвместим с евентуални други базови класове или миксини. Според https://docs.python.org/2/library/pickle .html#object.reduce_ex, това ще произведе правилното поведение за всички основни класове, като също така ще открие дали е деклариран само reduce().
Redux... reduce ще върне действителния dict на обекта на екземпляра -- ние не искаме да изтриваме от там, така че за __reduce* трябва всъщност плитко да копираме този dict.
person
Bryon Roché
schedule
17.10.2014