首页 > 解决方案 > 这个 lambda 函数是否有理由保留“self”的“旧实例”?

问题描述

这个错误有一个故事可以提供进一步的上下文:我编写了这段代码,因为如果我在内部创建一个带有 lambda 函数的 SQLAlchemy 关系,它只会在创建所有模型后初始化关系。它所做的基本上是将所有模型填充到字典 ( self._all_models) 中,然后 lambda 函数稍后将通过访问 ( self._all_models[table_name]['model']) 获取模型。因此,当我执行 a 时session.add(Model),将调用此 lambda 函数并尝试从字典中获取模型。

我执行得很好,但我的同事有一个奇怪的问题:self实例是“旧的”,我的意思是字典self._all_models只有迄今为止创建的模型,而不是所有模型。例如,如果它必须创建 3 个模型 ( a, b, ),当要调用关系中c的 lambda 时,将只有而不是全部 3 ( )。bself._all_models{'a': ...}{'a': ..., 'b': ..., 'c': ...}

我和我的同事之间唯一的区别是我运行 Python 3.9,而他们运行 Python 3.8。当我的一位同事——“Jack”——将他的 Python 升级到 3.9 时,它运行顺利(即使在改回他的 3.8 venv 之后);但我的另一位同事——“马克”——就没有那么幸运了:即使在升级之后,它仍然对他不起作用。

比较他们的库pip freeze并没有发现任何不同,问题不太可能出在 SQLAlchemy 上。

代码:

class ORM:
    def __init__(self, source_name: str, ..., address_http_protocol: str):
        self._all_models = defaultdict(lambda: {})
        ...
        self._create_all_models()
        ...
    def _create_all_models(self) -> None:
        base = declarative_base()
        base.metadata.reflect(self._get_engine())
        all_tables = base.metadata.tables
        for table in all_tables.values():
            current_table_name = table.name
            relationships = self._get_parents(table)
            obj = type(current_table_name, (object,), dict())
            mapper(obj, table,
                   properties={table_name: relationship(lambda table_name=table_name:
                                                        self._get_model_by_table_name(table_name), lazy='select')
                               for table_name in relationships})
            self._all_models[current_table_name]['model'] = obj
            self._all_models[current_table_name]['table'] = table
    @staticmethod
    def _get_parents(table: Table) -> set:
        parents = set()
        if table.foreign_keys:
            for fk in table.foreign_keys:
                parent_name = fk.column.table.name
                parents.add(parent_name) if parent_name != table.name else None
        return parents
    def _get_model_by_table_name(self, table_name: str) -> type:
        if isinstance(table_name, str):
            return self._all_models[table_name]['model']

我说的是里面的 lambda 函数_create_all_modelslambda table_name=table_name: self._get_model_by_table_name(table_name)

标签: pythonsqlalchemy

解决方案


所以显然问题在于self._all_models字典绑定到__init__函数,这使它成为“本地”并且没有“访问”权self

更多内容:函数、未绑定方法和绑定方法有什么区别?


推荐阅读