Python 函数中未访问全局变量
Python global variable is not being accessed in function
这是我的 python 模块,运行 作为主线程中的两个线程。一个线程运行 monitor_wind()
,每次旋转都会添加到 wind_count
,另一个线程运行 calculate_speed()
以从计数中获取以 mph 为单位的风速,并将其添加到一个列表中,该列表稍后对平均风速进行平均英里/小时
我的问题是 calculate_speed()
似乎没有访问全局变量 wind_count
,它始终为 0,即使 monitor_wind()
正在添加。但是它对 wind_list
所做的更改可以在 globals()
列表中看到。
如何让它访问全局变量?
from gpiozero import Button
import math
from time import sleep
wind_sensor = Button(6)
wind_count = 0
wind_list = []
def calculate_speed():
while True:
global wind_list, wind_count
print(wind_count)
radius_cm = 9.0
cm_in_mile = 160934.4
circumference_cm = (2 * math.pi) * radius_cm
rotations = wind_count / 2.0
dist_miles = (circumference_cm * rotations) / cm_in_mile
speed = dist_miles / 5 # Divide distance by time, 5 seconds
print(speed)
wind_list.append(speed)
wind_count = 0 # Reset wind count
sleep(5)
def spin():
global wind_count
wind_count += 1
def monitor_wind():
wind_sensor.when_pressed = spin
对我来说,这似乎不是您使用全局变量的问题,但我不鼓励使用全局变量,而是创建 class WindMonitor
。如果您从多个线程访问一个变量,您也应该使用锁。
试试这个(我不得不在随机时间间隔调用自旋,因为我的设备上没有 gpios)。
wspeed.py
# from gpiozero import Button
import math
import random
import threading
from time import sleep
DEFAULT_WIND_SENSOR = None; # Button(6)
class WindMonitor:
def __init__(self, button=DEFAULT_WIND_SENSOR):
self.wind_count = 0
self.wind_list = []
self.button = button
self.wind_count_lock = threading.Lock()
def calculate_speed(self, stop_event):
while True:
with self.wind_count_lock:
print(self.wind_count)
radius_cm = 9.0
cm_in_mile = 160934.4
circumference_cm = (2 * math.pi) * radius_cm
rotations = self.wind_count / 2.0
dist_miles = (circumference_cm * rotations) / cm_in_mile
speed = dist_miles / 5 # Divide distance by time, 5 seconds
print(speed)
self.wind_list.append(speed)
self.wind_count = 0 # Reset wind count
if stop_event.wait(5):
return
def spin(self):
with self.wind_count_lock:
self.wind_count += 1
def monitor_wind(self):
# self.button.when_pressed = self.spin
while True:
sleep(float(random.randint(1, 10)) / 10)
self.spin()
__main__.py
import threading as th
import time
from wspeed import WindMonitor
if __name__ == '__main__':
monitor = WindMonitor()
stop_event = th.Event()
th_wmonitor = th.Thread(target=monitor.monitor_wind, daemon=True)
th_wspeed = th.Thread(target=monitor.calculate_speed, args=[stop_event], daemon=True)
try:
th_wspeed.start()
th_wmonitor.start()
while True: time.sleep(100)
except (KeyboardInterrupt, SystemExit):
stop_event.set()
编辑:解释停止事件
您的所有线程永远循环(主线程、th_wmonitor
和 th_wspeed
)。
您希望程序在主程序终止时退出。
当 python 退出时,它会等待所有非守护线程终止,因此您将它们设为守护线程是正确的做法。问题是 python 只会在有 单个 剩余守护线程时退出。因为两个守护线程都无限循环,所以您需要一种方法来告诉其中一个(或两个)程序何时退出。
实现此目的的最简单方法是使用 threading.Event
对象。 Event
是线程间通信的一种简单方式。它基本上是您在一个线程中设置并在另一个线程中签入的标志。通过在 main 中设置异常,您可以设置 threading.Event
的 stop_event
实例。这让任何有权访问 stop_event
的线程认为主线程已经退出,其他线程可以在它们准备终止时终止。
th_wspeed
需要在特定时间终止,因为您不想在打印语句的中间终止。出于这个原因,我将 th_wspeed
作为检查 stop_event
的对象。当 th_wspeed
发现 stop_event
已设置时,它会 returns,从而终止两个守护线程之一。那时,因为 python 看到只剩下一个守护线程,它会强制该线程终止,程序退出。
如果没有停止事件,程序将不会在您按下 CTRL+C 时终止。
这是我的 python 模块,运行 作为主线程中的两个线程。一个线程运行 monitor_wind()
,每次旋转都会添加到 wind_count
,另一个线程运行 calculate_speed()
以从计数中获取以 mph 为单位的风速,并将其添加到一个列表中,该列表稍后对平均风速进行平均英里/小时
我的问题是 calculate_speed()
似乎没有访问全局变量 wind_count
,它始终为 0,即使 monitor_wind()
正在添加。但是它对 wind_list
所做的更改可以在 globals()
列表中看到。
如何让它访问全局变量?
from gpiozero import Button
import math
from time import sleep
wind_sensor = Button(6)
wind_count = 0
wind_list = []
def calculate_speed():
while True:
global wind_list, wind_count
print(wind_count)
radius_cm = 9.0
cm_in_mile = 160934.4
circumference_cm = (2 * math.pi) * radius_cm
rotations = wind_count / 2.0
dist_miles = (circumference_cm * rotations) / cm_in_mile
speed = dist_miles / 5 # Divide distance by time, 5 seconds
print(speed)
wind_list.append(speed)
wind_count = 0 # Reset wind count
sleep(5)
def spin():
global wind_count
wind_count += 1
def monitor_wind():
wind_sensor.when_pressed = spin
对我来说,这似乎不是您使用全局变量的问题,但我不鼓励使用全局变量,而是创建 class WindMonitor
。如果您从多个线程访问一个变量,您也应该使用锁。
试试这个(我不得不在随机时间间隔调用自旋,因为我的设备上没有 gpios)。
wspeed.py
# from gpiozero import Button
import math
import random
import threading
from time import sleep
DEFAULT_WIND_SENSOR = None; # Button(6)
class WindMonitor:
def __init__(self, button=DEFAULT_WIND_SENSOR):
self.wind_count = 0
self.wind_list = []
self.button = button
self.wind_count_lock = threading.Lock()
def calculate_speed(self, stop_event):
while True:
with self.wind_count_lock:
print(self.wind_count)
radius_cm = 9.0
cm_in_mile = 160934.4
circumference_cm = (2 * math.pi) * radius_cm
rotations = self.wind_count / 2.0
dist_miles = (circumference_cm * rotations) / cm_in_mile
speed = dist_miles / 5 # Divide distance by time, 5 seconds
print(speed)
self.wind_list.append(speed)
self.wind_count = 0 # Reset wind count
if stop_event.wait(5):
return
def spin(self):
with self.wind_count_lock:
self.wind_count += 1
def monitor_wind(self):
# self.button.when_pressed = self.spin
while True:
sleep(float(random.randint(1, 10)) / 10)
self.spin()
__main__.py
import threading as th
import time
from wspeed import WindMonitor
if __name__ == '__main__':
monitor = WindMonitor()
stop_event = th.Event()
th_wmonitor = th.Thread(target=monitor.monitor_wind, daemon=True)
th_wspeed = th.Thread(target=monitor.calculate_speed, args=[stop_event], daemon=True)
try:
th_wspeed.start()
th_wmonitor.start()
while True: time.sleep(100)
except (KeyboardInterrupt, SystemExit):
stop_event.set()
编辑:解释停止事件
您的所有线程永远循环(主线程、th_wmonitor
和 th_wspeed
)。
您希望程序在主程序终止时退出。
当 python 退出时,它会等待所有非守护线程终止,因此您将它们设为守护线程是正确的做法。问题是 python 只会在有 单个 剩余守护线程时退出。因为两个守护线程都无限循环,所以您需要一种方法来告诉其中一个(或两个)程序何时退出。
实现此目的的最简单方法是使用 threading.Event
对象。 Event
是线程间通信的一种简单方式。它基本上是您在一个线程中设置并在另一个线程中签入的标志。通过在 main 中设置异常,您可以设置 threading.Event
的 stop_event
实例。这让任何有权访问 stop_event
的线程认为主线程已经退出,其他线程可以在它们准备终止时终止。
th_wspeed
需要在特定时间终止,因为您不想在打印语句的中间终止。出于这个原因,我将 th_wspeed
作为检查 stop_event
的对象。当 th_wspeed
发现 stop_event
已设置时,它会 returns,从而终止两个守护线程之一。那时,因为 python 看到只剩下一个守护线程,它会强制该线程终止,程序退出。
如果没有停止事件,程序将不会在您按下 CTRL+C 时终止。