Python 模块 - 范围

Posted

技术标签:

【中文标题】Python 模块 - 范围【英文标题】:Python modules - Scopes 【发布时间】:2014-10-03 03:00:22 【问题描述】:

我发现我认为是 python 3.4 的特殊行为。我制作了这些小文件来说明我面临的问题。

为了解决这个问题,我现在有一个 python 程序(模块),special.py,包含一个类和一些函数。其中一个功能是从 Point 类实例化点。 当我左键单击 pygame 窗口时,通过这个函数 add_point 从类 Point 实例化一个点。在命令窗口中列出了以这种方式创建的实例。一切都很好。我们可以看到,创建的点被添加到 points_list 并在命令窗口中列出。

右击窗口会生成由另一个模块 (pec_controls.py) 中的函数调用的完全相同的函数 (add_point)。 然后实例化一个点,但它似乎被添加到一个新的或不同的 points_list 中,只添加通过右键单击窗口实例化的点。如果我们在右击和左击窗口之间切换,该类会在两个不同版本的 points_list 之间切换。

如果类是直接从 pec_controls.py 调用的,我可以理解这种行为,即该点在 pec_control.py 中实例化,但不像现在,它是在 special.py 中调用该类的完全相同的函数所有实例。 当我右键单击时,我有点将“范围”传递给 pec_control 模块,但我认为人们应该期望在该模块调用 add_point 时返回范围,返回到 special.py 中。 委婉地说,调用函数的位置对它的或类的行为很重要,这是非常出乎意料的。

有人能解释一下python这种行为背后的基本原理吗? 有什么我忘记了,让所有实例都出现在同一个列表中吗?

这里是 pec_controls.py:

import peculiar, sys, pygame

def clicked_right():
    peculiar.add_point()

这里是奇特的.py:

# peculiar.py
# Sample to show peculiar behaviour by python 3.4, or python in general?
# Left clicking window instantiates point by this module alone(see command window).
# Right clicking window instantiates point from pec_controls.py module. 
# Right clicking, instead of calling add_point function directly, as left clicking does, calls     function in pec_controls.py, which then calls the add_point function in this module.
# What is peculiar is that this is resulting in Class Point seeming to make a new list of the global list points_list,
# only containing the items instantiated from pec_controls module(i.e. by right clicking window) ref. command window .
# Left clicking again, makes the Class go back to the original list, adding "leftclicked" point instances as usual.
# Apparently there is now two different lists? Is this a bug or intended? 

import pygame, sys, pec_controls
from pygame.locals import *

FPS = 10
points_list = []
class Point():
    def __init__(self):
        points_list.append(self)
        self.position = (10 * len(points_list), 10 * len(points_list))
        print("Class says:    ",len(points_list), "points")                     

    def update(self):
        self.rect.x = self.position[0]
        self.rect.y = self.position[1]
        pass

def add_point( x = None, y = None):
    display_frame()
    point = Point()
    for i in points_list:                                                       # The points created by calling the class from controls.py via btn_add_point_clicked_left.
        print ("add_point says", i, i.position)                                 # ref: Display frame which prints out the points made by calling the class from main
   print ("add_point", points_list)                                             # This writes out points in points_list                     !!!!!!!!


def process_events():
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return True
            if event.type == pygame.MOUSEBUTTONUP :
                if event.button == 1:
                    add_point()                                     # Instantiates a point via btn_add_point_clicked. (Ok/Normal)
                    print("Left Click")
                elif event.button == 3:
                    pec_controls.clicked_right()                                # Instantiates a point via pec_controls module via add_point. (Peculiar result !!!!)
                    print("Right Click")    
                pass
        return False

def display_frame():                                        
    for i in points_list:                                   # Writes out the points in the global list points_list
        print ("display says", i, i.position)                   # 
    print("display", points_list)                               # 

def main():                                                 # Main function
    pygame.init()
    main.screen = pygame.display.set_mode((200,200),0,32)
    main.clock = pygame.time.Clock()

    point = Point()                                         # Instantiates a point from main of this module
    point.position =(100,200)

    add_point()                                             # Instatiates a point from main via the function add_point

    main.done = False
    while not main.done:                                    
        main.done = process_events()
        main.clock.tick(FPS)
        #display_frame()

    pygame.quit()   

if __name__ == "__main__":
    main()

【问题讨论】:

【参考方案1】:

您遇到的问题是当peculiar.py 作为脚本运行时,它不被认为是peculiar 模块。它被认为是__main__ 模块。导入peculiar 将再次运行该文件,生成Point 类、points_list 列表等的单独副本。

我建议将程序的 main 功能分离到一个单独的文件中,该文件导入 peculiar 并从 peculiar 模块调用所有内容的版本。或者,您可以在 if __name__ == "__main__" 块中使用 import peculiar; peculiar.main()

【讨论】:

特别是我的主要模块。问题是它的功能在从另一个模块调用时会发生变化,我有时想要这样做。这是说明问题的示例。实际上,controls.py 是一个包含控件、按钮等的模块...... @Stacker:“当从另一个模块调用时,它的功能会发生变化”——我强烈建议不要这样做。还有其他组织代码的方法不会遇到此问题。 显然我不想改变它的功能。但我希望能够从不同的模块调用一个函数,并获得相同的结果。在这种情况下:创建的实例每次都被添加到同一个列表中。 @Stacker:哦,对不起,我误会了。正如我所说,我建议为程序的入口点创建另一个文件或使用peculiar.main() 而不是main()。关键是要避免混合模块的__main__peculiar 版本的功能。

以上是关于Python 模块 - 范围的主要内容,如果未能解决你的问题,请参考以下文章

在 python 中加载模块范围的配置

如何让python访问ubuntu中的系统范围模块?

Python包含,模块范围问题

如何在 Python 中创建模块范围的变量? [复制]

python标准库模块二random模块学习

python之random模块