import threading
import time
class Data:
def __init__(self):
self.x: int = 0
self.y: int = 0
do_sleep = False
run = True
def reader(d: Data):
while run:
x, y = d.x, d.y
# по идее это условие не должно выполниться никогда
if (x != 0) != (y != 0):
print(f'Got x={x} and y={y}')
else:
print(f'OK {x}', end='\x08\x08\x08\x08')
def writer(d: Data):
while run:
if d.x == 0:
d.x = 1
if do_sleep: pass
d.y = 1
else:
d.x = 0
if do_sleep: pass
d.y = 0
do_sleep = False
instance = Data()
reader_thread = threading.Thread(target=reader, args=(instance,), daemon=True)
writer_thread = threading.Thread(target=writer, args=(instance,), daemon=True)
reader_thread.start()
writer_thread.start()
try:
input()
finally:
run = False
reader_thread.join()
writer_thread.join()if do_sleep: pass закомментировать, то в консоли высвечивается только OK - иными словами, присваивание двух полей выполняется достаточно быстро, чтобы поток не успел переключиться в промежутке. Как следствие, reader() всегда видит либо x=0 y=0, либо x=1 y=1.if do_sleep: pass оставить, то выполнение тела цикла замедляется достаточно, чтобы поток успел переключиться - и, как следствие, reader() начинает видеть структуру данных Data в неконсистентном состоянии, когда x=0 y=1 или когда x=1 y=0. \.( ) [ ] ^ $ . ? * +. Если тебе нужен этот символ как просто символ, его надо экранировать! Т.е. если тебе нужно совпадение с символом ?, надо писать \?.[abc] совпадёт с одним символом из указанных: a, b или c. Для задания диапазона можно сделать так: [a-z]. Это зачастую короче.[^abc] \w описывает словесные символы (буквы, цифры и подчёркивание), \d описывает цифры, и т.д. Аналогично, \W и \D описывают всё кроме словесных символов и цифр, соотв.re.sub(r'\W', '', 'test:_:test', re.I) # даст test_testre.sub(r'[\W_]', '', 'test:_:test', re.I) # даст testtest async def parse_card(card):
d = dict()
# из карточки берется html
# "вставляется" в объект супа
# и возвращается словарь
# внутри этой функции не используются await
return d# submodule_1.py - модуль, содержащий часть функций бота
def setup(bot):
# bot - объект бота. Можешь добавить и другие полезные параметры, такие как:
# - объект logging.Logger для журналирования
# - объект соединения с БД
# - ну и что там ещё тебе потребуется
# все обработчики событий объявляем ВНУТРИ setup()
# тогда они смогут ссылаться на переданные параметры
@bot.command('/start') # например, чтобы использовать декораторы
def on_start(message):
message.reply('foobar')
# мы описали функцию setup(), но здесь мы её не вызываем!
# main.py - основной файл бота
bot = ... # создаём объект бота
import submodule_1 # импортируем модуль с функциями
# при вызове setup() будут заданы обработчики событий, описанные в ней
submodule_1.setup(bot) # функции передаём объект бота (и другие объекты, если она их ожидает)
# функцию setup() нужно вызывать не более одного раза!
# так можно добавлять столько модулей, сколько требуется.
bot.run() # дальше бота запускаем как обычно @dp.callback_query_handler(text='1')
async def id1(callback: CallbackQuery):def do_stuff_nocache(*args, **kwargs):
...
@lru_cache
def do_stuff(*args, **kwargs):
return do_stuff_nocache(*args, **kwargs)@lru_cache
def do_stuff(*args, **kwargs):
...
print(do_stuff.__wrapped__(*args, **kwargs))do_stuff.clear_cache() но это очистит кэш вообще, что, скорее всего, нежелательно.