提问人:Watchduck 提问时间:9/11/2023 最后编辑:Watchduck 更新时间:9/12/2023 访问量:55
脚本更改类的源代码。为什么在运行脚本的同一控制台或测试中无法观察到效果?
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?
问:
我编写了一个脚本,它会自动将属性添加到类中。 它可以工作,但目前我无法测试它。
代码如下所示,但也可以在 GitHub 上看到。
查看类 Cat,
脚本和测试。
该脚本主要执行两件事:
- 它使用新属性的基本代码创建一个文件。
- 它附加了属性导入(它们位于单独的超类中,以实现这一点)。
(例如,创建晶须并附加 CatProperties。
该脚本用于编写它的实际目的。但它的效果不是立竿见影的。
运行脚本并尝试在同一控制台中访问新属性将失败。
但是当我打开一个新控制台时,它可以工作:
由于这种滞后,我无法为脚本编写测试函数。
请参阅 GitHub。
(它还包含断言,以证明脚本已成功运行。test_created_prop
我想知道,是否有测试脚本的好方法。
另外,我想知道滞后的原因。
(我想,这里有一些关于 Python 的知识需要学习。
类 Cat 及其属性
类 Cat
这是 in 文件夹。__init__.py
cat
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__.py
cat/properties
class CatProperties:
from .clawnum import clawnum
from .pawnum import pawnum
from .claws_per_paw import claws_per_paw
(在同一文件夹中有一个包含所有属性名称的列表,脚本需要该列表。name.py
示例属性 ClawNum
这是 in 文件夹。__init__.py
cat/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 上的版本稍微复杂一些,因为它还可以删除属性。
答:
调用代码时,将导入模块。create_property
animals.cat
由于该模块已加载并存在于现有 python 解释器会话中,因此后续调用将提供参考,但不会检查/重新加载模块。
通过在调用后手动重新加载,您将看到您的更改。create_property
import importlib
importlib.reload(animals.cat)
评论
'proj.classes.animals.cat' in sys.modules.keys()
create_property
下一个:类型提示:解决循环依赖
评论