Python: почему этот кортеж печатает результат и None? Также: есть ли лучший способ добиться результата?

Мне нужно вычислить с заданным числом, сколько «пятерок», «двоек» и «единиц» может попасть в эти числа. Извините, мой английский немного ограничен для такого рода объяснений :) Может быть, пример лучше:

Упражнение: печать штампов (8). Результат должен быть: (1, 1, 1) (один штамп 5 пенсов, один штамп 2 пункта и один штамп 1 пенал).

Я нашел способ добиться этого, но tuple () печатает результат и «None», и я не знаю почему. Я также хотел бы знать, есть ли лучший и более короткий способ получить правильный результат.

Вот что я сделал:

def stamps(dinero):
    p5=dinero/5
    p5a=p5*5
    resultado1=dinero-p5a
    dinero=resultado1
    p2=dinero/2
    p2a=p2*2
    resultado2=dinero-p2a
    dinero=resultado2
    p1=dinero/1
    p1a=p1*1
    resultado3=dinero-p1a
    dinero=resultado3
    print tuple([p5,p2,p1])

Результат, который я получаю: print stamps (8) - (1, 1, 1) None

Обновление: Я нашел лучшее решение, я размещаю его здесь на всякий случай, если кто-то поинтересуется лучшим решением:

def stamps(n):
    #Basically, thats the same as return n/5, n%5/2, n%5%2
    return n/5, (n-5*(n/5))/2, (n-5*(n/5))-2*((n-5*(n/5))/2)

person Rosamunda    schedule 22.07.2013    source источник
comment
Причина в том, что функция ничего не возвращает. Вы уверены, что не делаете print print_stamps(8)? Обычно цикл командной строки не печатает None   -  person David Robinson    schedule 22.07.2013
comment
СПАСИБО ЗА ВАШ ОТВЕТ! Я исправил опечатку: я набираю print stamps(8), и да, там написано "печать", а затем - процедура. Для упражнения требуются печатные штампы (8), как я могу избежать «Нет» внутри процедуры? Кроме того, вы упомянули цикл, но там нет цикла, о котором я знаю (if, for, while ...) :) Еще раз спасибо!   -  person Rosamunda    schedule 22.07.2013
comment
Я имел в виду цикл чтение-оценка-печать: то есть интерактивный интерпретатор Python   -  person David Robinson    schedule 22.07.2013


Ответы (2)


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

def stamps(dinero):
    p5=dinero/5
    dinero=dinero%5
    p2=dinero/2
    dinero=dinero%2
    p1=dinero/1
    return tuple([p5,p2,p1])

print stamps(8)
>>> (1,1,1)

В вашем коде эта строка:

p5=dinero/5

Выполняет целочисленное деление, а результат ниже получает остаток, умножая количество кратных делителя в исходном числе и вычитая его:

p5a=p5*5
resultado1=dinero-p5a
dinero=resultado1

Большинство языков предлагают функцию по модулю, которая выполняет это в Единственный шаг:

dinero=dinero%5

То же самое для части, где вы делите на 3, и когда вы делите на 1, целочисленный остаток никогда не остается, поэтому вы можете полностью удалить этот код.

У Python также есть способ, которым вы можете снова сократить это, используя divmod(), который возвращает как делитель, так и модуль:

def stamps(dinero):
    p5,dinero=divmod(dinero,5)
    p2,dinero=divmod(dinero,2)
    p1=dinero
    return tuple([p5,p2,p1])

print stamps(8)
>>> (1,1,1)

И, наконец, вы можете полностью обобщить его, попросив другую функцию принять как сумму, так и массив значений штампа и вызвать это:

def stamps(dinero):
    return allStamps(dinero,[5,2,1])

def allStamps(dinero=1,stamps=[]):
    vals = []
    for stamp in sorted(list(set(stamps)), reverse=True):
        val,dinero=divmod(dinero,stamp)
        vals.append(val)
    return tuple(vals)

print stamps(8)
>>> (1,1,1)
print allStamps(8,[5,3,1])
>>> (1,1,0)

Что касается скорости выполнения кода:

Я запустил timeit для некоторых параметров, а также для вызовов / и % оказался быстрее, чем даже один звонок divmod():

> python -m timeit 'a=1000;b=a/5;c=b*5;d=a-c;a=d'
 10000000 loops, best of 3: 0.156 usec per loop
> python -m timeit 'a=1000;b=a/5;a=a-b*5;'
 10000000 loops, best of 3: 0.127 usec per loop
> python -m timeit 'a=1000;a=a-(a/5)*5;'
 10000000 loops, best of 3: 0.121 usec per loop
> python -m timeit 'a=1000/13;b=1000%13;'
 10000000 loops, best of 3: 0.0755 usec per loop
root@meteordev:~# python -m timeit 'a,b=divmod(1000,13);'
 10000000 loops, best of 3: 0.183 usec per loop
person Community    schedule 22.07.2013
comment
Вызов целочисленного деления и модуля каждый раз будет дороже, чем вызов целочисленного деления, а затем умножения и вычитания, как в исходном коде. Однако divmod (), вероятно, достаточно умен, чтобы избежать этой ловушки, потому что он вычисляет как деление, так и остаток одновременно. +1 за это. - person user2566092; 22.07.2013
comment
@ user2566092 Я добавил правку, которая решает эту проблему, и оказалось, что div-then-mod в два раза быстрее исходного кода. Но, что удивительно, divmod медленнее, чем оба! - person ; 22.07.2013

Измените «print» на «return» внутри вашей функции, и это должно исправить это, когда вы вызываете «print stamps (8)». Кроме того, нет, для вашего простого выбора значений штампа 5,2,1 нет более эффективного способа найти хорошее решение, кроме того, что вы делаете (единственное возможное улучшение, возможно, будет использовать цикл for, если у вас есть больше значений штампа, чем просто 3) - если бы ваши значения штампа были более сложными, вы могли бы найти лучшие решения, которые используют меньше штампов, используя динамическое программирование.

person user2566092    schedule 22.07.2013
comment
Спасибо! Именно так! :) - person Rosamunda; 22.07.2013