Неожиданный вывод для literal_eval в Python3 [duplicate]

Это расширение для двух ответов, уже представленных выше, поскольку производительность во время исполнения показалась темой комментариев. Я добавил бы его в качестве комментариев, но у меня еще нет этой привилегии.

Я тестировал 2 реализации для производительности во время исполнения с использованием Visual Studio 2015:

Использование stringstream:

std::stringstream result;
auto it = vec.begin();
result << (unsigned short)*it++;
for (; it != vec.end(); it++) {
    result << delimiter;
    result << (unsigned short)*it;
}
return result.str();

Использование accumulate:

std::string result = std::accumulate(std::next(vec.begin()), vec.end(),
    std::to_string(vec[0]),
    [&delimiter](std::string& a, uint8_t b) {
    return a + delimiter+ std::to_string(b);
});
return result;

Производительность выполнения сборки сборки была близка к парам тонкостей.

Реализация накопления была немного быстрее (20-50 мс, ~ 10-30% от общей продолжительности (~ 180 мс) на 1000 итераций по 256-элементному вектору). Однако реализация accumulate была только быстрее, когда параметр a для функции лямбда был передан по ссылке. Передача параметра a по значению привела к аналогичной разнице во времени во время реализации stringstream. Реализация accumulate также улучшилась, когда возвратная строка была возвращена напрямую, а не назначена локальной переменной, которая была немедленно возвращена. YMMV с другими компиляторами C ++.

Сборка Debug была в 5-10 раз медленнее с использованием accumulate, поэтому я думаю, что добавление дополнительной строки, отмеченное в нескольких комментариях выше, разрешено оптимизатором.

Я искал конкретную реализацию, используя vector значений uint8_t. Полный тестовый код:

#include <vector>
#include <iostream>
#include <sstream>
#include <numeric>
#include <chrono>

using namespace std;
typedef vector<uint8_t> uint8_vec_t;

string concat_stream(const uint8_vec_t& vec, string& delim = string(" "));
string concat_accumulate(const uint8_vec_t& vec, string& delim = string(" "));

string concat_stream(const uint8_vec_t& vec, string& delimiter)
{
    stringstream result;

    auto it = vec.begin();
    result << (unsigned short)*it++;
    for (; it != vec.end(); it++) {
        result << delimiter;
        result << (unsigned short)*it;
    }
    return result.str();
}

string concat_accumulate(const uint8_vec_t& vec, string& delimiter)
{
    return accumulate(next(vec.begin()), vec.end(),
        to_string(vec[0]),
        [&delimiter](string& a, uint8_t b) {
        return a + delimiter + to_string(b);
    });
}

int main()
{
    const int elements(256);
    const int iterations(1000);

    uint8_vec_t test(elements);
    iota(test.begin(), test.end(), 0);

    int i;
    auto stream_start = chrono::steady_clock::now();
    string join_with_stream;
    for (i = 0; i < iterations; ++i) {
        join_with_stream = concat_stream(test);
    }
    auto stream_end = chrono::steady_clock::now();

    auto acc_start = chrono::steady_clock::now();
    string join_with_acc;
    for (i = 0; i < iterations; ++i) {
        join_with_acc = concat_accumulate(test);
    }
    auto acc_end = chrono::steady_clock::now();

    cout << "Stream Results:" << endl;
    cout << "    elements: " << elements << endl;
    cout << "    iterations: " << iterations << endl;
    cout << "    runtime: " << chrono::duration<double, milli>(stream_end - stream_start).count() << " ms" << endl;
    cout << "    result: " << join_with_stream << endl;

    cout << "Accumulate Results:" << endl;
    cout << "    elements: " << elements << endl;
    cout << "    iterations: " << iterations << endl;
    cout << "    runtime: " << chrono::duration<double, milli>(acc_end - acc_start).count() << " ms" << endl;
    cout << "    result:" << join_with_acc << endl;

    return 0;
}
17
задан ThoAppelsin 1 July 2016 в 23:58
поделиться

4 ответа

Обновите несколько лет спустя: Python 3.6 теперь поддерживает PEP515 , и поэтому вы можете использовать _ для улучшения удобочитаемости с плавающей и целочисленной литералами.

Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 1_1000
11000
>>>

Для справки по истории, вы можете посмотреть на лексический анализ для строгих определений python2.7 , python3.5 ...

Для python3.6.0a2 и ранее вы должен получить сообщение об ошибке, подобное:

Python 3.6.0a2 (v3.6.0a2:378893423552, Jun 13 2016, 14:44:21) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 1_000
  File "<stdin>", line 1
    1_000
        ^
SyntaxError: invalid syntax
>>> amount = 10_000_000.0
  File "<stdin>", line 1
    amount = 10_000_000.0
                      ^
SyntaxError: invalid syntax
18
ответ дан Foon 16 August 2018 в 01:58
поделиться

В Python такой функции нет, но было предложено интегрировать ее в будущем.

Вы можете увидеть предложение в PEP515 .

3
ответ дан Hamlett 16 August 2018 в 01:58
поделиться

В настоящее время в Python нет разделителя тысяч, но вы можете использовать модуль locale для преобразования строки с такими разделителями в int:

import locale
locale.setlocale(locale.LC_ALL, '')
locale.atoi("1,000,000")
4
ответ дан scope 16 August 2018 в 01:58
поделиться

Самое близкое, что я видел в python, это 12 * 1000 * 1000, что не идеально, но может быть полезно, если требуется 12000000. Однако, хотя в C они эквивалентны, поскольку во время компиляции он преобразует оба значения в одно и то же, python может не разделять эту оптимизацию.

2
ответ дан TemporalWolf 16 August 2018 в 01:58
поделиться
  • 1
    Если они являются литералами, питон сбрасывает константы. Тем не менее, он не будет делать никаких складных символов. – mgilson 2 July 2016 в 00:08
  • 2
    За 12 миллионов я буду использовать и рекомендовать 12e6. – ThoAppelsin 2 July 2016 в 00:16
  • 3
    @ThoAppelsin - Ну, это зависит от того, хотите ли вы, чтобы ваше значение было float или int ... – mgilson 2 July 2016 в 00:17
  • 4
    @TemporalWolf - вы всегда можете проверить это, разобрав источник: dis.dis(lambda : 100 * 200 * 300) – mgilson 2 July 2016 в 00:18
  • 5
    @mgilson: Как это бывает, это одна из тех вещей, где порядок имеет значение. Если вы используете x * 100 * 1000 * 1000, то он не будет сбрасываться (потому что x * 100 может не возвращать int, если x не является int). Но 100 * 1000 * 1000 * x складывается, потому что оценка слева направо работает с известными константами. – ShadowRanger 2 July 2016 в 00:34
Другие вопросы по тегам:

Похожие вопросы: