• Как замокать метод __next__?

    Vindicar
    @Vindicar
    RTFM!
    Вообще делать return self из __iter__() не очень хорошая идея.
    Или верни итератор по внутренней коллекции, т.е. iter(self.nums). Это имеет смысл, так как чтение коллекции циклом for по-хорошему не должно приводить к её модификации. Для этого лучше сделать явный метод.
    Или сделай из __iter__() генератор, и делай yield значения.

    В обоих случаях определять __next__() не потребуется.
    Ответ написан
    2 комментария
  • Как распарсить этот XML?

    @Mark0vka
    Чтобы прочитать поля Name, Surname, Email и Birthday из XML с использованием библиотеки xml, вам нужно указать полные пути к этим элементам с учетом пространства имен. Вот как это можно сделать:

    import xml.etree.ElementTree as ET
    
    data = """
    <ns2:Request xmlns:ns2="urn://www.example.com">
        <ns2:User>
            <ns2:Name>John</ns2:Name>
            <ns2:Surname>Snow</ns2:Surname>
            <ns2:Email>joihn.show@gmail.com</ns2:Email>
            <ns2:Birthday>2005-10-23T04:00:00+03:00</ns2:Birthday>
        </ns2:User>
    </ns2:Request>
    """
    
    namespaces = {"ns2": "urn://www.example.com"}
    
    xml = ET.fromstring(data)
    
    name = xml.find(".//ns2:Name", namespaces).text
    surname = xml.find(".//ns2:Surname", namespaces).text
    email = xml.find(".//ns2:Email", namespaces).text
    birthday = xml.find(".//ns2:Birthday", namespaces).text
    
    print("Name:", name)
    print("Surname:", surname)
    print("Email:", email)
    print("Birthday:", birthday)

    Этот код найдет и выведет значения полей Name, Surname, Email и Birthday из XML.
    Ответ написан
    Комментировать
  • Как распарсить этот XML?

    Maksim_64
    @Maksim_64
    Data Analyst
    С твоей библиотекой не работал, но с BeautifulSoup все работает как надо.
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(data, 'xml')
    name = soup.find('ns2:Name').text
    surname = soup.find('ns2:Surname').text
    email = soup.find('ns2:Email').text
    birthday = soup.find('ns2:Birthday').text
    Ответ написан
    2 комментария
  • Примеры реальных (оперсорсных) проектов на FastAPI?

    @calculator212
    Есть такой проект В целом можно спросить еще на редите.
    В связи с этим приходится самостоятельно вырабатывать подходы для разработки на нем
    Фреймворк может быть и новым, но никто не запрещает посмотреть примеры на том же джанго или фласке, т.к. в большинстве случаев разница между подходами не такая большая.
    Выше вам предложили вполне хорошие ссылки для вашего уровня, также на хабре недвано видел пост, где делали очередной клон пикабу тут код, в целом проект еще небольшой, хоть и написан н джанго понять логику и концепции которые есть в коде не составляет проблем
    Ответ написан
    Комментировать
  • Почему при отправке письма возникает ошибка "Sender address rejected: not owned by auth user"?

    InstantMedia
    @InstantMedia
    $mail->From = "Ваш реальный email в Яндекс для подключенного домена";

    Вероятней всего тот, что указан в Username.
    Ответ написан
    1 комментарий
  • Как работает annotated-types в пределах Pydantic?

    @alekssamos
    Программист любитель
    А зачем? Можно же сделать ттак:
    class Person(BaseModel):
        age: conint(ge=30)
        class Config:
            validate_assignment = True
            validate_all = True

    А вот пример со своим валидатором (это я обрабатывал checkboxes с формы):
    class FormModel(BaseModel):
        first: Optional[bool] = False
        second: Optional[bool] = False
        third: Optional[bool] = False
        something_there: str = "qwexdfg"
    
        class Config:
            validate_assignment = True
    
        @validator("first", "second", "third")
        def set_bool(cls, val):
            return False if val is None else val
    
        @validator("something_there")
        def set_str(cls, val):
            return "x" in val

    Чтобы None тоже приравнивалось к False.
    И от себя вот сейчас одну переменную добавил, принять строку, только если есть буква "x"
    Ответ написан
    Комментировать
  • Как работает annotated-types в пределах Pydantic?

    Vindicar
    @Vindicar
    RTFM!
    Насколько я понял, annotated-types просто задаёт стандарт для описания правил валидации полей, и способ получения этого описания для класса. А уж как это описание будет использоваться, должна решать конкретная библиотека, которая этому стандарту следует. Т.е. annotated-types сам по себе ничего не проверяет.
    Впрочем, в тестах у них есть примитивный пример реализации.
    Ответ написан
    Комментировать
  • Как работает asyncio.sleep?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Есть такой системный вызов select (а также подобные ему poll, epoll итд), суть которого - передать массив файловых дескрипторов (частный случай - сетевых соединений) и затем при получении событий ввода-вывода получить список тех дескрипторов, в которых произошёл ввод-вывод. Важно понимать, что при это программа "засыпает", передаёт управление ОС и не тратит ресурсов. ОС сама разбудит программу при наступлении нужных событий (записался файл, пришли новые сетевые байтики итд). Высокопроизводительные сетевые приложения (типа nginx, haproxy итд) используют подобный подход для того, чтобы эффективно обрабатывать большое количество сетевого трафика одновременно.

    asyncio работает как раз примерно по тому же принципу. Когда случается ввод-вывод, нужная функция "засыпает", а управление передаётся потоку событий. Соответственно, он либо находит задачу, которая ожидает выполнения и передаёт ей управление, либо видит, что все задачи уже одидают какого-нибудь ввода-вывода и запускает select на все ожидающие дескрипторы (возможно, в реальности используется не select, а какой-то из его аналогов, но это для нас сейчас непринципиально). Как только приходит событие, программа просыпается, поток событий находит нужное событие и передаёт управление соответствующей задаче, которая его ожидала. Это позволяет очень эффективно в один поток работать с задачами, которые много ожидают ввода-вывода, но мало выполняют реальной процессорной работы.

    Обычный ввод/вывод является блокирующим: пока не будет выполнена операция (чтение/запись/передача/приём), программа приостанавливает свою работу в ожидании. В asyncio весь ввод-вывод является неблокирующим: операции ввода-вывода не приостанавливают работу программы, а позволяют перейти к другим ожидающим задачам.

    Обычный вызов sleep приводит к приостановке и засыпанию программы на указанное время (с передачей управления ОС), и в ней в это время ничего не выполняется. Как только время истечёт, ОС вернёт управление программе. Всё это время программа не работает, события ввода-вывода не обрабатывает.

    В то же время asyncio.sleep возвращает управление потоку событий, а не ОС, что позволяет переключиться на выполнение других задач, обработать новые события итд итп. Программа не останавливается и управление ОС не передаёт (ну, кроме сна в процессе исполнения select), поэтому asyncio.sleep приводит к неблокирующему засыпанию, не мешающему выполнять задачи, которым ждать окончания сна одной конкретной задачи не нужно. Когда истечёт не менее чем указанное в asyncio.sleep время, поток событий вернёт управление приостановленной задаче.

    Важно отметить, что и sleep, и asyncio.sleep не гарантируют, что функция возобновит работу через указанное число секунд, а не позже, но при этом sleep делает это значительно точнее. Потому что возврат в вызвавшую asyncio.sleep функцию может произойти только из потока событий и только при условии, что поток событий не вернёт управление какой-то другой задаче.

    Например, пусть есть функция, которая делает asyncio.sleep(1), затем три секунды работает числомолотилка без ввода-вывода. Тогда если у нас выполняются подряд с интервалами 0.1 с три таких функции, то первая задержит на 2.9 секунд возврат управления второй, а вторая - на 5.8 с третьей.

    Это общий принцип, разумеется, там много нюансов и особенностей реализации.
    Ответ написан
    Комментировать
  • Как работает asyncio.sleep?

    Vindicar
    @Vindicar
    RTFM!
    Идея простая.
    Асинхронные приложения - это набор пар "операция - обработчик", где операция - это некоторый длительный процесс (скажем, вводы/вывод), который не требует постоянного внимания со стороны кода. Когда операция завершается, выполняется её обработчик. Этот обработчик может планировать другие операции, и так далее.

    Корутины - это такие функции, которые умеют сохранять своё состояние, и восстанавливать его. Т.е. когда корутина делает await-вызов, она начинает длительную операцию, а обработчик этой операции просто восстанавливает контекст корутины и продолжает её выполнение.

    Соответственно, await-вызов сохраняет текущий контекст корутины, и планирует новую длительную операцию. Какую - зависит от того, что идёт после await. Эта операция представлена тем или иными awiatable значением (Future, Task и т.п.).

    Рабочий цикл (loop, его также называют реактор) просто проверяет текущие операции. Как только одна из них завершилась, он выполняет её обработчик. А потом продолжает проверять остальные активные операции.

    Ключевой момент - выполняет обработчик, а только потом проверяет остальные операции. Т.е. если обработчик планирует операцию через await - это не проблема, она будет выполняться наравне с остальными. А вот если обработчик просто делает что-то длительное, он не возвращает управление циклу, и не даёт выполняться остальным операциям.

    asyncio.sleep() планирует ничего не делающую операцию, которая завершится успехом через заданное время. Поэтому её выполнение не мешает циклу-реактору. Просто ещё один await вызов, который приостанавливает текущую корутину и возвращает управление реактору.

    time.sleep() ничего не знает о реакторе и асинхронных операциях. Она приостанавливает выполнение обработчика, не прерывая его и не отдавая контроль реактору. Поэтому на время time.sleep() (или любой длительной синхронной операции) спит вся программа.
    Ответ написан
    5 комментариев
  • Почему Uvicorn советуют запускать через gunicorn?

    @deliro
    Потому что uvicorn - это не менеджер процессов. Он запускает ровно один процесс, в котором будет один ивент луп, который будет всё крутить на одном ядре. Если у тебя 4ядерный проц на сервере, то для полной утилизации ресурсов нужно запустить как минимум 4 таких uvicorn’ов. Для этого gunicorn здесь и нужен.
    Ответ написан
    Комментировать
  • Как работает это решение задачи с LeetCode?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Воспринимайте tail и head не в глобальном контексте, а локально. Это всего лишьпеременные с таким именем. Вкаждом конкретном случае и на каждой итерации они могут означать разные места связного списка.

    Представьте, что вас много, вы на соревнованиях, у каждого на груди номер и вас выстроили по неубыванию номера в колонну, попросив положить руку на плечо впереди стоящего.
    Некоторые номера повторяются и Солюшн Иванович (тренер) идёт вдоль вашей цепочки и делает в точности то, что написано в алгоритме.
    При этом там где он идёт, он расцепляет вашу цепочку формируя новую уже без дубликатов.
    При этом tail - это хвост новой цепочки, он на каждом шагу новый. Каждому новому хвосту следующим эементом (новым хвостом ставится очередной, но если у него отличный номер. Так тренер выпнет всех с неуникальными номерами из цепочки.

    Что конкрено не понятно?

    Вот поэкспериментируйте сами:
    class ListNode:
        def __init__(self, val, next=None):
            self.val = val
            self.next = next
    
        def __str__(self):
            tail = self.next and f', {self.next}' or ''
            return f'{self.val!r}{tail}'
    
        def __next__(self):
            if self.next:
                return self.next
            raise StopIteration
    
        def __iter__(self):
            item = self
            while item:
                yield item.val
                item = item.next
    
        def copy(self):
            return ListNode(self.val, self.next and self.next.copy())
        
        __repr__ = __str__
    
    
     ln=ListNode; l=ln(1, ln(1, ln(2, ln(3, ln(3)))))
    Ответ написан
    Комментировать
  • Как работает это решение задачи с LeetCode?

    @o5a
    Я понимаю, как tail меняется и зачем это нужно, но как head становится без дублей - не понимаю.

    tail - последний обработанный (недублирующийся) узел
    current - текущий узел
    Когда переходим к новому узлу (присваивая его текущему), проверяем, а не совпадает ли он с предыдущим (по значению).
    Если совпадает, то текущий узел мы просто выкидываем из цепочки, как бы прицепляя выход предыдущего узла к входу последующего, в обход текущего, за счет:
    tail.next = current.next
    Таким образом после проверки 2-го узла (повтор значения 1) получится такая картина:
    63d8f2d68cb94688580440.png
    Надеюсь, так понятнее ;)

    P.S. а если вопрос именно в том, почему head при этом тоже изменился, то head это просто ссылка на сам список (список = его первый элемент). Мы действиями изменили линковку списка.
    Ответ написан
    Комментировать
  • Django - Как оптимизировать группировку, чтобы было быстрее?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Попробуйте добавить индекс на пару полей (plu, sku). При выборке сортируйте по ним на упровне БД.
    Используйте itertools.groupby для группировки сперва по plu, а потом и по sku.
    Обходите группировки двумя циклами (один вложен в другой).
    Внутри внутреннего цикла уже можно использовать литерал генератора списка, чтобы получить список pack_type_id.
    Это позволит сразу собирать последовательно элементы словарей и не возвращаться к уже собранным.
    Если вашу структуру нужно поместить в какой-то внешний json-файл или отдавать в тело http-запроса в json-формате, то можно попробовать писать json с помощью какой-нибудь потоковой библиотеки вроде этой: https://pypi.org/project/jsonstreams/
    Это позволит не ждать по отдельности извлечение данных из БД, сборку структуры а пвмяти, а затем сериализацию ее в файл или в поток сокета. Всё будет делаться в рамках одного конвейера, что может оказаться более эффективным по времени.

    Однако вам и ваш способ стоило бы проверить на предмет "бутылочных горлышек" и понять что именно занимает у вас основное время работы вашего алгоритма.
    Возможно радикально ускорить процедуру и не удастся ввиду очень медленной БД или гиганского размера получающейся структуры.

    Расскажите подробнее куда вам нужна такая структура, какой у нее получается объём, куда вы её потом пихаете, как измеряете скорость, почему вам так критична эта скорость?
    Может быть проблема решается и иначе? К примеру, может оказаться, что вам не требуется синхронно возвращать всю структуру, или можно запрос и ответ развести в отдельные запросы, сделав интерфейс более отзывчивым.

    В общем опишите вашу задачу подробнее. Ну и есл что наисал не понятно, спрашивайте. Буду разьяснять детальнее.
    Ответ написан
    Комментировать
  • Как преобразовать значение при использовании dataclass?

    Vindicar
    @Vindicar
    RTFM!
    Я в таких случаях создаю фабричный метод.
    @dataclass
    class Person:
        first_name: str
        last_name: str
        bdate: date
    
        @classmethod
        def make(cls, first_name: str, last_name: str, bdate: str) -> 'Person':
            _bdate = datetime.strptime(bdate, '%Y%m%d').date()
            return cls(first_name=first_name, last_name=last_name, bdate=_bdate)
    
    data = {
        'first_name': 'Adam', 
        'last_name': 'Smith', 
        'bdate': '20220617'
    }
    person = Person.make(**data)

    Просто, коротко, позволяет реализовать любую логику приведения типов и вычисления значений по умолчанию, использует базовые механизмы Питона, при необходимости можно проигнорировать и использовать обычный конструктор (который мы не ломаем).

    Но вообще это неправильное распределение обязанностей. Обязанность датакласса - хранить данные, а не менять их представление. За смену представления пусть отвечает тот код, который получает значение строки.
    Ответ написан
    Комментировать
  • Как преобразовать значение при использовании dataclass?

    drygdryg
    @drygdryg
    Python-разработчик
    Возможно, вам стоит использовать Pydantic вместо dataclasses для этого: он позволяет создавать пользовательские валидаторы как отдельного поля, так и всех полей. Валидаторы можно использовать для преобразования типов данных. Что важно, он позволяет создавать пре-валидаторы, то есть те, которые будут применяться к полю перед стандартными валидаторами Pydantic. Например, вашу задачу можно решить так:
    from datetime import date, datetime
    
    from pydantic import BaseModel, validator
    
    
    class Person(BaseModel):
        first_name: str
        last_name: str
        bdate: date
    
        @validator('bdate', pre=True)
        def bdate_from_string(cls, v):
            if isinstance(v, str):
                return datetime.strptime(v, '%Y%m%d').date()
            return v
    
    
    data = {
        'first_name': 'Adam',
        'last_name': 'Smith',
        'bdate': '20220617'
    }
    
    person = Person(**data)
    print(person)


    Если вы не хотите использовать Pydantic, то можно посмотреть на продвинутую альтернативу dataclasses — attrs, может быть, там есть средства для решения вашей задачи.
    Ответ написан
    Комментировать
  • Как из ситуации start получить ситуацию end?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Другой вариант:
    git checkout F1^ # переместить HEAD на C3
    git commit –m "C10" # добавить коммит
    git rebase --onto HEAD master F3 # пересадить сюда кусок ветки F3
    git cherry-pick F1 # скопировать коммит С4 с вершины ветки F1

    Ничего лишнего и обошлось без временной ветки и без возни с хешами – только имена веток в командах. Алгоритм на четыре шага короче.
    Ответ написан
    Комментировать
  • Для чего нужные побитовые операции в Python?

    @deliro
    Например, флаги. Юзер может:
    0b1  # Читать
    0b10  # Писать
    0b100  # Редактировать
    0b1000  # Удалять
    
    0b1010  # юзер может писать и удалять, но не может читать и редактировать

    Итого, все флаги можно запихнуть в инт, который можно запихнуть в 1 байт.
    Ответ написан
    5 комментариев
  • Скопировать установленные poetry пакеты из образа slim в образ alpine и запустить?

    @dmtrrr
    Backend developer
    Почему бы не строить сразу на основе alpine?
    Виртуальное окружение никакой особой магии не делает, прочитайте про https://docs.python.org/3/using/cmdline.html#envva...
    Ответ написан
    Комментировать
  • Как избавиться от утечки памяти в связке Django+Celery?

    dizballanze
    @dizballanze
    Software developer at Yandex
    Можно установить параметр CELERYD_MAX_TASKS_PER_CHILD, чтобы раз в определенное количество выполненных заданий процесс воркера пересоздавался, в таком случае память будет очищаться. Но у вас явно где-то в коде есть утечки памяти, иначе воркеры бы не съедали столько памяти со временем.
    Ответ написан
    1 комментарий
  • Как разобраться в битовых масках или как их там?

    sergiks
    @sergiks Куратор тега ВКонтакте
    ♬♬
    Про двоичное представление чисел вы же в курсе?
    0 = 0000 0000
    1 = 0000 0001
    2 = 0000 0010
    3 = 0000 0011
    4 = 0000 0100
    5 = 0000 0101
    6 = 0000 0110
    7 = 0000 0111
    8 = 0000 1000
    9 = 0000 1001

    ... и так далее. До 232 или даже до 264 - зависит от системы, 32- или 64-битной и языка программирования.

    Позиции битов считаются справа налево. Крайний правый бит имеет позицию 0. Позиция бита – это степень двойки. Если бит установлен в 1, надо прибавить 2 в степени этой позиции.

    Например, число 3 = 0000 0011 означает 20 + 21 = 1 + 2 = 3.

    Примечательно, что степени двойки – 0, 1, 2, 4, 8, 16, 32, 64, ... – выражаются всего одним включённым битом, одной единичкой, остальные биты – нули.

    Битовые маски – это договорённость, что каждый бит (каждая позиция) значит что-то определённое, что может быть включено или выключено, 1 или 0. Как линейка выключателей.

    Например, с разрешениями ВКонтакте:
    1 - бит 0 - notify
    2 - бит 1 - friends
    4 - бит 2 - photos
    8 - бит 3 - audio

    У ВК линейка длинная, состоит из 32 «выключателей».

    Допустим, вашему приложению требуются разрешения photos и audio – биты 2 и 3 надо установить в 1, остальные 0. Это можно сделать простым сложением: 22 + 23 = 4+8 = 12. В двоичной системе: 12 = 0000 0000 0000 1100

    Для удобства вычисления ВК прямо пишут значения, которые надо прибавить, чтобы получить нужную битовую маску – итоговое число, которое вы передадите в метод АПИ для запроса разрешения.

    Ещё один пример, вам требуется стена wall и offline доступ в любое время. Смотрите в таблице, какие там числа: wall (+8192) и offline (+65536). Значит, вам нужно просить разрешения для маски 73728
    Ответ написан
    Комментировать