为什么 class 中的 global 在 class 位于函数内时表现不同?
why does global in a class behave differently when the class is within a function?
我正在尝试使用 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()
我很困惑为什么会这样。我尝试将 class 定义移到主代码中,但这没有帮助。我对任何类型的解决方案都很满意(例如,通过参数传递操作,我不明白如何使用小部件),因为我认为 global
的使用经常不受欢迎。但基于 global
的解决方案也很好。
action
inside subtest
是局部的子测试,而 action
inside Index.test
是全局的。在 subtest
中声明 action
全局,或者在 Index.test
中使用 nonlocal
。
(我怀疑没有全局变量可能会有更好的解决方案,但由于我不熟悉 GUI 工具包,所以我会把它留给其他人。)
您想查看这篇文章 on closures and this other article on closures。我认为您需要在 class 和函数之外声明操作,然后在 class.
中使用全局引用它
我认为您不需要使用 class - 您可以通过围绕函数传递变量、布尔值、字典来实现相同的目的。
您可以使用“on_click”事件来执行您想要的操作,请参阅此小部件教程widget tutorial and this 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()
我正在尝试使用 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()
我很困惑为什么会这样。我尝试将 class 定义移到主代码中,但这没有帮助。我对任何类型的解决方案都很满意(例如,通过参数传递操作,我不明白如何使用小部件),因为我认为 global
的使用经常不受欢迎。但基于 global
的解决方案也很好。
action
inside subtest
是局部的子测试,而 action
inside Index.test
是全局的。在 subtest
中声明 action
全局,或者在 Index.test
中使用 nonlocal
。
(我怀疑没有全局变量可能会有更好的解决方案,但由于我不熟悉 GUI 工具包,所以我会把它留给其他人。)
您想查看这篇文章 on closures and this other article on closures。我认为您需要在 class 和函数之外声明操作,然后在 class.
中使用全局引用它我认为您不需要使用 class - 您可以通过围绕函数传递变量、布尔值、字典来实现相同的目的。
您可以使用“on_click”事件来执行您想要的操作,请参阅此小部件教程widget tutorial and this 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()