脚本更改类的源代码。为什么在运行脚本的同一控制台或测试中无法观察到效果?

A script changes the source code of class. Why can the effect not be observed in the same console or test, where the script was run?

提问人:Watchduck 提问时间:9/11/2023 最后编辑:Watchduck 更新时间:9/12/2023 访问量:55

问:

我编写了一个脚本,它会自动将属性添加到类中。 它可以工作,但目前我无法测试它。

代码如下所示,但也可以在 GitHub 上看到。
查看类 Cat脚本测试

该脚本主要执行两件事:

  • 它使用新属性的基本代码创建一个文件。
  • 它附加了属性导入(它们位于单独的超类中,以实现这一点)。

(例如,创建晶须并附加 CatProperties

该脚本用于编写它的实际目的。但它的效果不是立竿见影的。
运行脚本并尝试在同一控制台中访问新属性将失败。

enter image description here

但是当我打开一个新控制台时,它可以工作:

enter image description here

由于这种滞后,我无法为脚本编写测试函数。
请参阅 GitHub
(它还包含断言,以证明脚本已成功运行。
test_created_prop

我想知道,是否有测试脚本的好方法。

另外,我想知道滞后的原因。
(我想,这里有一些关于 Python 的知识需要学习。

类 Cat 及其属性

类 Cat

这是 in 文件夹。__init__.pycat

from proj.classes.animals.cat.properties import CatProperties


class Cat(CatProperties):

    def __init__(self, number_of_front_legs=2, number_of_hind_legs=2):
        self.number_of_front_legs = number_of_front_legs
        self.number_of_hind_legs = number_of_hind_legs

超类 CatProperties

这是 in 文件夹。__init__.pycat/properties

class CatProperties:

    from .clawnum import clawnum
    from .pawnum import pawnum
    from .claws_per_paw import claws_per_paw

(在同一文件夹中有一个包含所有属性名称的列表,脚本需要该列表。name.py

示例属性 ClawNum

这是 in 文件夹。__init__.pycat/properties/clawnum

def clawnum(self):
    return self.number_of_front_legs * 5 + self.number_of_hind_legs * 4

脚本create_property

该脚本使用一些 Bottle 模板来创建或更新文件。
主要是为新属性创建初始化文件。(如上面显示的 clawnum 示例。
它还使用 中的名称列表来更新 CatProperties 和名称列表本身。这意味着,将根据附加的名称列表创建这两个文件的新版本。
properties/names.py

import os
from bottle import template
from importlib import import_module


def create_property(path_string, name):

    path_list = path_string.split('.')

    ############################################################################

    this_folder = os.path.dirname(__file__)
    proj_folder = os.path.dirname(os.path.dirname(this_folder))
    view_folder = os.path.join(this_folder, 'views')

    # existing properties folder
    properties_folder_list = [proj_folder, 'classes'] + path_list + ['properties']
    properties_folder = os.path.join(*properties_folder_list)

    # current names
    names_module = import_module(f'proj.classes.{path_string}.properties.names')
    names_list = getattr(names_module, 'names')

    # target folder
    target_folder = os.path.join(properties_folder, name)

    # files
    target_init_file = os.path.join(target_folder, '__init__.py')
    target_test_file = os.path.join(target_folder, '_test.py')
    update_names_file = os.path.join(properties_folder, 'names.py')
    update_imports_file = os.path.join(properties_folder, '__init__.py')

    # views
    target_init_view = os.path.join(view_folder, 'target_init.tpl')
    target_test_view = os.path.join(view_folder, 'target_test.tpl')
    update_names_view = os.path.join(view_folder, 'update_names.tpl')
    update_imports_view = os.path.join(view_folder, 'update_imports.tpl')

    ############################################################################

    context = {
        'name': name,
        'class_name': path_list[-1].title(),  # folder name in title case
        'path_dots': path_string,
        'names': names_list
    }

    ############################################################################

    assert name not in names_list
    names_list.append(name)
    os.mkdir(target_folder)

    with open(target_init_file, 'x') as f:
        f.write(template(target_init_view, context))

    with open(target_test_file, 'x') as f:
        f.write(template(target_test_view, context))

    ############################################################################

    with open(update_names_file, 'w') as f:
        f.write(template(update_names_view, context))

    with open(update_imports_file, 'w') as f:
        f.write(template(update_imports_view, context))

GitHub 上的版本稍微复杂一些,因为它还可以删除属性。

属性 pytest python-class

评论


答:

1赞 Teejay Bruno 9/12/2023 #1

调用代码时,将导入模块。create_propertyanimals.cat

由于该模块已加载并存在于现有 python 解释器会话中,因此后续调用将提供参考,但不会检查/重新加载模块。

通过在调用后手动重新加载,您将看到您的更改。create_property

import importlib 

importlib.reload(animals.cat)

评论

0赞 Watchduck 9/12/2023
你是对的,运行脚本后确实如此。但是重新加载不起作用。'proj.classes.animals.cat' in sys.modules.keys()
0赞 Teejay Bruno 9/12/2023
@Watchduck可以更新原始帖子以包含您正在运行的代码吗?
0赞 Watchduck 9/12/2023
我正在运行上面显示的脚本。你错过了什么?create_property