如何将脚本分成较小的脚本和模块并连接到工作区变量?
How to divide a script in a smaller script and a module and connect to workspace variable?
我使用 Python 在 Jupyter 中启动会话,并使用为我使用的应用程序部分定制的脚本。该脚本包含依赖于应用程序的字典和函数,但有些函数是通用的。我想制作一个通用模块并使启动脚本仅包含应用程序部分。困难在于我希望通用模块中的函数默认有应用程序字典。那么如何将这样的工作区字典连接到导入的函数呢?
下面一个非常简单的例子说明了这个问题。首先您会看到原始的总启动脚本。此代码有效。
import numpy as np
import matplotlib.pyplot as plt
parDict = {}
parDict['Y'] = 0.5
parDict['qSmax'] = 1.0
parDict['Ks'] = 0.1
def par(parDict=parDict, *x, **x_kwarg):
""" Set parameter values if available in the predefined dictionaryt parDict. """
x_kwarg.update(*x)
x_temp = {}
for key in x_kwarg.keys():
if key in parDict.keys():
x_temp.update({key: x_kwarg[key]})
else:
print(key, 'seems not an accessible parameter')
parDict.update(x_temp)
而且我可以在笔记本中给出类似 par(Y=0.4) 的命令,然后检查字典 parDict 中的结果。
第二个(下图)您看到尝试将通用函数分解为一个模块,并且该函数被导入到启动脚本中。在实际模块下方。此代码不起作用。错误信息是:name 'parDict' is not defined
如何解决?
parDict = {}
parDict['Y'] = 0.5
parDict['qSmax'] = 1.0
parDict['Ks'] = 0.1
from test_module import par
和test_module.py
def par(parDict=parDict, *x, **x_kwarg):
""" Set parameter values if available in the predefined dictionaryt parDict. """
x_kwarg.update(*x)
x_temp = {}
for key in x_kwarg.keys():
if key in parDict.keys():
x_temp.update({key: x_kwarg[key]})
else:
print(key, 'seems not an accessible parameter')
parDict.update(x_temp)
如果我在函数中去掉默认参数 parDict 然后它就可以工作,但是我必须有一个更长的调用,比如 par(parDict, Y=0.4)。我想避免这个冗长的调用并自动提供默认的 parDict。一个想法是在启动脚本中从导入的函数中创建一个新函数,并在此处连接到字典。但这似乎是一种笨拙的方法,还是唯一的选择?
在您尝试定义函数 par
的地方,字典 parDict
未定义。您可以将 parDict
的定义移动到 test_module.py
中(在函数定义之前)。
作为旁注,请注意 Python 中可变默认参数的危险:
https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments
它们可能会导致意外行为。
我的建议:
def par(parDict=None, *x, **x_kwarg):
""" Set parameter values if available in the predefined dictionaryt parDict. """
if parDict is None:
parDict = {}
parDict['Y'] = 0.5
parDict['qSmax'] = 1.0
parDict['Ks'] = 0.1
x_kwarg.update(*x)
x_temp = {}
for key in x_kwarg.keys():
if key in parDict.keys():
x_temp.update({key: x_kwarg[key]})
else:
print(key, 'seems not an accessible parameter')
parDict.update(x_temp)
return parDict
然后这样调用:
parDict = par(Y=2)
我上面草拟的暂定解决方案的细节如下所示。关键思想是在 start-up 脚本中从模块导入函数 parX() ,然后创建一个新函数 par() ,其中 parDict 是默认参数,因此“连接”到这个级别的函数,而在模块级别,进行此连接不起作用。因此,在 start-up 脚本中,字典 parDict 隐含地是一个全局变量,函数 par() 可以对其进行操作。
parDict = {}
parDict['Y'] = 0.5
parDict['qSmax'] = 1.0
parDict['Ks'] = 0.1
from test_module2 import parX
def par(*x, **x_kwarg):
parX(parDict, *x, **x_kwarg)
调整后test_module2.py为:
def parX(parDict, *x, **x_kwarg):
""" Set parameter values if available in the predefined dictionary parDict. """
x_kwarg.update(*x)
x_temp = {}
for key in x_kwarg.keys():
if key in parDict.keys():
x_temp.update({key: x_kwarg[key]})
else:
print(key, 'seems not an accessible parameter')
parDict.update(x_temp)
第一次测试表明它有效。通过这种方式,我避免将 parDict 作为默认参数引入,而只是将其作为全局变量访问。因此,避免了在上面 link 中讨论的默认参数何时被评估的不确定性。这段代码有什么问题吗?
关于更好的方法的建议?
一般来说,我想避免使用全局变量并引入它们作为默认参数来提高可读性,但它可能会引入问题,正如上面 link 所解释的那样,我放弃了这个想法。我想使用像 parDict 这样的工作区字典作为全局变量的原因是具有非常短的 command-line 函数,例如:par(),... 来管理字典并稍后对其内容进行操作。工作区字典的名称始终相同,但内容取决于应用程序。在字典上运行的 par() 等一般函数需要逐渐更新和扩展等,并且最好从一个模块集中完成,而不是从每个单独的 start-up 脚本。
现在我整理了一个更好的解决方案,想与您分享!关键是利用 Python class-concept 可以将字典与相关功能结合起来,然后从模块中导入 class。在 setup-file 中,您在导入 class 之后用应用程序参数名称和值填充字典,并为关联的函数创建一个短名称。如果您愿意,可以用“抽象数据类型”来描述。
start-up 脚本现在看起来像这样:
from test_module3 import ParDict
p = {}
p['Y'] = 0.5
p['qSmax'] = 1.0
p['Ks'] = 0.1
parDict = ParDict('Test3', p)
par = parDict.parX
更新后的 test_module3 现在稍微复杂一些:
class ParDict(object):
""""Tool to associate a dictionary parDict with robustified way to
modifiy parameter values."""
def __str__(self):
return self.id
def __init__(self, id, parDict):
self.id = id
self.parDict = parDict
def parX(self, *x, **x_kwarg):
x_kwarg.update(*x)
x_temp = {}
for key in x_kwarg.keys():
if key in self.parDict.keys():
x_temp.update({key: x_kwarg[key]})
else:
print(key, 'seems not an accessible parameter')
self.parDict.update(x_temp)
终于在 Jupyter Notebook 中推出了,您现在可以像以前一样使用简化的 command-line par(Y=0.4, Ks=0.08) 等更改 parDict 中的参数值
我使用 Python 在 Jupyter 中启动会话,并使用为我使用的应用程序部分定制的脚本。该脚本包含依赖于应用程序的字典和函数,但有些函数是通用的。我想制作一个通用模块并使启动脚本仅包含应用程序部分。困难在于我希望通用模块中的函数默认有应用程序字典。那么如何将这样的工作区字典连接到导入的函数呢?
下面一个非常简单的例子说明了这个问题。首先您会看到原始的总启动脚本。此代码有效。
import numpy as np
import matplotlib.pyplot as plt
parDict = {}
parDict['Y'] = 0.5
parDict['qSmax'] = 1.0
parDict['Ks'] = 0.1
def par(parDict=parDict, *x, **x_kwarg):
""" Set parameter values if available in the predefined dictionaryt parDict. """
x_kwarg.update(*x)
x_temp = {}
for key in x_kwarg.keys():
if key in parDict.keys():
x_temp.update({key: x_kwarg[key]})
else:
print(key, 'seems not an accessible parameter')
parDict.update(x_temp)
而且我可以在笔记本中给出类似 par(Y=0.4) 的命令,然后检查字典 parDict 中的结果。
第二个(下图)您看到尝试将通用函数分解为一个模块,并且该函数被导入到启动脚本中。在实际模块下方。此代码不起作用。错误信息是:name 'parDict' is not defined 如何解决?
parDict = {}
parDict['Y'] = 0.5
parDict['qSmax'] = 1.0
parDict['Ks'] = 0.1
from test_module import par
和test_module.py
def par(parDict=parDict, *x, **x_kwarg):
""" Set parameter values if available in the predefined dictionaryt parDict. """
x_kwarg.update(*x)
x_temp = {}
for key in x_kwarg.keys():
if key in parDict.keys():
x_temp.update({key: x_kwarg[key]})
else:
print(key, 'seems not an accessible parameter')
parDict.update(x_temp)
如果我在函数中去掉默认参数 parDict 然后它就可以工作,但是我必须有一个更长的调用,比如 par(parDict, Y=0.4)。我想避免这个冗长的调用并自动提供默认的 parDict。一个想法是在启动脚本中从导入的函数中创建一个新函数,并在此处连接到字典。但这似乎是一种笨拙的方法,还是唯一的选择?
在您尝试定义函数 par
的地方,字典 parDict
未定义。您可以将 parDict
的定义移动到 test_module.py
中(在函数定义之前)。
作为旁注,请注意 Python 中可变默认参数的危险: https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments
它们可能会导致意外行为。
我的建议:
def par(parDict=None, *x, **x_kwarg):
""" Set parameter values if available in the predefined dictionaryt parDict. """
if parDict is None:
parDict = {}
parDict['Y'] = 0.5
parDict['qSmax'] = 1.0
parDict['Ks'] = 0.1
x_kwarg.update(*x)
x_temp = {}
for key in x_kwarg.keys():
if key in parDict.keys():
x_temp.update({key: x_kwarg[key]})
else:
print(key, 'seems not an accessible parameter')
parDict.update(x_temp)
return parDict
然后这样调用:
parDict = par(Y=2)
我上面草拟的暂定解决方案的细节如下所示。关键思想是在 start-up 脚本中从模块导入函数 parX() ,然后创建一个新函数 par() ,其中 parDict 是默认参数,因此“连接”到这个级别的函数,而在模块级别,进行此连接不起作用。因此,在 start-up 脚本中,字典 parDict 隐含地是一个全局变量,函数 par() 可以对其进行操作。
parDict = {}
parDict['Y'] = 0.5
parDict['qSmax'] = 1.0
parDict['Ks'] = 0.1
from test_module2 import parX
def par(*x, **x_kwarg):
parX(parDict, *x, **x_kwarg)
调整后test_module2.py为:
def parX(parDict, *x, **x_kwarg):
""" Set parameter values if available in the predefined dictionary parDict. """
x_kwarg.update(*x)
x_temp = {}
for key in x_kwarg.keys():
if key in parDict.keys():
x_temp.update({key: x_kwarg[key]})
else:
print(key, 'seems not an accessible parameter')
parDict.update(x_temp)
第一次测试表明它有效。通过这种方式,我避免将 parDict 作为默认参数引入,而只是将其作为全局变量访问。因此,避免了在上面 link 中讨论的默认参数何时被评估的不确定性。这段代码有什么问题吗?
关于更好的方法的建议?
一般来说,我想避免使用全局变量并引入它们作为默认参数来提高可读性,但它可能会引入问题,正如上面 link 所解释的那样,我放弃了这个想法。我想使用像 parDict 这样的工作区字典作为全局变量的原因是具有非常短的 command-line 函数,例如:par(),... 来管理字典并稍后对其内容进行操作。工作区字典的名称始终相同,但内容取决于应用程序。在字典上运行的 par() 等一般函数需要逐渐更新和扩展等,并且最好从一个模块集中完成,而不是从每个单独的 start-up 脚本。
现在我整理了一个更好的解决方案,想与您分享!关键是利用 Python class-concept 可以将字典与相关功能结合起来,然后从模块中导入 class。在 setup-file 中,您在导入 class 之后用应用程序参数名称和值填充字典,并为关联的函数创建一个短名称。如果您愿意,可以用“抽象数据类型”来描述。
start-up 脚本现在看起来像这样:
from test_module3 import ParDict
p = {}
p['Y'] = 0.5
p['qSmax'] = 1.0
p['Ks'] = 0.1
parDict = ParDict('Test3', p)
par = parDict.parX
更新后的 test_module3 现在稍微复杂一些:
class ParDict(object):
""""Tool to associate a dictionary parDict with robustified way to
modifiy parameter values."""
def __str__(self):
return self.id
def __init__(self, id, parDict):
self.id = id
self.parDict = parDict
def parX(self, *x, **x_kwarg):
x_kwarg.update(*x)
x_temp = {}
for key in x_kwarg.keys():
if key in self.parDict.keys():
x_temp.update({key: x_kwarg[key]})
else:
print(key, 'seems not an accessible parameter')
self.parDict.update(x_temp)
终于在 Jupyter Notebook 中推出了,您现在可以像以前一样使用简化的 command-line par(Y=0.4, Ks=0.08) 等更改 parDict 中的参数值