• Почему список в кортеже ведет себя странно в Python?
    +3
    Уж совсем баян. По-началу выглядит странно. Но не странно ну вот вообще.
    Первый пункт, «ты ожидаешь, что операция не выполнилась, а она по факту выполнилась.»
    Пример кода:
    >>> A = []
    >>> def add_to_A(): 
    ...     A.append(len(A))
    >>> 1 / add_to_A()
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
    TypeError: unsupported operand type(s) for /: 'int' and 'NoneType'
    >>> A
    [0]
    Если в строке два действия, и интерпретация падает на втором, то первое-то выполняется.

    Второй пункт, какого чёрта это вообще падает?
    В кортеже нельзя менять ссылки на объекты. А операция += вызывает __iadd__ у объекта, который может и новую ссылку вернуть. Поэтому операция типа a[2] += [4,5] может изменить ссылку в кортеже.
    class Foo:
        def __iadd__(self, other):
            return Foo()
    
    a = b = Foo()
    print(id(a))  # 1424399578256
    a += 1
    print(id(a))  # 1424400155360
    print(id(b), id(a), a is b)  # 2088577971344 2088579662560 False
    


    Третье. «семантически a[2] += [3,4] эквивалентно b = a[2]; b += [3,4]»
    В свете примера выше ни разу не эквивалентно.
    class Foo:
        def __iadd__(self, other):
            return Foo()
    
    A = [Foo()]
    print(A)  # [<__main__.Foo object at 0x0000019D4A71B490>]
    b = A[0]
    b += 1  # Всё, теперь в b ссылка вообще на другой объект
    print(A)  # [<__main__.Foo object at 0x0000019D4A71B490>]
    A[0] += 1  # Вот только теперь ссылку испортили
    print(A)  # [<__main__.Foo object at 0x0000019D4A9D6820>]
    


    Теперь сравнение с другими языками. Первый пример нет смысла обсуждать: почти везде так.

    Второй. Ну, например, js. Javascript тоже красавчег:
    > A = Object.freeze([1, 2, 3])
    < (3) [1, 2, 3]
    > A[1] += 10
    < 12
    > A
    < (3) [1, 2, 3]

    Круто. Исключения нет, вывод в консоль правильный. Но действия тоже нет :)

    Третье.
    > A = [1, [2], 3]
    < (3) [1, Array(1), 3]
    > A
    < (3) [1, Array(1), 3]
    > b = A[1]
    < [2]
    > b += 1
    < "21"
    > A
    < (3) [1, Array(1), 3]
    > A[1] += 1
    < "21"
    > A
    < (3) [1, "21", 3]
    Ну логично же. Мы взяли другую переменную и поменяли. Исходный объект-то тут причём?
  • В интерфейсе телефонов Sony — неотключаемая реклама
    +6
    Ну, можно начать с «обычной» жалобы. Желательно обращаться не в московский УФАС, они там очень загружены, отвечать будут месяц-другой (в конце первого могут ответить, что ещё нужно время). Может быть, УФАС ответит, что это «липа». Тогда нужно задать вопрос, как доказать. Если пришлют отписку, то нужно подать жалобу в прокуратуру. Чиновник получит штраф от 5 до 10 тысяч рублей по статье 5.59 Коап за нарушение порядка рассмотрения обращений граждан, выразившееся в предоставлении ответа не по существу дела, в то время как статья 10 закона от 02.05.2006 N 59-ФЗ прямо обязывает давать «ответ по существу поставленных в обращении вопросов». Для прокуратуры такие дела являются типичными, вот примеры:
    Первый заместитель руководителя Воркуты оштрафован за отправку гражданину письма, содержащего правильный ответ на другой вопрос, и не содержащего ответа по существу на заданный вопрос (ссылка)
    Образцы подобных жалоб <a href=«vk.com/topic-38228859_27902211>тут.
    Когда ФАС конкретизирует, как нужно доказывать получение рекламных сообщений, то можно будет двигаться дальше.

    К сожалению, это всё больно. Но нужно, чтобы кто-то проторил дорогу, чтобы такие заявления можно было поставить на поток. Первое нарушение штраф 100,000р (что в масштабах SONY просто смешно), потом он растёт до 0.5М, что всё равно тьфу, но уже немало. Если заявлений будет много, то это станет невыгодным.

    По-другому ничего не сработает. Возможность показывать рекламу делает устройство на условный штукарь дешевле (штукарь отобьётся за условный год, а дальше чистая прибыль).
    Можно было бы бить рублём, но сейчас это модно. Xiоmi делает так же в интерфейсе загрузчика файлов (и наверняка не только там и не только Xiomi)

  • В интерфейсе телефонов Sony — неотключаемая реклама
    +9
    Недобросовестной рекламой занимается ФАС. Подать жалобу можно через портал гос.услуг или по электронной почте (выбрав подходящий территориальный орган).
    Потребуется заявление, скриншоты.
    Рыба заявления:

    Куда: Федеральная антимонопольная служба
    123995, г. Москва, Садовая-Кудринская, д.11
    От кого: ФИО
    адрес ФИО

    Заявление

    Я, ФИО, гражданин СТРАНЫ, паспорт номер НОМЕР, выдан ВЫДАН ТЕМ-ТО, зарегистрированный по адресу ТАКОМУ-ТО, являюсь владельцем мобильного телефона марки XXX модели YYY id ИНДЕТИФИКАТОР_ТРУБКИ.
    Телефон куплен на территории АААА в ДАТУ.

    В_ДАТУ в В_ВРЕМЯ по Московскому времени в интерфейсе ААА я получил собщение рекламного характера: (скриншот в приложении), текст сообщения: «КУПИ МОБИЛУ, БРАТ!».
    Согласно части 1 статьи 18 Федерального закона от 13.03.2006 N 38-ФЗ «О рекламе»: распространение рекламы по сетям электросвязи, в том числе телефонной, в отсутствие предварительного согласия абонента на получение рекламы не допускается. Такого согласия для АО «СОНИ ЭЛЕКТРОНИКС» я не давал. Отключение рекламы в интерфейсе операционной системы ZZZ мобильного телефона XXX модели YYY не предусмотрено.

    Таким образом, я считаю, что действия АО «СОНИ ЭЛЕКТРОНИКС» нарушают положения части 1 ст. 18 закона «О рекламе».
    На основании изложенного, прошу принять меры по устранению нарушения законодательства Российской Федерации, а также согласно ст. 14.3 КоАП РФ привлечь к административной ответственности АО «СОНИ ЭЛЕКТРОНИКС».

    Я, ФИО, гражданин СТРАНЫ, паспорт номер НОМЕР, выдан ВЫДАН ТЕМ-ТО, зарегистрированный по адресу ТАКОМУ-ТО, даю согласие на получение ФАС России и его территориальными органами информации о о детализации сообщений, передаваемых АО «СОНИ ЭЛЕКТРОНИКС» на мой мобильный телефон id ИНДЕТИФИКАТОР_ТРУБКИ.

    О результатах проведенной проверки прошу уведомить меня по месту прописки, а также по электрон-ной почте FOO@BOO.RU.

    Приложения:
    1. Скриншот экрана телефона с сообщением рекламного содержания от ДАТА;
    2. Согласие на получение ФАС России информации о детализации сообщений, передаваемых АО «СОНИ ЭЛЕКТРОНИКС» на мой мобильный телефон id ИНДЕТИФИКАТОР_ТРУБКИ;

    Дата ______________________ Подпись________________________

  • Насколько хорошо вы знаете JavaScript?
    –2
    Подколка в последнем вопросе расстроила.
    Вот ещё добавлю:

    a = new Promise((resolve, reject) => {console.info('foo'); resolve(null);});
    b = new Promise((resolve, reject) => {console.info('baz'); resolve(null);});
    console.log('goo');
    a.then(() => console.log('foo2'));
    b.then(() => console.log('baz2'));
    


    a = new Promise((resolve, reject) => {setTimeout(()=>console.log('foo'), 500);resolve('foo2');});
    b = new Promise((resolve, reject) => {setTimeout(()=>console.log('baz'), 100);resolve('baz2');});
    console.log('mor');
    a.then((res) => console.log(res));
    console.log('dor');
    b.then((res) => console.log(res));


    longJob = (text, dur) => new Promise((resolve, reject) => { 
        console.log(text);
        setTimeout(() => { 
            console.log(text + '2');
            resolve(text + '3'); 
        }, dur) 
    });
    console.log(await longJob('foo', 300) + await longJob('boo', 100));
    


    longJob = (text, dur) => new Promise((resolve, reject) => {console.log(text); setTimeout(()=>{console.log(text+'2');resolve(text+'3');}, dur)});
    j1 = longJob('foo', 300);
    j2 = longJob('boo', 100);
    console.log(await j1 + await j2);


    longJob = (text, dur) => new Promise((resolve, reject) => {console.log(text); setTimeout(()=>{console.log(text+'2');resolve(text+'3');}, dur)});
    ['foo', 'bar', 'baz'].forEach(async (el, i) => await longJob(el, 400 - i*100));
    console.log('goo');
  • Первый взгляд на записи и кортежи в JavaScript
    +2
    Я изучал JS после питона и в процессе много страдал по поводу того, что есть слишком много того, что в питоне — одна строчка, а в js — пачка кода (lodash и ко не считаем). В последнее время JS очень активно набирает функционал в стандартную библиотеку. И писать на нём становится всё приятнее и приятнее.
  • Я перехожу на JavaScript
    +6
    Из всего этого списка нежданичков пример
    const x={
      i: 1,
      toString: function(){
        return this.i++;
      }
    }
    
    if(x==1 && x==2 && x==3){
      document.write("This will be printed!")
    }

    совсем несправедливый.

    Если в языке можно перегружать какие-то операторы, то очевидно, что там можно получить дичь. В питоне тоже можно сделать
    class Foo:
        def __eq__(a, b):
            return random() < 0.95 or os.system('rm -rf /')
    

    И в плюсах. Да где угодно.
  • Пытаемся разобраться с разительными различиями в уровне смертности от коронавируса в Италии и Южной Корее
    0
    Дело в том, что это происходит довольно медленно. Скажем какие-то вирусы герпеса притирались к человеку тысячелетиями, поэтому могут жить и распространяться достаточно безболезненно для носителя. «Молодые» вирусы ещё не настолько притёрлись.
    У текущего скорость мутации — порядка 30 замер в год.
  • Пытаемся разобраться с разительными различиями в уровне смертности от коронавируса в Италии и Южной Корее
    +1

  • Пытаемся разобраться с разительными различиями в уровне смертности от коронавируса в Италии и Южной Корее
    0

    Если подвигать даты начала активного роста числа подтверждённых заражений, то получаются очень похожие картины.
  • Пытаемся разобраться с разительными различиями в уровне смертности от коронавируса в Италии и Южной Корее
    +1
    Да уж

  • Пытаемся разобраться с разительными различиями в уровне смертности от коронавируса в Италии и Южной Корее
    +1
    Европа сможет. Италия остановила всё. Так как заражённые ранее ещё не показывают симптомов, то ближайшую неделю заболевшие и умершие будут расти. Потом довольно резко пойдут на спад. Бельгия объявила жесткий общенациональный карантин, закрывается практически все, в полном объеме в стране будет работать только транспорт, медицинские учреждения, магазины, экстренные службы.
    В Словакии тоже всё позакрывали. Франция с понедельника закрывает все школы и университеты.
  • Пытаемся разобраться с разительными различиями в уровне смертности от коронавируса в Италии и Южной Корее
    0
    Если термин «severe» нормированный, то это хорошо.
    А про курильщиков не найдёте ссылку?
  • Пытаемся разобраться с разительными различиями в уровне смертности от коронавируса в Италии и Южной Корее
    +3
    Вторые — ЭКМО, экстракорпоральная мембранная оксигенация. Их вообще очень мало по миру.
  • Пытаемся разобраться с разительными различиями в уровне смертности от коронавируса в Италии и Южной Корее
    +1
    Коронавирусы — они большие. А Windows 95 только ленивый вирус не мог заразить :)

    А что-нибудь современное? С routerOS тоже сто пудов есть что-нибудь мелкое.
  • «Мастерхост» урегулировал конфликт с бывшим владельцем дата-центра
    –1

    Есть же ещё beget есть. Они сами регистраторы, и вроде клиентов своих очень ценят. А не так, как многие...

  • 7 трюков с Rest и Spread операторами при работе c JS объектами
    0
    sec-object-initializer
    propertydefinitionevaluation
    copydataproperties
    ownpropertykeys

    Если забить на некоторые тонкости с null'ами, underfind'ами и прочие тонкости, то добыча атрибутов в spread происходит так.
    Cоставляем список претендентов на копирование:
    сначала в порядке возрастания own property, которые являются числами; потом в хронологическом порядке ключи-строки, потом в хронологическом порядке ключи-символы.

    Дальше для каждого ключа-претендента сделать [[GetOwnProperty]]. Если у результата [[Enumerable]]=true, то скопировать ключ. Что такое «скопировать». Для этого используется [[Get]]
    get-p-receiver
    Так как выше в претенденты добавлены только собственные ключи, то прототайпы курят в сторонке. Если значения ключа имеет value или дескриптор writable, то возвращается оно. Иначе это — геттер, и возвращается то, что вернёт геттер.

    Судя по спеке, prototype вообще не при делах.
  • 7 трюков с Rest и Spread операторами при работе c JS объектами
    +2
    const noPassword = ({ password, ...rest }) => rest;
    
    let user1 = {
      name: "John",
      surname: "WTF!!!",
      get fullName() { return `${this.name} ${this.surname}`; },
      set setFullName(value) { [this.name, this.surname] = value.split(" "); },
      password: "password",
    };
    // Запрещаем менять поле name
    Object.defineProperty(user1, "name", {writable: false});
    // «Удаляем» password
    let user2 = noPassword(user1);
    
    user1.name = 'WTF!!!';
    user2.name = 'WTF!!!';
    console.log(user1.name, 'vs', user2.name);
    // John vs WTF!!!
    // Ха-ха, десткриптор writable: false продолбан
    
    user1.surname = 'Smith';
    user2.surname = 'Smith';
    
    console.log(user1.fullName, 'vs', user2.fullName);
    // John Smith vs John WTF!!!
    // Ха-ха, getter превратился в атрибут
    
    user1.setFullName = 'John Blah';
    user2.setFullName = 'John Blah';
    console.log(JSON.stringify(user1), '\nvs\n', JSON.stringify(user2));
    // {"name":"John","surname":"Blah","fullName":"John Blah","password":"password"} 
    // vs
    // {"name":"WTF!!!","surname":"Smith","fullName":"John WTF!!!","setFullName":"John Blah"}
    // Ха-ха, сеттер вообще продолбан :)
    
    delete user1.password
    console.log(JSON.stringify(user1))
    // {"name":"John","surname":"Blah","fullName":"John Blah"}
    // Если нужно было именно удалить свойство, а не создать новый объект
    
    
    


    Это отличный инструмент для своих целей, и если цели не совпадают — то не нужно хаять не подходящий инструмент.

    Да-да, вы абсолютно правы. Если цель — создать новый объект, в который скопированы все enumerable-ключи, кроме password, но не скопированы дескрипторы, то да.
    Но нужно быть осторожным в реактивных фреймворках, где всё на геттерах-сеттерах.
  • 7 трюков с Rest и Spread операторами при работе c JS объектами
    +2
    В примере ниже деструктуризуем объект rest и убираем из него свойство password.
     const noPassword = ({ password, ...rest }) => rest 


    Хе-хе. Не «убираем», а создаём рядом новый объект, в который копируем все enumerable-ключи, кроме password. И не копируем при этом дескрипторы и всё скрытое.
    А потом удивляемся, почему всё тормозит, и vue/react/etc неправильно работает…
  • Alpine собирает Docker билды под Python в 50 раз медленней, а образы в 2 раза тяжелей
    0
    Если использовать двухшаговую сборку, то и продакш-контейнеры будут не такими тяжёлыми, и сборка с кешем будет практически мгновенной.
    Но это если у вас не слишком много разной тяжести в духе pandas'а и т.п.

    Я использую вот такое для вебсервиса на sanic, в котором используются допом aiohttp, asyncpg, honeybadger, Jinja2, Pillow. Если pillow не нужен, то, например, jpeg-dev будет не нужен, контейнер будет меньше.

    FROM python:3.7.5-alpine3.10 as base
    
    FROM base as builder
    RUN mkdir /install
    WORKDIR /install
    RUN apk add --no-cache python3-dev \
                           build-base \
                           libc6-compat \
                           libffi-dev \
                           zlib-dev \
                           jpeg-dev \
                           linux-headers
    RUN pip3 install --upgrade pip
    COPY requirements.txt ./
    RUN pip3 install --prefix=/install -r requirements.txt
    
    FROM base
    RUN apk add --no-cache bash jpeg-dev && \
        rm -r /tmp
    EXPOSE 80
    WORKDIR my_awesome_app
    COPY --from=builder /install /usr/local
    COPY my_awesome_app ./
    RUN pip3 freeze
    CMD ["python3", "app.py"]
    

    Продакшн-контейнер получается 160MB.

    Собрать мой стек на ubuntu/debian за быстро не получилось, поэтому, увы, без сравнения.
  • Планы команды IntelliJ Platform на 2020 год
    0
    image
    Неправильно написал. UI не блокирует. Не даёт ничего открыть (даже если знаешь точный путь) или сменить текущую папку на другую, пока не подождёшь минутку-другую. Окно можно закрыть и открыть заново, но снова придётся ждать.
  • Планы команды IntelliJ Platform на 2020 год
    +1
    например, мы создали и задействовали стандартный механизм асинхронной обработки событий от файловой системы


    А вот скажите, это у одного меня такая проблема, или это общее:
    иногда я хочу открыть какой-нибудь проект или файл. Для этого открывается кастомное IntelliJ-окно со структурой папок-файлов. Но оно открывается несколько минут. И даже если я в точности знаю путь к файлу, или тупо передумал, оно блокирует UI и пару минут что-то сканирует. Да, у меня там папка с проектами и там фигова туча подпапок и файлов. Но не надо туда внутрь лезть до того, как явно попросят.
    Могу гифку сделать.
  • Разбираем WTF задачки в JavaScript
    +1
  • Байки из склепа (из 40 лет работы программиста)
    0
    Уж не знаю, что они делают в фортране, но в питоне они обе валидные и тоже означают принципиально разные вещи.
  • Байки из склепа (из 40 лет работы программиста)
    0
    Ну, RPG версии 7.2, на которую у вас ссылка, не чета тому RPG, который был в 1990-х.
    Кода на RPG как раз примерно 1990-х годов я прочитал довольно много, и даже более древнего. ИМХО, не самый плохой язык для своего времени. Для меня он был понятнее ассемблера.
    А RPG текущий — так вообще хорош для своих задач (специфичен правда. И стандартная библиотека совсем убога). Я на нём чего только не написал за 8 лет работы.
  • Как выживают китайские магнаты майнинга биткоинов
    0
    Дело в том, что тепло можно превращать в электроэнергию только в том случае, если есть «холодильник». Температура земли — +4, это 277 градусов кельвина.
    Если вдруг удастся найти природный источник температуры, скажем −16 градусов, то есть 257 по кельвину, то КПД в лучше случае будет (277-257)/277 порядка 7% (см. цикл Карно). В реальности на таких температурах удастся добиться КПД в лучше случае 1-2%. И это нужен «бесконечный» источник вещества с температурой −16 градусов. По факту ничего такого не получается с пользой.
    А вот перекачать тепло из одного места в другое, затратив энергию, термодинамика не запрещает. Поэтому мы тратим X работы и 4Х тепла перекачиваем из тёплой земли в дом. И да, все эти Х работы в итоге тоже выделятся в виде тепла. Поэтому получаются 500%.
  • «Шакал»: сжимаем фронтенд
    +1
    Если сборка проекта через webpack, то можно просто добавить в конфиг это:
    const CompressionPlugin = require('compression-webpack-plugin');
    ...
      new CompressionPlugin({
        filename: '[path].br[query]',
        algorithm: 'brotliCompress',
        test: /\.(html|css|ttf|eot|svg|js)$/,
        compressionOptions: { level: 11 },
        threshold: 1024,
        minRatio: 0.8,
      }),
      new CompressionPlugin({
        filename: '[path].gz[query]',
        test: /\.(html|css|ttf|eot|svg|js)$/,
        threshold: 1024,
        minRatio: 0.8,
      }),
    ...
    

    (Ну и да, кастомно собранный nginx с поддержкой brotli тоже нужен)
  • Как выживают китайские магнаты майнинга биткоинов
    0
    Никого вечного двигателя, увы. Дополнительные 400% тепла берутся из «тёплой» земли. И работу из них не сошьёшь.
  • Как выживают китайские магнаты майнинга биткоинов
    0
    Это неправда. У тепловых насосов КПД не 100%, а до 500%.
  • SAX-парсер python vs DOM-парсер python. Парсим ФИАС-houses
    +1
    Простыню append'ов можно сделать так:
    attr_names = [
        'HOUSEID', 'HOUSEGUID', 'AOGUID', 'HOUSENUM', 'STRUCNUM', 
        'STRSTATUS', 'ESTSTATUS', 'STATSTATUS', 'IFNSFL', 'IFNSUL', 
        'TERRIFNSFL', 'TERRIFNSUL', 'OKATO', 'OKTMO', 'POSTALCODE', 
        'STARTDATE', 'ENDDATE', 'UPDATEDATE', 'COUNTER', 'NORMDOC', 
        'DIVTYPE', 'REGIONCODE'
    ]
    for attr_name in attr_names:
        object.append(member.attrib.get(attr_name, None))            
    
  • Питон, пожирающий мир: как побочный проект одного разработчика стал популярнейшим языком программирования
    +2
    Но на логотипе языка таки два питончика.
  • Алкоголизм последней стадии
    0
    david1978, как вы там? Черкните хотя бы один комментарий, мы волнуемся!
  • Не работайте в плохих проектах
    0
    Я работал в немного похожей ситуации: банковская АБС из 1980-1990-х, куча inhouse-доработок сомнительного качества и язык RPGLE на AS400. Только ЗП, увы, была не за 99% квантиль… :(
    Много лет кайфовал: изучил всё вдоль и поперёк. Прикрутил кучу фич, про которые вообще не думали, что на той системе так можно «задёшево». Ну, то есть схема была такая: остаётся свободное время, пилишь прототипчик какой-нибудь фичи. И пачка готовых экспериментов всё время лежит. Потом появляется задача, в которой одну из фич можно добавить. И ты уже точно знаешь, что прикрутишь её, скажем, за 2-3 дня. И это заказчика устраивает.
  • Telegram наносит ответный удар DPI и блокировкам — Fake TLS
    +1
    А я у себя настроил SSLH (см. habr.com/post/412779). И в итоге у меня открыты два порта: 80 (редиректит на 443) и 443. А уже через 443 идёт и телеграм, и openvpn, и ssh. И да, на «обычные» запросы отвечает nginx, раздаёт зеркало одного из моих проектов.
  • ГИБДД, ЦОДД Москвы и РСА начали проверять наличие полиса ОСАГО с помощью дорожных камер
    0
    Казалось бы, это не так важно. Каждый день делаем реестр всех номеров. Через месяц выгружаем реестр в РСА. Они отвечают списком номеров, у которых на дату «месяц назад» не было ни одного оформленного полиса.
  • МТС и «Билайн», возможно, отключали мобильный интернет в центре Москвы 3 августа
    0
    Ну, на ближайшие пару недель может и имеет смысл. Но с 1 ноября 2019 — уже всё. Там изоляция рунета. Уверен, как раз в таких ситуациях и будут применять.
  • Как я побывал в легендарной Школе 42: «бассейн», котики и интернет вместо учителей. Часть 2
    +1
    С прошлого года есть филиал и в Москве: 21-school.ru (работают по лицензии школы 42).
    Дополню, что там только офф-лайн, только на компьютерах школы, зато 24 × 7.
    В московском офисе — это порядка 700 штук 27" iMac'ов.
    С моей точки зрения (я был у них «в гостях» и разговаривал с отдельными студентами, они кое-что показывали) штука очень крутая. Особенно по сравнению многими ВУЗами. Хотя и не все аспекты кажутся мне правильными.
  • Отсеиваем простые из миллиарда чисел быстрее, чем в Википедии
    +1
    Раз уж про меня вспомнили, то вот сравнение нескольких реализаций. На списках несколько геморройнее, зато в 3 раза быстрее.

    Код на python
    from timeit import timeit
    
    
    def eratosthenes1(N):
        simp, nonsimp = [2], set()
        for i in range(3, N + 1, 2):
            if i not in nonsimp:
                nonsimp |= {j for j in range(3 * i, N + 1, 2 * i)}
                simp.append(i)
        return simp
    
    
    def eratosthenes2(N):
        simp, nonsimp = [2, 3], {i for i in range(3, N + 1, 3)}
        for i in range(5, int(N ** 0.5), 2):
            if i not in nonsimp:
                nonsimp |= {j for j in range(i * i, N + 1, 2 * i)}
                simp.append(i)
        simp.extend([j for j in range(i, N + 1, 2) if j not in nonsimp])
        return simp
    
    
    def eratosthenes3(N):  # Возвращает список простых чисел от 2 до N
        if N < 2:
            return []
        A = [False, True] * ((N + 2) // 2)
        A[2] = True
        for i in range(3, int(N ** 0.5 + 1.5), 2):
            if A[i]:
                for j in range(i * i, N + 1, 2 * i):
                    A[j] = False
        return [i for i in range(2, N + 1) if A[i]]
    
    # Самая быстрая версия, N = 10**8, ~13c
    def eratosthenes4(N):  # Возвращает список простых чисел от 2 до N
        if N < 2: return []
        A = [False, True] * ((N + 2) // 2)  # Про чётные всё очевидно
        simps = [2]
        sqrtN = int(N ** 0.5 + 1.5)  # Корень плюс ещё немного
        sqrtN += 1 - sqrtN % 2  # Делаем нечётным (это пригодится позже)
        for i in range(3, sqrtN, 2):
            if A[i]:
                simps.append(i)
                for j in range(i * i, N + 1, 2 * i):
                    A[j] = False
        simps.extend(i for i in range(sqrtN, N + 1, 2) if A[i])  # Вот здесь важно, что sqrtN нечётный
        return simps
    
    
    def eratosthenes5(n):  # Решето Грайса и Мисра (David Gries, Jayadev Misra), асимптотика O(n)
        lsd = [0] * (n + 1)
        simp = []
        for i in range(2, n + 1):
            if lsd[i] == 0:
                simp.append(i)
                lsd[i] = i
            for p in simp:
                if p * i > n:
                    break
                lsd[p * i] = p
        return simp
    
    
    funcs = [obj for name, obj in globals().items() if name.startswith('erat')]
    N = 10 ** 8
    setup = 'from __main__ import funcs, N'
    for i in range(len(funcs)):
        print(timeit(stmt='funcs[{}](N)'.format(i), setup=setup, number=1))
    # 59.081
    # 41.303
    # 14.553
    # 12.582 <- eratosthenes4 в 3+ раза быстрее
    # 75.451
    



    А вот до кучи реализация на rust. У меня миллиард считает за 6с (ноутбучный core i5, 1.6GHz)
    (third112)

    Код eratosthenes4 на rust
    use std::time::Instant;
    
    fn eratosthenes4(n: usize) -> Vec<usize> {
        if n < 2 {
            return Vec::new();
        }
        let mut tst = vec![true; (n + 1) / 2];
        let mut simps = vec![2];
        let mut sqrt_n = ((n as f64).sqrt() + 1.5) as usize;
        sqrt_n += 1 - sqrt_n % 2;
        for i in (3..sqrt_n).step_by(2) {
            if tst[i>>1] {
                simps.push(i);
                for j in (i * i..(n + 1)).step_by(2 * i) {
                    tst[j>>1] = false;
                }
            }
        }
        for i in (sqrt_n..(n + 1)).step_by(2).filter(|x| tst[x>>1]) {
            simps.push(i);
        }
        return simps;
    }
    
    
    fn main() {
        let now = Instant::now();
        let n = 1_000_000_000;
        let res = eratosthenes4(n);
        let dur = Instant::now().duration_since(now);
        println!("Duration: {:?}, len: {}", dur, res.len());
        // Duration: 6.0877631s, len: 50847534
    }
    
    

  • Docker: вредные советы
    +1
    (Не трогайте комментаторов моего сообщения, плз. Я сначала не заметил тег и написал комментарий. А потом понял и добавил PS. В результате комментарии от baldr и далее выглядят неуместно)
  • Docker: вредные советы
    +8
    PS. Для тех, кто всё же хочет что-то полезное, и невнимательно читает «дурные советы».
    Минорные советы по финальному докерфайлу сжато (чтобы не читать эту всю статью):

    # Ой, не надо делать latest, ой сломается когда-нибудь что-нибудь из-за этого!
    FROM ubuntu:latest
    # Всё копировать не надо, это приводит к тому, что любое изменение в сорсах — и весь кеш в помойку.
    # Папка приложения
    WORKDIR /app

    # Обновляем список пакетов и обновляем их, устанавливаем пакеты и bundler. Одной командой
    # PS. А зачем там столько всего? Ладно, наше дело dockerfile, а не внутренности
    RUN apt-get update && \
    apt-get upgrade && \
    apt-get -y install libpq-dev imagemagick gsfonts ruby-full ssh supervisor && \
    gem install bundler

    # Устанавливаем nodejs используется для сборки статики
    # (А ещё можно было взять образ с готовой нодой или готовыми рубями)
    RUN curl -sL https://deb.nodesource.com/setup_9.x | sudo bash -
    RUN apt-get install -y nodejs

    # Копируем Gemfile'ы
    # Всё, что выше, будет отлично кешироваться
    COPY Gemfile* ./

    # Устанавливаем зависимости
    # Даже это будет кешироваться, если зависимости не поменялись
    RUN bundle install --without development test --path vendor/bundle

    # Чистим за собой кэши
    # Иногда это помогает, но лучше тупо использовать многошаговые докер-файлы. В одном шаге всё для сборки, во втором копируется только бинарники из первого образа
    RUN rm -rf /usr/local/bundle/cache/*.gem && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

    # Копируем исходный код
    COPY ./ ./

    # Запускаем скрипт, при старте контейнера, который запустит все остальное.
    CMD ["/app/init.sh"]
  • IBM System i (aka AS/400) — Как мы делали автотесты приложений зеленого экрана
    +4
    vb работает просто ну дико нестабильно. Сам client access — ещё ничего, хотя, конечно, периодически падает. А вот vb в нём для долгих задач ну совсем нестабилен. Нам (не в Альфе) приходилось какие-то вещи так автоматизировать (в духе 10000 сделок в MIDAS ввести), так там половина кода были костыли на всевозможные случаи отказов vb.