• Как правильно реализовать телеграм бота который основывается на диалоге?

    @MEDIOFF
    Python Developer
    А чем FSM то не устраивает? Можете свой велосипед попробовать изобрести конечно, но боюсь больно на FSM похоже выйдет

    P.S: Можете попробовать просто в редис или куда то еще записывать текущий этап пользователя и проверять его везде
    Ответ написан
    1 комментарий
  • В чем разница императивного и декларативного подхода в javascript? Это процедурный и ООП стили?

    @pikkvile
    developer
    Моё понимание такое.
    Декларативное программирование - это когда в коде описано что должно получиться, а императивное - когда написано как это сделать. Т.е. в первом случае мы совершенно не интересуемся, каким именно образом машина сделает работу, какие инструкции в каком порядке выполнятся и так далее, мы просто объясняем ей, что хотим увидеть в результате. Примеры декларативных языков - html, css, sql, конфиг nginx. Ещё тут стоит упомянуть функциональные языки (lisp, haskell), программы на них тоже, как правило, являются описанием (декларацией) того "что должно получиться". Ну, короче говоря, мы говорим компьютеру: вот смотри, мне надо чтобы было так, а как ты это сделаешь, мне не интересно. Аналогия такая: у меня есть чертёж бани, я даю его бригаде строителей и уезжаю. Как именно они там будут таскать брёвна, пилить доски и прочее - я не в курсе.
    Программируя императивно, мы описываем конкретные шаги, действия и точный порядок, в котором их нужно исполнять. Напрямую руководим процессом, непосредственно отдаём приказания. Примеров масса, большинство популярных языков императивны, в том числе и javascript. Ты пишешь: вот, сделай-ка переменную myVar, потом запиши туда число 5, повторяй это до тех пор, пока что-то не случится... и так далее. Возвращаясь к примеру с баней, ты теперь - начальник бригады, именно говоришь какое бревно куда класть.
    Что касается процедурного и объектно ориентированного стилей, это немного о другом. Я бы сказал, что это два разных способа писать императивные программы. В процедурном случае мы организуем код, наши команды (приказы машине) в виде процедур. Процедура - набор команд. Это довольно простой способ организации кода и исторически более ранний. ООП - это чуть более сложный подход к организации кода, когда мы группируем инструкции и данные, которыми они манипулируют, вместе. Объект - это состояние (данные) плюс поведение (набор методов). Но это уже немного другая история.
    Ответ написан
    2 комментария
  • Нужен ли класс threading.Lock?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Python
    Седой и строгий
    GIL гарантирует только, что два потока не работают параллельно, и нужен для простого управления памятью на основе счётчика ссылок и простой интероперабельности, на уровне прикладного кода никаких гарантий он вам не даёт, два потока вполне могут конкурентно работать с одними данными и устроить гонку.
    Ответ написан
    Комментировать
  • Нужен ли класс threading.Lock?

    @deliro
    Скопируй и запусти две разных версии кода.

    Без Lock

    from threading import *
    
    def work(i):
        for _ in range(100):
            print(f"hello i'm a thread #{i}")
    
    t1 = Thread(target=work, args=(1,))
    t2 = Thread(target=work, args=(2,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()



    С Lock

    from threading import *
    
    lock = Lock()
    
    def work(i):
        for _ in range(100):
            with lock:
                print(f"hello i'm a thread #{i}")
    
    t1 = Thread(target=work, args=(1,))
    t2 = Thread(target=work, args=(2,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()



    Как можешь заметить, первый вариант иногда печатает две строки на одной, а иногда печатает пустые строки

    Ещё примеры

    Без Lock

    from threading import *
    from time import sleep
    
    
    class GlobalState:
        def __init__(self, x):
            self.x = x
            
        def set_x(self, x):
            self.x = x
    
    def reader(state: GlobalState):
        if state.x % 2 == 0:
            sleep(0.01)  # simulate OS context switch
            print(f"{state.x=} is even")
        else:
            print(f"{state.x=} is odd")
            
    
    def changer(state: GlobalState):
        state.set_x(state.x + 1)
    
    state = GlobalState(2)
    t1 = Thread(target=reader, args=(state,))
    t2 = Thread(target=changer, args=(state,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()


    С Lock

    from threading import *
    from time import sleep
    
    
    class GlobalState:
        def __init__(self, x):
            self.x = x
            self.lock = Lock()
            
        def set_x(self, x):
            self.x = x
    
    def reader(state: GlobalState):
        with state.lock:
            if state.x % 2 == 0:
                sleep(0.01)  # simulate OS context switch
                print(f"{state.x=} is even")
            else:
                print(f"{state.x=} is odd")
            
    
    def changer(state: GlobalState):
        with state.lock:
            state.set_x(state.x + 1)
    
    state = GlobalState(2)
    t1 = Thread(target=reader, args=(state,))
    t2 = Thread(target=changer, args=(state,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()


    Ну и совсем упоротый пример для тех, кто говорит, что list — threadsafe (что фактически является истиной, но логически не всегда) и не нужно использовать Lock:
    Открыть

    from threading import *
    from random import *
    
    class GlobalState:
        def __init__(self):
            self.x = []
            
        def do_something_changing(self):
            if random() < 0.5:
                self.x.append(1)
            elif self.x:
                self.x.pop()
    
    def reader(state: GlobalState):
        for _ in range(10000000):
            if len(state.x) % 2 == 0:
                if len(state.x) % 2 != 0:  # wtf how it's possible?
                    print(f"length {len(state.x)} was even before context switch")
    
    def changer(state: GlobalState):
        for _ in range(10000000):
            state.do_something_changing()
    
    state = GlobalState()
    t1 = Thread(target=reader, args=(state,))
    t2 = Thread(target=changer, args=(state,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()



    И напоследок. Хватит программировать (или пытаться) на тредах. Это сложно и никому не нужно. Давно существуют куда более удачные реализации использования всех ядер процессора (csp например в golang). А если треды используются для IO (а в питоне они в 99.9% используются именно для IO), то давно есть и довольно юзабельный asyncio.
    Ответ написан
    Комментировать