Есть ли какой-либо способ изменить значение из 2 сценариев в Python?

#python #python-3.x

#python #python-3.x

Вопрос:

Я хочу изменить значение sensor_value из двух сценариев python test1.py :

 from time import sleep 

class Sensor_value:
    def __init__(self):
        self.sensor_value = 1
    
    def __str__(self):
        return str(self.sensor_value)

    def change(self, val):
        assert isinstance(val, int)
        self.sensor_value = val

sensor_value = Sensor_value()

while True :
    sensor_value.change(sensor_value.sensor_value - 1)
    sleep(2)
    print("value = {} from test 1".format(sensor_value))

  

и test2.py

 from test1 import sensor_value
from time import sleep 

while True :
    sensor_value.change(sensor_value.sensor_value   1)
    sleep(3)
    print("value = {} from test 2".format(sensor_value))
  

когда я запускаю test2.py код застревает в test1.py цикл while и никогда не вводите test2.py цикл while

вот результат :

 $ python test2.py
value = 0 from test 1
value = -1 from test 1
value = -2 from test 1
value = -3 from test 1

  

кто-нибудь может мне помочь, пожалуйста

Комментарии:

1. У вас есть один процесс Python . В tests2.py вы используете from test1 import sensor_value запускает все в sensor_value , который включает бесконечный цикл, поэтому после него ничего не выполняется from test1 import sensor_value . Вам понадобится некоторая форма параллелизма. Возможно, начните читать здесь , если вы хотите все в одном процессе. В качестве альтернативы вы можете создать несколько процессов, но тогда обработка общего состояния становится сложной (это всегда сложно в параллелизме).

2. если вы хотите запустить два while цикла одновременно, вам придется использовать threading , multiprocessing или другой метод для одновременного запуска двух процессов. Но я бы предпочел воссоздать код только с одним while циклом и sleep(1) , и я бы использовал некоторые переменные, чтобы контролировать, нужно ли мне запускать sensor_value - 1 или sensor_value 1 или оба в текущем цикле.

Ответ №1:

Вы должны изменить свой test1.py сценарий, необходимо добавить цикл while под оператором if, чтобы проверить, __name__ == "__main__" .

Что происходит, всякий раз, когда вы импортируете модуль test1, интерпретатор выполняет модуль test1.

например, если вы добавите инструкцию print в модуль test1, во время импорта модуля test1 он выполнит все инструкции модуля test1.

В этом случае при запуске скрипта test2 интерпретатор застревает в первой строке модуля test2, выполняя цикл while модуля test1.

 from test1 import sensor_value
  

Но, если вы измените свой код test1, как показано ниже:

 from time import sleep 

class Sensor_value:
    def __init__(self):
        self.sensor_value = 1
    
    def __str__(self):
        return str(self.sensor_value)

    def change(self, val):
        assert isinstance(val, int)
        self.sensor_value = val

sensor_value = Sensor_value()
if __name__=='__main__': ### putting while loop under if statement.
    
    while True :
        sensor_value.change(sensor_value.sensor_value - 1)
        sleep(2)
        print("value = {} from test 1".format(sensor_value))
  

Здесь он сначала проверит, является ли модуль основным модулем, иначе, если модуль импортирован из другого модуля, оператор if завершится ошибкой, и он проигнорирует цикл while модуля test1.

Ответ №2:

Вы могли бы попробовать использовать threading или multiprocessing или другой метод для одновременного запуска двух сценариев, но для этого потребуется больше изменений и, возможно, использовать queue для отправки значений из одного процесса в другой. Коротко: это может быть сложно, когда две функции / скрипта имеют доступ к одной и той же переменной.

И именно поэтому я бы предпочел переписать второй while True цикл, чтобы запустить весь код за один цикл.

В первом сценарии я бы использовал if __name__ == '__main__': поэтому я бы запускал его цикл, когда он запускается напрямую, но не когда он импортируется в другой сценарий.

test1.py

 from time import sleep 

class Sensor_value:
    def __init__(self):
        self.sensor_value = 1
    
    def __str__(self):
        return str(self.sensor_value)

    def change(self, val):
        assert isinstance(val, int)
        self.sensor_value = val

sensor_value = Sensor_value()

if __name__ == '__main__': # don't run when imported to other script
    while True:
        sensor_value.change(sensor_value.sensor_value - 1)
        sleep(2)
        print("value = {} from test 1".format(sensor_value))
  

А затем в скрипте seconds я бы использовал sleep(1) и считал секунды, чтобы проверить, какую часть выполнить.

test2.py

 from test1 import sensor_value
from time import sleep 

seconds = 0

while True:

    if seconds % 2 == 0: # every 2 seconds
        sensor_value.change(sensor_value.sensor_value - 1)
        print("value = {} from test 1".format(sensor_value))

    if seconds % 3 == 0: # every 3 seconds
        sensor_value.change(sensor_value.sensor_value   1)
        print("value = {} from test 2".format(sensor_value))

    sleep(1)  # it needs to sleep only 1 second

    seconds  = 1
  

С потоками я бы поместил код в функции, чтобы запустить их позже с Thread()

test1.py

 from time import sleep 

class Sensor_value:
    def __init__(self):
        self.sensor_value = 1
    
    def __str__(self):
        return str(self.sensor_value)

    def change(self, val):
        assert isinstance(val, int)
        self.sensor_value = val

sensor_value = Sensor_value()

def run_test1():
    while True:
        sensor_value.change(sensor_value.sensor_value - 1)
        sleep(2)
        print("value = {} from test 1".format(sensor_value))

if __name__ == '__main__': # don't run when imported to other script
    run_test1()
  

И запустите оба потока во втором сценарии

test2.py

 from test1 import sensor_value, run_test1
from time import sleep 
import threading

def run_test2():
    while True:
        sensor_value.change(sensor_value.sensor_value   1)
        sleep(3)
        print("value = {} from test 3".format(sensor_value))


# create threads - `target` needs only function name without `()`
t1 = threading.Thread(target=run_test1)  # Thread(target=run_test1, args=(arg1,arg2))
t2 = threading.Thread(target=run_test1)

# start threads
t1.start()
t2.start()

# ... other code ...

# wait for the end of threads
t1.join()
t2.join()
  

Но иногда threads может возникнуть проблема с корректным обновлением одной и той же переменной, и может потребоваться дополнительный код для блокировки доступа к переменной или использования queue для отправки значения в основной поток, который обновит его.