python 结构体嵌套_Python 3不更新嵌套包中的变量(使用“递归”相对导入)

在Python中重构大型程序时,遇到包结构嵌套导致的变量更新问题。作者试图在不同层级的包中更新第四层级包中的变量,但遇到了未使用导入的警告。尽管在各层级使用递归导入使得变量可见,但更新变量时引发了警告。解决方案是理解Python中的名称和值的区别,避免直接赋值更新,而是通过包名进行操作。
摘要由CSDN通过智能技术生成

我正在重构一个大型程序程序(在一个文件夹中实现了许多文件),并使用包将文件分组为面向对象的结构。该应用程序使用tKinter(可能是红色鲱鱼),并且正在Eclipse Kepler上(在Win7上)使用PyDev开发。

它确实使用了一些类,但是将包结构(参见下文)转换为类并不是首选的解决方案(除非这是获得我想要的唯一合理的方法)。

在4层程序包的底部,我定义了一个常量(“ conA”),一个函数(“ funcB”)和一个变量(“ varC”)。从下至上,__init__.py每个级别的文件(在实现程序包的(嵌套)文件夹中)包含:

from .levelbelowModuleName import conA

from .levelbelowModuleName import funcB

from .levelbelowModuleName import varC

以便“递归”导入使“ level4”实体在所有级别上均通过其“ level4”名称可见。

在更高级别的程序包中,对所有实体的“只读”引用不会引起警告/错误消息。到目前为止没有问题。

但是,当尝试在更高级别的包中更新“ varC”时,我收到两个警告:1)文件顶部的“未使用的导入:varC”警告,以及2)在更新函数(具有“全局varC”)内部”语句)在“ varC =”行出现“未使用的变量:varC”警告。到目前为止还可以,因为没有关联两个“ varC”(但请参见下面的令人讨厌的附带问题)。

我认为(从Lutz的“ Learning Python”书的第23/24章推论),导入的名称(在各个级别上)都将引用同一个对象(地址),因此,更新了位于“侄子”中的变量(兄弟孩子)包会起作用。将“ varC”提升到最近的公共祖先程序包(问题程序包的直接父级,“侄子”的祖父母)似乎是一种有效的解决方法(它消除了警告)–但这破坏了面向对象程序包的目的结构体。

转换为绝对进口没有帮助。重命名/别名化“ varC”(在导入中使用“ as”)没有帮助。

顺便说一句,在更高级别的模块中使用的更新行是“ varC = X.getTable()”;这从定制类返回tKinter IntVars的矩阵(列表列表)。

棘手的问题是:在问题文件中的任何位置对“ varC”的“只读”引用,例如在文件顶部还是函数内部的“ print(varC)”,都将消除这两种警告,从而隐藏了问题。

有办法吃我的蛋糕吗?是否有“非类”方式使“ varC”驻留在第4级,并且仍可以由更高级别的包更新?还是使用共同的祖先是唯一可行的简单易懂的“非类”方法?

PS在输入此问题时建议的相关问题中,似乎没有一个适用。一个类似但更简单(而非嵌套)的问题是:如何从另一个模块更改模块变量?

新增2015-03-27:

这是实际文件的两个Eclipse屏幕快照。(对于不熟悉Eclipse的用户,将__init__.py显示为具有软件包名称的选项卡。)第一幅图显示了递归导入(从下到上)。第二个显示函数,“ SiteSpecificReports”的“未使用的导入”(黄色三角形)警告。蓝色突出显示的行是“未使用的变量”警告所在的位置(它神秘地消失了)。

忽略与LongitudeReports有关的一切,它本质上是MessageCountReports的克隆。为了清楚起见,我已隐藏了与该问题无关的所有代码(例如tKinter调用)。忽略文件名上的红色“ X”;都是tKinter的“初始时间”类型不匹配,这些不匹配在运行代码时消失(如__init__.pyMessageCountReports中“ SiteSpecificReports”上方的注释)。

在模块层次结构中,问题文件以灰色突出显示。“ A_Mainline.py”是执行点,其下的所有内容都是要重构的代码(有些已经移至该文件上方的软件包中)。最后,除CZQX外,“ SiteSpecific”下的所有子包都是占位符,并且仅包含一个空__init__.py文件。

ZljPR.jpg

b25917e4ea6450f8b3793ddb4c1416ea.png

更新了2105-10-23

所有这些背后的目的是通过将每个模块分成几个源文件来将文件大小保持在合理的水平。

接受的答案(包括它的链接)提供了我需要的线索。我的问题是,当我将一个文件/模块重构为几个子文件(每个子文件都包含变量定义和修改它们的函数)时,我认为每个子文件都是类类的“黑匣子”对象,而不是更多正确地,一个简单的“将文件插入更高级别的文件”命令(就像编辑器的“粘贴”命令一样)。

我的想法是,递归导入实际上将递归地将较低级别的变量的地址提升到较高级别的“init.py”命名空间中,从而使这些变量对模块的所有其他子文件可见(谁仅引用那些变量)-并允许我吃蛋糕(本地化定义)并且也可以吃(变量在最高级别可用)。这种方法对我来说适用于其他编译语言,尤其是ADA 83。

创建子文件时,似乎要使变量对其他子文件可见,您需要在最顶层的文件而不是最底层的文件中定义变量-这与我尝试使用的“对象化”方法不符。有点遗憾,这种方法行不通,因为变量的位置使它难以在其他模块中重用子文件。将每个文件转换为一个类应该可以完成我所追求的工作-但是,当您需要的只是“在此处插入此代码块”效果时,这似乎毫无意义。

无论如何,重要的是现在一切正常。

解决方案

您缺少python中名称和值之间的区别。名称位于命名空间中并指向值。当你说:

from .blah import Foo

您正在创建一个新的在当前的命名空间名称,它指向相同的值是Foo在关卡blah命名空间。如果之后您说:

Foo = 1

这会改变你的本地命名空间的 Foo为指向1,但它确实没有什么blah.Foo-你必须明确地说,blah.Foo = 1改名字Foo是生命blah。

这篇博客文章很容易澄清。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值