【问题标题】:why does global in a class behave differently when the class is within a function?为什么当类在函数中时,类中的全局行为会有所不同?
【发布时间】:2021-06-30 09:48:17
【问题描述】:

我正在尝试使用 ginput 来注册地图上的点击,并希望使用 matplotlib 小部件添加操作按钮。在下面的代码中,我可以通过将 action 的值声明为 global 将其传递回主代码。如果我点击地图,action=0,如果我点击按钮,action=1,根据需要。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button

class Index:
    def test(self, event):
        global action
        action=1

# fake data
x=np.arange(30)
y=x**2
fig,ax=plt.subplots()
ax.plot(x,y)
callback = Index()
buttonname=['test']
colors=['white']
idx=[0.2]
bax,buttons={},{}

# set up list of buttons.
for i,col,button in zip(idx,colors,buttonname):
    bax[button] = plt.axes([0.92, i, 0.07, 0.07])
    buttons[button] = Button(bax[button],button,color=col,hovercolor='green')
    buttons[button].on_clicked(getattr(callback,button))

# register click on plot
while True:
     pts=plt.ginput(1)
     plt.pause(0.5)
     print("action is ",action)
     action=0 # reset 

但我的困惑是,如果我采用完全相同的代码并将其放在 def 块中,则不再将 action 的值传回,action 始终为零。

def subtest():
    class Index:
        def test(self, event):
            global action
            action=1

    # fake data
    action=0
    x=np.arange(30)
    y=x**2
    fig,ax=plt.subplots()
    ax.plot(x,y)
    callback = Index()
    buttonname=['test']
    colors=['white']
    idx=[0.2]
    bax,buttons={},{}

    # set up list of buttons.
    for i,col,button in zip(idx,colors,buttonname):
        bax[button] = plt.axes([0.92, i, 0.07, 0.07])
        buttons[button] = Button(bax[button],button,color=col,hovercolor='green')
        buttons[button].on_clicked(getattr(callback,button))

    # register click on plot
    while True:
         pts=plt.ginput(1)
         plt.pause(0.5)
         print("action is ",action)
         action=0 # reset

res=subtest()

我很困惑为什么会发生这种情况。我尝试将类定义移到主代码中,但这没有帮助。我对任何类型的解决方案都感到高兴(例如,通过参数传递动作,我不明白如何处理小部件),因为我认为global 的使用经常被皱眉。但也可以使用基于 global 的解决方案。

【问题讨论】:

  • 您在subtest.Index.test 范围内将action 声明为global,但不在subtest 范围内。

标签: python matplotlib matplotlib-widget ginput


【解决方案1】:

subtest 内部的action 对子测试来说是本地的,而Index.test 内部的action 是全局的。要么在 subtest 中声明 action 全局,要么在 Index.test 中使用 nonlocal

(我怀疑没有全局变量可能会有更好的解决方案,但由于我不熟悉 GUI 工具包,所以我将把它留给其他人。)

【讨论】:

  • hmmm,事实上我在发布之前尝试过,但是在子测试中将操作声明为全局并没有帮助。但是,非本地声明有效!谢谢!
【解决方案2】:

您想查看这篇文章 on closuresthis other article on closures。我认为您需要在类和函数之外声明操作,然后在类中使用 global 引用它。

我认为您不需要使用类 - 您可以绕过函数传递变量、布尔值、字典并实现相同的目标。

你可以使用“on_click”事件来做你想做的事,看这个小部件教程widget tutorialthis on matplotlib event handling

这是一个使用“全局”来实现状态更改的示例代码。最好传递一个变量或使用事件来触发您希望状态生效的任何内容。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button

state = False

def change_state(btn_action):
    #do something
    btn_action= not(btn_action)
    return btn_action

def grid(val):
    global state
    #do something
    state =change_state(state)
    print(state)

    ax.grid()
    fig.canvas.draw()

    #reset value
    state =change_state(state)
    print(f'resetting state to {state}')

# fake data
x=np.arange(30)
y=x**2

#create fig, ax
fig =plt.figure()
ax= fig.subplots()
p, = ax.plot(x,y)

# set up list of buttons.

buttonname=['test']
colors=['white']
idx=[0.2]
bax,buttons={},{}

for i,col,button in zip(idx,colors,buttonname):
    bax[button] = plt.axes([0.92, i, 0.07, 0.07])
    buttons[button] = Button(bax[button],button,color=col,hovercolor='green')
    buttons[button].on_clicked(grid)

#show plot
fig.canvas.draw()
plt.show()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-14
    • 1970-01-01
    • 2020-08-06
    • 1970-01-01
    相关资源
    最近更新 更多