• Как получить все классы в файле .py?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Слово "лежат" вообще непонятное в контексте вопроса.
    Но можно попробовать угадать чего хочет автор.
    Я бы предложил такой вариант:
    module = importlib.import_module('my_module_name')
    classes = [
        value 
        for value in (
            getattr(module, name) 
            for name in dir(module)
        )
        if isinstance(value, type)
        and getattr(value, '__module__', None) == module.__name__
    ]
    Ответ написан
    Комментировать
  • Что написать на Python?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    1. Начните с утилит командной строки.
      • Освойте argparse, pathlib, yaml-конфиги, sqlite, концепцию пайпов, стандартные потоки ввода-вывода, цветной вывод в терминал.
      • Сделайте тулзу для автоматической разгрузки флешек от фотоаппарата. Пусть забирает все фотки с подключенной флешки, раскидывает по папкам с датами в каталоге хранилища, находит дубли, отделяет RAW'ы, правит EXIF, привязывает гео-метки по треку, индексирует в sqlite, находит похожие (opencv), находит и отделяет серии брекетинга для HDR, делает и восстанавливает бэкапы...
      • Сделайте CLI тулзу, которая качает спутниковые снимки региона и клеит для печати на фотообои или большой формат с рамкой, легендой и масштабной линеечкой.
    2. Попробуйте себя в бэкенде:
      • Освойте Flask.
      • Поиграйтесь с Django (сделайте себе уже сайт с вашими проектами, блогом, гостевой, галереей и админкой на готовых компонентах и дизайне).
      • Сделайте свой:
        • уменьшатель ссылок,
        • хостинг записок через QR-коды,
        • TODO-list,
        • анонимный интернет-чат на web-сокетах,
        • свою интернет-радиостанцию для семьи (с ротацией, новостными и погодными вставками, напоминалками из календаря семеных событий помощью TextToSpeech).
      • Попробуйте прикрутить к сайту донаты, принимать платежи.
      • Сделайте свой сайт, который присылает (можно за денежку) выбранную область карты в виде страниц атласа в масштабе и с легендой на основе рендера OSM и спутниковых снимков.
    3. Поиграйтесь с ML на классических примерах.
      • Научите вашу веб-камеру в ноуте вас узнавать, фотать незнакомые лица перед вашим компом.
      • Научите комп "видеть" вашего кота в комнате, понимать когда ему надо погулять.
      • Сделайте скрипт, который находит на записях видеорегистратора гос-знаки автомобилей и сохраняет в CSV вместе с таймингом по ролику.
    4. Поиграйтесь с MicroPython на NodeMCU (ESP8266).
      • Сделайте и закастомизируйте на нём интернет-wifi-радиоприёмник, или детский MP3-плеер для сказок с RFID-сканером и карточками.
      • Сделайте кормушку для котейки.
      • Робота-охранника или робота теле-присутствия для квартиры...
    5. Попробуйте себя в игрострое, если душа лежит. Я бы смотрел для начала в сторону веб-игр для соц-сетей. Да, придётся окунуться немного во фронтенд, но можно найти подельника, который учится фронту.
      • Можно замутить очередной http://www.milliondollarhomepage.com,
      • огромный скетч-холст для совместного рисования в стиле https://xkcd.com/1110/ на leaflet,
      • или свой граббер и просмотрщик тайлов этого комикса и похожих.
    6. Поделайте ботов для телеги - сейчас, похоже, все этим занимаются. Этот ресурс ломится от тупых вопросов по ним, присоединяйтесь.
      • Можно замутить своего бота для скачивания видоса с ютуба (и не только) по ссылке на основе YoutubeDL.
      • Сделайте бота для чата знакомств с гео-привязкой.
      • Бота, который мониторит RSS и репостит в чат.
      • Бота, который мониторит чат и репостит в RSS через сервер на Flask или статику.
      • Сделайте автоматическую качалку и публиковалку аудиокниг с рутрекера (принять ссылку или название, скачать торрент с нужными тегами, сгенерировать запись в RSS-фид, положить в публикуемый каталог, чтобы книги можно было качать и слушать как обычные подкасты, но еще и по команде из телеги).


    Ну сколько можно ныть и вопрошать "что делать"? Огромная куча всего еще не сделана или сделана через задницу. Сделайте тоже! Пусть получится хорошо или снова через задницу, но это будет ваш опыт!
    Публикуйте свои работы в opensource на github. Изучайте best practice, осваивайте CI/CD, Docker, TDD. Подпишитесь на технологические IT-подкасты. Заведите блокнот для базз-вордов и пишите туда всё что слышите незнакомое. Возьмите в привычку обзорно изучать новые вещи каждый день, каждую неделю.
    Со временем ваш профиль в гитхабе начнёт работать на вас. Крутые конторы постоянно мониторят открытые проекты и хантят разработчиков. Хороших программистов всегда не хватает!
    Дерзайте! Хватит ныть и колебаться! Идите делать!
    Ответ написан
    Комментировать
  • Как сопротивление может влиять на напряжение?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    А мне нравится другая метафора.
    Представьте, что у вас в школе есть длинный коридор (это проводник).
    Коридор полон слоняющихся в нём туда-сюда школьников (это электроны). В среднем в коридоре ток равен нулю.
    Вдруг (прозвенел звонок) и в коридор с одного конца стали ломиться новые школьники, движимые желанием идти нахрен подальще от класса (минус "батарейки"). Напор школьников - это потенциал. Он разный в начале и в конце коридора.
    Школьники давят с одного конца, а второй конц коридора открыт на улицу (плюс).

    Разница потенциалов (напоров) между началом и концом коридора - это напряжение.
    Представьте, что перед звонком в коридоре хаотично расставили стулья.
    Стулья мешают - это сопротивление. Школьники спотыкаются, ломают стулья, накаляют обстановочку (часть энергии желания школьников погулять тратится на это).
    Чем больше стульев, тем больше разница давления школьников между началом и концом коридора.

    Это был закон Ома для участка цепи.
    На примере школьников проще объяснять, чем на примере гидравлики. Так можно рассказать и про полупроводники, транзисторы, правило Кирхгофа... да что угодно.
    Ответ написан
    16 комментариев
  • Ошибка "string indices must be integers" как решить?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Если data['custom_answer'] равно тому, что вы привели в качестве примера (хотя закрывающую фигурную скобку забыли), то код сработает верно и без ошибок.
    "string indices must be integers"

    Такая ошибка бывает, если кто-то пытается обратиться по текстовому индексу к строке:

    In [1]: 'qwerty'['xxx']                                                         
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-6-994fc1ca7c86> in <module>
    ----> 1 'qwerty'['xxx']
    TypeError: string indices must be integers

    Возможно несколько причин ситуации:
    1. Вы привели не тот код. который выдал вам ошибку.
    2. Вы запутались в данных, что не удивительно если почитать ваши формулировки:
      Вот такой массив передаю в 'custom_answer'

      Теперь мне нужно результат получить и "забрать".


    3. Вы не полностью привели пример данных и среди словарей в списке под ключом 'groups' у вас затесалась обычная строка к которой вы и обратились по текстовому индексу 'full_name'.

    Ответ написан
  • Ввод строки с добавлением в список?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    def task_v1(): 
        """
        Принимает на вход строки (признак конца ввода - пустая строка),
        сохраняет их в список без повторений.
        Печатает сохранённые в списке строки.
        """
        lst = []              # делаем пустой список
        s = input()           # вводим первую строку
        while s:              # пока введённая строка не пуста:
            if s not in lst:  # если строка не в списке:
                lst.append(s) # добавляем её
            s = input()       # принимаем следующую строку
            
        print('\n'.join(lst)) # объединяем все строки через абзац и печатаем
      
    
    def task_v2():
        """
        Также принимает на вход строки, но сохраняет их в Счётчик.
        Счётчик и порядок добавления запоминает и считает количество повторов.
        Печатает ключи счётчика.
        """
        from collections import Counter  # импортируем класс счётчика
        c = Counter()                    # создаём экземпляр Счётчика
        s = input()                      # вводим первую строку
        while s:                         # пока введённая строка не пуста:
            c[s] += 1                    # подсчитываем её счётчиком
            s = input()                  # принимаем следующую строку
            
        print('\n'.join(c))             # объединяем ключи счётчика через абзац и печатаем
          
    
    def task_v3():
        """
        То же, что и v2, но в функциональном стиле
        """
        from collections import Counter  # импортируем класс счётчика
        print(                        # функция печати, которой даём строку...
            '\n'.join(                # которую формируем объединяя через абзац элементы (строки) полученные...
                Counter(              # созданием экземпляра счётчика, которому в конструктор передаём...
                    iter(input, '')   # итератор, который будет вызывать функцию input пока она не вернёт '', 
                                      #   а результаты всех вызовов (кроме последнего) будет возвращать по мере
                                      #   запроса их конструктором Счётчика (для подсчёта)
                ).keys()              # и формированием списка уникальных ключей (строк) из счётчика.
                                      #   ктсати `.keys()` совершенно не нужен. Итаратор по счётчику возвращает ключи.
            )
        ) 
    
    
    def task_v3_1():    
        """В одну строку это выглядит не так ужасно:"""
        print('\n'.join(Counter(iter(input, ''))))
    
            
    def task_v4():
        """
        То же, что и v3, но расписано на этапы и сохранено в промежуточные переменные
        """
        from collections import Counter  # импортируем класс счётчика
        it = iter(input, '')   # создаём итератор, который по мере запроса у него
                               #   очередных значений будет вызывать функцию
                               #   input пока она не вернёт пустую строку
    
        c = Counter(it)        # создаём экземпляр Счётчика и в качестве аргумента
                               #   даём ему наш итератор. тем самым мы предлагаем
                               #   нашему новому счётчику запросить все значения, 
                               #   что отдаст итератор и посчитать количество
                               #   вхождений каждой уникальной строки
    
        unic = c.keys()        # получаем у счётчика его ключи, то есть все 
                               #   уникальные строки, которые он считал.
                               #   Приятный побочный эффект, доступный в современном
                               #   Питоне - это сохранение порядка ключей по мере ввода.
                               # Этот шаг не обязателен, поскольку счётчик итерируется по ключам.
    
        result_text = '\n'.join(unic)  # объединяем все уникальные строки через абзац. Вместо unic можно просто указать `c`.
        print(result_text)             # и печатаем их


    На баше можно совсем коротко, но порядок не сохраняется:
    $ py "set(iter(input,''))"
    $ cat<<""|py -l "set(l)"
    Чтобы сохранялся - подлиннее получится:
    $ cat<<""|py -l "collections.Counter(l)"
    py "collections.Counter(iter(input, ''))"
    Ответ написан
    Комментировать
  • Почему бот выдает ошибку No such file or directory: 'temp/?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    1. Вынесите строку `temp/` в отдельную переменную.
    2. Проверяйте при старте бота этот путь на существование.
    3. Если такого пути нет, можно его либо создать, либо выдать соответствующее сообщение об ошибке и завершить работу.

    Если путь без "/" вначале , то это относительный путь от текущего на момент запуска скрипта.
    Если бот лежит по пути: `/home/my_username/my_bot_folder/my_bot.py`
    И запускается так:
    `my_bot_folder/my_bot.py`
    То текущий каталог на момент запуска у вас домашний:
    `/home/my_username`
    И бот будет пытаться писать картинки по пути типа:
    `/home/my_username/temp/2345435666hashtralala.png`.
    Если у вас в домашнем каталоге нет папки temp, то будет эта ошибка.
    Нужно создать папку temp в нужном месте.
    Можно обработать эту ошибку и в ее обработчике написать `print('please make temp folder in:', os.getcwd())`
    Ответ написан
    Комментировать
  • Как посчитать сумму одинаковых значений по одной колонке, но разных по другой?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Уберите T.TRANZTIME из группировки и из селекта. Там два разных значения.
    Если вам обязательно надо какое-то показать (например последнее), то выкиньте его из группировки, а в селекте поставьте там агрегатор, например, max.
    Вот так ваш Сидоров просуммируется на этом датасете в одну строку:
    SELECT
        C.CODE AS "Табельный",
        C.NAME AS "Ф.И.О.",
        T.TRANZDATE AS "Дата",
        max(T.TRANZTIME) AS "Время",
        T.INFOSTR AS "Карта",
        sum(T.SUMM) AS "Сумма"
    FROM 
        DOCUMENT D
            LEFT JOIN TRANZT T ON D.ID = T.DOCUMENTID
            JOIN CLIENT C ON D.CLIENTID = C.ID
    WHERE
          T.TRANZDATE >='20.02.2020' AND T.TRANZDATE <='20.02.2020' AND
          T.TRANZTIME >='18:55:00' AND T.TRANZTIME <='23:59:59' AND
          D.STATE = 1 AND
          D.ISFISCAL = 1 AND
          D.CLIENTID >=0 AND
          T.TRANZTYPE = '36'
    GROUP BY
        C.CODE,
        C.NAME,
        T.TRANZDATE,
    --    T.TRANZTIME,
        T.INFOSTR
    --    ,T.SUMM

    Но на этом ваши проблемы не кончатся. В вашем SQL много других косяков:
    1. Какой смысл делать такое условие: T.TRANZTIME <='23:59:59'? Любое время будет ему удовлетворять.
    2. Если ваши дата и время связаны, то есть определяют какой-то момент во времени, то их нужно хранить и фильтровать как единое значение, иначе вы сами не заметите как наткнётесь на не очевидную (для новичка) ошибку неконсистентности. К примеру, событие Б позднее события А, но А произошло вечером, а Б утром (другого дня). При вашем отдельном сравнении дат и времён может получиться некорректность из-за того, что время (без даты) события А > времени (без даты) события Б. Соедините дату и время в единое поле datetime или соединяйте их каждый раз когда делаете условную фильтрацию по временнОму диапазону.
    3. Зачем вы группируете по T.SUMM, если собирались агрегировать это поле?
    Ответ написан
    2 комментария
  • В чём может быть ошибка в коде?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Метод .send_document() не принимает аргументов. А вы ему туда пихаете два лишних.
    Ответ написан
    Комментировать
  • Способ пакетной обрезки изображения?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Ответ написан
    Комментировать
  • Как сохранить неизвестное количество элементов из массива в неизвестное количество переменных?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Попробуйте для каждого значения из json, которое вы хотите поместить в отдельную ячейку, собрать ключ, состоящий из имён всех ключей родительских элементов. Для списков это может быть индекс.
    Я показывал такое вот в этом вопросе: Какой программой можно быстро сделать из json в csv?
    Ответ написан
    Комментировать
  • Какое максимальное количество гигабайт можно загрузить в Telegram?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Разглашать такие ограничения - это было бы стратегической ошибкой со стороны Дурова по ряду причин:
    1. Пока объёмы не создают проблем и укладываются в существующие мощности, создать иллюзию безлимитного изобилия дискового пространства - это хороший PR ход подогревающий интерес к мессенджеру.
    2. Как только лимиты будут четко очерчены, сразу появятся желающие их "пощупать". Таких желающих будет много, и они начнут ныть, когда лимиты придётся урезать из-за этого. Всякие любители нецелевого использования халявы узнав про конкретные лимиты станут плодить и заливать под завязку аккаунты для хранения своего барахла. Очевидно. что от таких паразитов Телеграму только вред, а ныть они будут на весь инет жалуясь, что либо лимиты постоянно урезают и "чего нам теперь ждать дальше", либо что этих паразитов банят за не целевое использование сервиса, а они "просто хотели другу архивы с лабами переслать". Ага.
    3. В лицензии наверняка (я правда не читал, ибо лень) написано, что телегу можно юзать как можно и нельзя как нельзя. Но банить за такое нужно только самых упоротых и по лотерее, чтобы нельзя было вычислить строгий алгоритм и делать всё, чтобы брать максимум халявы, но не попадаться на бан.

    Я понимаю, что вопрос вы задаёте с другой стороны окопа. Я понимаю вашу мотивацию.
    Однако если бы я разрабатывал похожую систему, то постарался бы:
    • максимально расплывчато описать ограничения;
    • максимально обобщенно описать правила (чтобы можно было любого злоупотреблятеля забанить, и нельзя было докопаться, мол, почему вот его не банят, а меня забанили);
    • максимально неочевидными и непостоянными сделать правила блокировок самых неудобных и геморройных пользователей.
    Ответ написан
    1 комментарий
  • Насколько вредны телевышки?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Я однажды был лично свидетелем такой истории.
    Поставили в одном небольшом селе на 5к жителей вышку сотовой связи. Сперва на том месте стояла старая тридцатиметровая вышка релейной связи - вся ржавая и, естественно, давно неиспользуемая. Потом эту вышку "спилили" на металлолом, что, говорят было увлекательно наблюдать. И вот опсосы (МТС кажется, но это не важно) поставили вышку гораздо выше. ХЗ, метров 70, может.
    Спустя какое-то время у жителей окрестных домов вокруг вышки стали наблюдаться проблемы со здоровьем. Пошли жалобы, мол, участились головные боли, с суставами проблемы полезли, с печенью, почками... В общем народ уже чуть ли не с вилами стоит у сельсовета, мол, давайте, выпиливайте уже свою щайтан-вышку, мочи нету терпеть, вымираем. Длилось это несколько месяцев, надо сказать. Не прям революция, но всё на серьёзных щах.
    Короче, очередной гвалт на эту тему среди местного населения по случаю какого-то сельского события, а тут "Сельский" (глава администрации, типа) на своём "бобике" подкатывает и тормозит с кем-то за ручку поздороваться. Ну деревня, так принято.
    В общем народные массы к нему с наболевшим и обращаются, мол, всё, жизни нет, вышка эта басурманская отравила всех, головы болят, люди мрут.
    Председатель (блин, ну не председатель, да, сельским его все кличут, или по имени-отчеству, само собой) посмотрел так задумчиво на страдальцев, покачал головой, цыкнул зубом, а тут и народ притих... А Сельский и говорит так горестно и с сочувствием: "Не, народ, не получится ничего. Если вас сейчас уже эта вышка так припекла да искалечила, то что будет когда ОНИ её включат! Звизда всем настанет вообще." Ну или как-то так.
    Оказывается опсосы вышку-то построили, оборудование поставили, а что-то там настроить и подготовить - тянули. Вышку поставили быстро, и стояла она готовенькая несколько месяцев не подключённая. Вопрос этот, как я понял, не афишировался, чтобы пацаны-паркурщики местные на неё не лазили лишний раз. Стращали всех, что сгоришь влёт, как спичка, если под луч попадёшь.
    Короче смех-смехом, история звучит как пипец-рваный баян, но даже самые душные анекдоты порой и не раз снова и снова случаются в реальной жизни.

    А называется эффект от такой телевышки не иначе как "ноцебо".
    Ответ написан
    2 комментария
  • Куда двигаться(Python)?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Хватит "учить". Это не продуктивно. Просто делайте.
    Начните небольшой pet-project в той области, в какой лично вам интересно. Интерес нужен чисто для мотивации. Если вы супер-мотивированный человек, то и так можете делать всё что угодно.
    Вот какой-то тип рассуждает на ютубчике про то, чем заняться юным программистам. Специально не искал, просто промелькнуло на периферии и ваш вопрос напомнил. Он не про питон говорит, но это не важно.

    От себя могу порекомендовать следующее:
    1. Вести блокнотик для баззвордов. Всё, что слышите вокруг себя касательно предметной области, все непонятные слова и термины выписывайте в блокнотик и, на досуге, гуглите. Если тема и термин релевантны вашей области интересов и выбранному стеку технологий, то вникайте глубже, если не очень, то читайте поверхностно. Со временем новые слова в блокнотик станут попадать всё реже, а старые после нескольких попаданий запомнятся и тоже перестанут. Вы станете эрудированным в своей области.
    2. Читайте чужие исходники. Нет, не учите. Нет глубоко лезть не надо. Просто ищите на гитхабе для себя интересное и читайте как это сделали, думайте как сделали бы вы.
    3. освойте базовые вещи:
      • системы контроля версий в целом и git в частности;
      • концепцию TDD и какую-нибудь из стандартных библиотек для юнит-тестирования;
      • принципы unix-way; стандарты CLI; bash; концепцию пайпов (в linux и windiws);
      • освойте регулярные выражения, порешайте кроссворды.
      • соберите для себя шаблоны стандартных приложений для быстрого старта проектов: сайт с админкой и авторизацией; CLI-утилита; REST API сервис...
      • освойте концепцию docker контейнеризации;
      • освойте CI/CD...



    Где-то к середине этого списка ваш вопрос станет гарантировано не релевантен для вас.
    Ответ написан
    Комментировать
  • Как можно заменить способ выбора случайной величины с меньшим потреблением памяти, или есть ли альтернатива random.choises()?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Как минимум можно передавать аргументы в choices не в виде списков, а в виде генераторов.
    r=range(20, 2*10**7);
    print(choices(r, (1/x for x in r)))


    from guppy import hpy; from random import choices; h=hpy(); print(h.heap()); r=range(20, 2*10**7); print(choices(r, (1/x for x in r))); print(h.heap())                                             
    Partition of a set of 257681 objects. Total size = 30586285 bytes.
     Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
         0  77410  30  8264794  27   8264794  27 str
         1  69723  27  5198776  17  13463570  44 tuple
         2  28709  11  2133716   7  15597286  51 bytes
         3  14447   6  2089272   7  17686558  58 types.CodeType
         4  15188   6  2065568   7  19752126  65 function
         5   2013   1  1932488   6  21684614  71 type
         6   3316   1  1515992   5  23200606  76 dict (no owner)
         7    684   0   937144   3  24137750  79 dict of module
         8   2013   1   932560   3  25070310  82 dict of type
         9   1866   1   633536   2  25703846  84 set
    <863 more rows. Type e.g. '_.more' to view.>
    [9585326]
    Partition of a set of 257636 objects. Total size = 30579517 bytes.
     Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
         0  77406  30  8264562  27   8264562  27 str
         1  69724  27  5198832  17  13463394  44 tuple
         2  28709  11  2133716   7  15597110  51 bytes
         3  14447   6  2089272   7  17686382  58 types.CodeType
         4  15186   6  2065296   7  19751678  65 function
         5   2013   1  1932488   6  21684166  71 type
         6   3310   1  1514552   5  23198718  76 dict (no owner)
         7    684   0   937144   3  24135862  79 dict of module
         8   2013   1   932560   3  25068422  82 dict of type
         9   1866   1   633536   2  25701958  84 set
    <859 more rows. Type e.g. '_.more' to view.>

    Но что-то мне подсказывает, что это можно математически привести к операции, работающей за O(1) по времени.

    UPD

    Залез-таки в исходники и считаю важным отметить, что моё решение не полностью решает вашу проблему с памятью.
    Вот что (примерно) делается под капотом:
    def choices(self, population, weights=None, *, cum_weights=None, k=1):
            """Return a k sized list of population elements chosen with replacement.
    
            If the relative weights or cumulative weights are not specified,
            the selections are made with equal probability.
    
            """
            random = self.random
            if cum_weights is None:
                if weights is None:
                    _int = int
                    total = len(population)
                    return [population[_int(random() * total)] for i in range(k)]
                cum_weights = list(_itertools.accumulate(weights))
            elif weights is not None:
                raise TypeError('Cannot specify both weights and cumulative weights')
            if len(cum_weights) != len(population):
                raise ValueError('The number of weights does not match the population')
            bisect = _bisect.bisect
            total = cum_weights[-1]
            hi = len(cum_weights) - 1
            return [population[bisect(cum_weights, random() * total, 0, hi)]
                    for i in range(k)]

    Для нашего случая функцию можно упростить до:
    def choices(a=20, b=2*10**7, k=1):
        from random import Random
        import itertools
        from bisect import bisect
        random = Random().random
    
        n = b - a
        population = range(a, b)
        weights = (1/x for x in population)
        cum_weights = list(itertools.accumulate(weights))
        # get_weight = lambda idx: 1 / (a + idx)
        # get_cum_weight = lambda idx: ????
    
        total = cum_weights[-1]
        hi = len(cum_weights) - 1
        return [
            population[bisect(cum_weights, random() * total, 0, hi)]
            for i in range(k)
        ]

    И здесь видно, что происходит материализация генератора в список:
    cum_weights = list(itertools.accumulate(weights))
    Это уже не три огромных списка, а всего лишь один, но эту проблему тоже можно решить.

    Короче. Весь вопрос в том, как вычислить за O(1) следующую сумму ряда:
    С[n]=1/(a+0)+1/(a+1)+1/(a+2)+...+1/(a+n)
    Если это научиться вычислять за O(1), то bisect(cum_weights, random() * total, 0, hi) будет вычисляться за O(log2(n)). И такая же сложность будет у всей функции в целом.
    Однако это не предел. Думаю можно сразу вычислять индекс искомого числа за O(1) без двоичного поиска. Но это уже вы задайте как вопрос с тегом "математика".
    Ответ написан
    Комментировать
  • Ошибка CORS при использование aiohttp и Angular8 как правильно настроить?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Запустите рядом nginx (есть и портабл, и в докере можно стартануть) и пропишите ваши сервера как upstream через nginx в качестве реверс-прокси.
    Это повесит все ваши сервера на один порт и приблизит ваше девелоперское окружение к тому, что будет у вас в проде.
    Можно в hosts прописать для 127.0.0.1 какой-нибудь домен, чтобы всё ещё сильнее похоже было на прод.
    Проблема уйдёт, когда origin будет совпадать с адресами вызова api.
    Но, очевидно, можно и настройками cors побороть. Вопрос только зачем, если ваш апи предназначен для вашего сайта, а не для публикации для неограниченного круга сторонних сайтов.
    Ответ написан
    Комментировать
  • Как спарсить координаты городов?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Попробуйте вытащить данные из базы openstreetmap.
    Снапшот их базы доступен бесплатно.
    Вот есть штука для импорта в posgtres. Надо сказать, что кроме неё есть еще osm2pgsql, который делает примерно то же самое.
    На OSM Wiki можно найти теги, которыми промаркированы точки городов. А дальше вам, возможно, и ваш список названий не нужен будет, там они все (эти города) есть, причем на нескольких языках.

    Вот, кстати, был даже вопрос про фильтрацию на этом ресурсе.
    Ответ написан
    Комментировать
  • Как выполнить нормализацию адресов?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    После того, как открыли для себя сервис https://dadata.ru/, вообще перестали тратить время и деньги на собственные костыли из граблей. Сервис просто огонь.
    Для нас онлайн режим и скорость обработки не критична, поэтому мы даже уложились в бесплатный пробный тариф.
    Вроде бы у них были решения по установке их ПО в закрытом контуре, а это не что иное, как нужный вам оффлайн. Правда тут уже бесплатно не прокатит точно.

    До дадаты этот вопрос решался жутким нагромождением фильтров, регекспов с заменами и человеко-машинного совокупления.
    Общая схема годится не только для адресов, а вообще любых грязных данных:
    1. Входной датасет сохраняем в CSV и НИКОГДА не меняем.
    2. Обработка многоступенчатая. Каждая ступень состоит из фильтра и модификатора. Фильтр решает применим ли модификатор к каждой записи. Модификатор применяет свою модификацию если фильтр разрешил.
    3. Отладочный выхлоп, который показывает и позволяет быстро просмотреть полностью внесённые изменения.
    4. Каждая ступень должна делать минимальное однотипное улучшение максимально большого числа строк. Цель - каждой ступенью уменьшать разнообразие проблем, увеличивать регулярность, стандартизировать.
    5. При огромных входных датасетах можно сохранять промежуточный выхлоп, но в общем очистка должна выглядеть как пайп их последовательных ступеней обработки.
    - Очень часто бывает, что какая-то ступень незаметно ломает данные, а понимаешь это уже поздно, когда последующие ступени реализованы и отлажены, и сильно опираются на результат ломающей. Благодаря ступенчатости и иммутабельности процесса всегда можно зипнуть текущее состояние с любым предыдущим шагом и очередным фильтром заменить необходимые куски.
    - Часто бывает, что какая-то из ступеней улучшив отдельные записи убирает характерные признаки для фильтрации элемнтов для другой ступени. Благодаря такому инкрементальному процессу можно переставлять ступени местами.
    - При внесении ступенью изменения в запись. ступень должна оставлять свою сигнатуру в отдельном столбце. Удобно для поиска проблем.

    Расскажите подробнее почему не рассматривается онлайн. Заинтриговали.
    Ответ написан
    3 комментария
  • Как подставить в параметры команды имя текущего каталога?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    echo %cd%
    но... arj? В 2020 году? Серьёзно?...
    Ответ написан
    4 комментария
  • Как в JSON выбрать все имена?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Нифига из условия задачи не ясно. Я понял вас так:
    echo '[{"name": "ha-collector-data-test1"}, {"name": "ha-collector-data-test2"}]' | py "[item['name'] for item in json.load(sys.stdin) if item['name'].startswith('ha-collector-data-')]"

    Или из питоновского кода:
    import json
    
    FILTER='[{"name": "ha-collector-data-test1"}, {"name": "ha-collector-data-test2"}, {"name": "ha-collector-data-test3"}]'
    filter_data = json.loads(FILTER)
    items = [
        item['name']
        for item in filter_data
        if item['name'].startswith('ha-collector-data-')
    ]
    Ответ написан
  • Почему получается неверная кодировка при парсинге html?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Там страница в cp1251. Эта кодировка указана в специальном теге на странице:
    <meta http-equiv="content-type" content="text/html; charset=windows-1251">

    При копировании из браузера система учитывает эту кодировку и конвертирует её на лету. Вам следует конвертировать html-код в utf-8, перед парсингом, либо конвертировать отдельно вырезанные фрагменты.
    Ответ написан
    Комментировать