简体   繁体   English

Python 的 importlib 并检查静态类成员

[英]Python's importlib and inspect for static class members

In a long-running app I need to dynamically modify static class members based on path to the class' module and the class name.在长时间运行的应用程序中,我需要根据类模块的路径和类名动态修改静态类成员。

Ex.前任。 I have a class pack1.mod1.Person and by definition I know it has a age property.我有一个类pack1.mod1.Person并且根据定义我知道它有一个age属性。 So utilizing the importlib and inspect I try to load the class using the module path and class name and update the age property.因此,利用importlibinspect我尝试使用模块路径和类名加载类并更新age属性。 It all seems fine until I read the the age property from my naturally imported Person class and find it's not updated.一切似乎都很好,直到我从我自然导入的Person类中读取了age属性并发现它没有更新。

Here are some more details:以下是更多详细信息:

.
├── app.py
└── pack1
    ├── __init__.py
    └── mod1.py

mod1.py模块1.py

class Person:
    age = 42

app.py应用程序

import inspect
import os
from importlib import util

from pack1.mod1 import Person

if __name__ == '__main__':
    Person.age = 3
    print(Person.age)  # => 3

    spec = util.spec_from_file_location('pack1.mod1', os.path.join('pack1', 'mod1.py'))
    module = util.module_from_spec(spec)
    spec.loader.exec_module(module)

    members = inspect.getmembers(module)

    for x, member in inspect.getmembers(module, lambda i: inspect.isclass(i) and i.__name__ == Person.__name__):
        print('Person:', Person.age)  # => Person: 3
        print('Person from inspect:', member.age)  # => Person from inspect: 42
        Person.age = 11
        member.age = 66
        print('Person:', Person.age)  # => Person: 11
        print('Person from inspect:', member.age)  # => Person from inspect: 66

In the app.py I would expect member and Person to be the same thing but as the example shows they aren't.app.py我希望memberPerson是同一件事,但正如示例所示,它们不是。

What am I missing and how to achieve such an update on the static members of a class?我错过了什么以及如何对类的静态成员进行这样的更新?

Python has no way of knowing that the regularly imported module and the manually module are "the same": Using util.spec_from_file_location up to spec.loader.exec_module side-steps Python's module registry and explicitly creates a new instance of the module. Python 无法知道定期导入的模块和手动模块是“相同的”:使用util.spec_from_file_locationspec.loader.exec_module Python 的模块注册表并显式创建模块的新实例。
Instead, use the native operations of the interpreter ( import , ...) or their programmatic equivalents ( importlib.load_module , ...)相反,使用解释器的本机操作( import ,...)或其编程等效项( importlib.load_module ,...)

If the module/class are well-known, one can import it regularly and directly inspect it.如果模块/类是众所周知的,可以定期import并直接检查它。

import pack1.mod1
pack1.mod1.Person.age = 66

If module and class are only known by name, one can look them up from the existing modules.如果模块和类仅通过名称知道,则可以从现有模块中查找它们。

import importlib

module_name, qualname, attribute, value = 'pack1.mod1', 'Person', 'age', 66

obj = importlib.import_module(module_name)  # same as `import {module_name}`
for part in qualname.split('.'):
    obj = getattr(obj, part)                # same as `{obj}.{part}

setattr(obj, attribute, value)              # same as `{obj}.{attribute} = {value}`

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM