Какие общие советы у вас есть для игры в гольф на Python? Я ищу идеи, которые могут быть применены к задачам кода-гольфа и которые, по крайней мере, несколько специфичны для Python (например, «удалить комментарии» - это не ответ).
Пожалуйста, оставьте один совет за ответ.
Ответы:
Используйте
a=b=c=0
вместоa,b,c=0,0,0
.Используйте
a,b,c='123'
вместоa,b,c='1','2','3'
.источник
Условия могут быть длинными. В некоторых случаях вы можете заменить простой условный на
(a,b)[condition]
. Еслиcondition
это правда, тоb
возвращается.сравнить
К этому
источник
a if a<b else b
иa<b and a or b
(lambda(): b, lambda(): a)[a < b]()
сделай свое собственное короткое замыкание с лямбдамиP and A or B
для любого, который даетbool(A)=False
. Но(P and [A] or [B])[0]
сделаю работу. См. Diveintopython.net/power_of_introspection/and_or.html для справки.Замечательная вещь, которую я сделал однажды:
вместо:
Операторы сравнения Python качаются.
Используя то, что в Python 2 все сравнимо, вы также можете избежать
and
оператора таким образом. Например, еслиa
,b
,c
иd
являются целыми числами,можно сократить на один символ до:
При этом каждый список больше любого целого.
Если
c
иd
есть списки, это становится еще лучше:источник
3>a>1<b<5
[$a => $b]->[$b <= $a]
:)if(a<b)+(c>d):foo()
*
. Анor
будет+
foo()if 3>a>1<b<5
Если вы неоднократно используете встроенную функцию, может быть более эффективно использовать новое имя, если используются разные аргументы:
источник
Иногда ваш код Python требует, чтобы у вас было 2 уровня отступа. Очевидная вещь, которую нужно сделать - использовать один и два пробела для каждого уровня отступа.
Однако Python 2 считает символы табуляции и пробела разными уровнями отступа.
Это означает, что первый уровень отступа может быть одним пробелом, а второй - одним символом табуляции.
Например:
Где
\t
находится символ табуляции.источник
TabError: inconsistent use of tabs and spaces in indentation.
Используйте подстановку строк и
exec
для работы с такими длинными ключевыми словамиlambda
, которые часто повторяются в вашем коде.Целевая строка очень часто
'lambda '
, длиной 7 байт. Предположим, что ваш фрагмент кода содержитn
вхождения'lambda '
и имеетs
длину в байты. Затем:plain
Опцияs
байт длиной.replace
Опцияs - 6n + 29
байт длиной.%
Опцияs - 5n + 22 + len(str(n))
байт длиной.Из графика байтов, сохраненного
plain
для этих трех вариантов, мы можем видеть, что:exec"..."%(('lambda ',)*5)
сохраняет 2 байта и является вашим лучшим вариантом.exec"...".replace('`','lambda ')
- ваш лучший вариант.Для других случаев вы можете проиндексировать таблицу ниже:
Например, если строка
lambda x,y:
(длина 11) встречается в вашем коде 3 раза, лучше писатьexec"..."%(('lambda x,y:',)*3)
.источник
replace
огромна.=>
это просто строка= lambda
. Например,f=>:0
будетf = lambda: 0
.Используйте расширенную нарезку, чтобы выбрать одну строку из многих
против
В этом булевом двухстрочном случае можно также написать
за
В отличие от чередования, это работает для строк любой длины, но может иметь проблемы с приоритетом операторов, если
b
вместо этого используется выражение.источник
for x in ("foo","bar","baz"): print x
x
отображаются различные значения . Golfed часть является"fbboaaorz"[x::3]
против["foo","bar","baz"][x]
Какx
стоимость определяется будет другая часть вашего решения для гольфа.Используйте
`n`
для преобразования целого числа в строку вместо использованияstr(n)
:источник
Хранить таблицы поиска как магические числа
Скажем, вы хотите жестко закодировать булеву таблицу поиска, например, какое из первых двенадцати английских чисел содержит
n
.Затем вы можете кратко реализовать эту таблицу поиска как:
с полученным
0
или1
быть равным ,False
чтобыTrue
.Идея состоит в том, что магическое число хранит таблицу как цепочку битов
bin(3714)
=0b111010000010
, сn
десятой цифрой (от конца), соответствующейn
записи таблицы. Мыn
получаем доступ к th-записи, сдвигая битовыеn
пробелы справа и беря последнюю цифру&1
.Этот способ хранения очень эффективен. Сравните с альтернативами
Вы можете иметь свою таблицу поиска хранить многобитные записи, которые могут быть извлечены как
извлечь соответствующий четырехбитный блок.
источник
Свернуть два числовых цикла в один
Скажем, вы перебираете ячейки
m*n
сетки. Вместо двух вложенныхfor
циклов, одного для строки и одного из столбцов, обычно короче использовать один цикл для итерации поm*n
ячейкам сетки. Вы можете извлечь строку и столбец ячейки внутри цикла.Оригинальный код:
Гольф-код:
По сути, вы перебираете декартово произведение двух диапазонов, кодируя пару
(i,j)
какx=i*n+j
. Вы сохранили дорогойrange
вызов и уровень отступа внутри цикла. Порядок итерации неизменен.Используйте
//
вместо/
в Python 3. Если вы ссылаетесьi
иj
много раз, это может быть быстрее , чтобы назначить их значениеi=k/n
,j=k%n
внутри цикла.источник
for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
n
циклов: repl.it/EHwaitertools.product
может быть гораздо более кратким, чем вложенные циклы, особенно при создании декартовых произведений.a1, a2, b1, b2
примеры декартовых произведений'ab'
и'12'
Если следующий токен не начинается с
e
илиE
. Вы можете удалить пробел после числа.Например:
становится:
Использование этого в сложных однострочных операторах может сохранить довольно много символов.
РЕДАКТИРОВАТЬ: как указал @marcog,
4or a
будет работать, но не так,a or4
как это путают с именем переменной.источник
if(i,j)==(4,4):
еще короче и в этом особом случаеif i==j==4:
4or a
работает, но неa or4
0or
также не работает (0o
это префикс для восьмеричных чисел).0 or x
все равно имело значение, потому что всегда вернетсяx
. Сможешь вырезать0 or
.0or
хорошо как часть более длинного числа все же.10 or x
эквивалентно10or x
.Для целого числа
n
вы можете написатьn+1
как-~n
n-1
как~-n
потому что бит флип
~x
равен-1-x
. При этом используется то же количество символов, но можно косвенно сократить пробелы или скобки для приоритета оператора.Для сравнения:
Операторы
~
и Унарный-
выше приоритет , чем*
,/
,%
, в отличие от двоичного файла+
.источник
-~-x
сохраняет один байт против(1-x)
.a+b+1
может быть более кратко написано какa-~b
.n-i-1
это простоn+~i
.Хороший способ конвертировать итерируемое в список на Python 3 :
представьте, что у вас есть итеративный, как
Но вам нужен список:
Это очень полезно сделать список символов из строки
источник
*s,='abcde'
а затемs
вылетает мой интерактивный python3 с segfault :([*'abcde']
.Вместо этого
range(x)
вы можете использовать*
оператор в списке чего угодно, если вам на самом деле не нужно использовать значениеi
:в отличие от
Если вам нужно сделать это более двух раз, вы можете назначить любую итерацию переменной и умножить эту переменную на нужный вам диапазон:
Примечание : это часто длиннее
exec"pass;"*8
, поэтому этот трюк следует использовать только тогда, когда это невозможно.источник
[1]*8
корочеrange(8)
, вы также можете сэкономить место, потому чтоfor i in[...
законно, аfor i in range...
нет».exec"pass;"*8
значительно короче.r=1
,r*8
это 8, и вы не можете перебрать номер. Я думаю, вы имели в видуr=[1]
Вы можете использовать старый добрый инопланетный смайлик, чтобы изменить последовательность:
источник
Расширенная повторяемая распаковка («Помеченное назначение», только Python 3)
Лучший способ объяснить это на примере:
Мы уже видели использование для этого - превращение итерируемого в список в Python 3 :
Вот еще несколько вариантов использования.
Получение последнего элемента из списка
В некоторых ситуациях это также может быть использовано для получения первого элемента, который будет экономить на паренах:
Назначение пустого списка и других переменных
Удаление первого или последнего элемента из непустого списка
Это короче, чем альтернативы
L=L[1:]
иL.pop()
. Результат также может быть сохранен в другом списке.Советы любезно предоставлены @grc
источник
a=1;L=[]
так много раз. Удивительно, что вы можете сэкономить символы на чем-то таком простом, как это.a,*L=1,
), но все равно сохраняет один символ :)a,*_,b=L
установить литералы в Python2.7
Вы можете написать наборы, подобные этому.
S={1,2,3}
Это также означает, что вы можете проверить членство, используя{e}&S
вместоe in S
которого один символ.источник
if
s, так как нет пробелов (if{e}&S:
)not in
на{e}-S
этот трюкВеками меня беспокоило, что я не мог придумать краткий способ получить весь алфавит. Если вы используете
range
достаточно того, чтоR=range
стоит иметь в вашей программе, токороче наивного
, но в противном случае он длиннее на один символ. Меня преследовало, что умный, требующий некоторых знаний о значениях ascii, оказался более многословным, чем просто ввод всех букв.
Пока я не увидел этот ответ для алфавита моей дочери . Я не могу достаточно хорошо следить за историей редактирования, чтобы понять, был ли этот гений работой ОП или предложением комментатора, но это (я полагаю) самый короткий способ создания итерируемого из 26 букв в латинском алфавите.
Если регистр не имеет значения, вы можете удалить другой символ, используя прописные буквы:
Я
map
слишком много использую, я не знаю, как это никогда не происходило со мной.источник
string.lowercase
- вот для чего оно.ord('z')
)? Помимо одинаковой длины ... Кроме того, если вам нужны буквенно-цифровыеstr.isalpha
символы , замените в версии @ quintopia наstr.isalnum
. (Но если вам нужен только один регистр, вся строка из 36 символов не длиннееfilter(str.isalnum,map(chr,range(90)))
.)R
, моя версия короче, чем ваша оригинальная:'%c'*26%tuple(R(97,123))
(всего 24 знака), если вы пишете,range
она равна длине алфавита - заглавная версия корочеХотя в python нет операторов switch, вы можете эмулировать их с помощью словарей. Например, если вам нужен такой переключатель:
Вы можете использовать
if
заявления, или вы могли бы использовать это:или это:
что лучше, если все пути кода являются функциями с одинаковыми параметрами.
Для поддержки значения по умолчанию сделайте это:
(или это:)
Еще одним преимуществом этого является то, что если у вас есть избыточности, вы можете просто добавить их после конца словаря:
И если вы просто хотите использовать переключатель для возврата значения:
Вы можете просто сделать это:
источник
dict(s1=v1,s2=v2,...,sn=vn)
вместо{'s1':v1,'s2':v2,...,'sn':vn}
2 * n-4 байт используется экономия, и лучше, если n> = 3Если у вас есть два логических значения,
a
иb
, если вы хотите , чтобы выяснить, какa
иb
истинны, использовать*
вместоand
:против
если любое из значений равно false, оно будет оцениваться так же, как
0
в этом операторе, а целочисленное значение имеет значение true, только если оно отлично от нуля.источник
&
:a=b=False
,a&b
+
дляor
если вы можете гарантироватьa != -b
|
работает во всех ситуациях.*
вместоand
/&&
сохраняет несколько байтов во многих языках.Эксплойт Python 2 строковые представления
Python 2 позволяет конвертировать объект
x
в его строковое представление`x`
по цене всего 2 символа. Используйте это для задач, которые легче выполнить на строке объекта, чем сам объект.Присоединяйтесь к персонажам
Учитывая список символов
l=['a','b','c']
, можно создать''.join(l)
как`l`[2::5]
, что сохраняет байт.Причина в том, что
`l`
это"['a', 'b', 'c']"
(с пробелами), поэтому можно извлечь буквы срезом списка, начиная с второго символа с нулевым индексомa
и беря оттуда каждый пятый символ. Это не работает для объединения многосимвольных строк или escape-символов, представленных как'\n'
.Объединить цифры
Точно так же, учитывая непустой список таких цифр, как
l=[0,3,5]
, можно объединить их в строку'035'
как`l`[1::3]
.Это экономит, делая что-то вроде
map(str,l)
. Обратите внимание, что они должны быть однозначными и не могут содержать плавающие числа, например,1.0
смешанные. Кроме того, в пустом списке это не сработает]
.Проверьте на негативы
Теперь о нестроковой задаче. Предположим, у вас есть список
l
действительных чисел, и вы хотите проверить, содержит ли он какие-либо отрицательные числа, производя логическое значение.Ты можешь сделать
который проверяет наличие отрицательного знака в строке rep. Это короче, чем любой из
Во-вторых,
min(l)<0
произойдет сбой в пустом списке, поэтому вам придется хеджировать.источник
str(l)[2::5]
12 байтов против 19 для''.join(map(str,l))
. Фактическая ситуация, когда это произошло (гдеl
был оператор-генератор, а не список), спасла мне всего один байт ... который все еще стоит!Функция с одной строкой может быть выполнена с помощью лямбды:
может быть преобразовано в (обратите внимание на пропущенное место
3and
и10or
)источник
c=lambda a:a+[-5,10][a<3]
. и и / или трюк более полезен, когда выelse:
может быть отброшено, так какreturn
останавливает выполнение функции, поэтому все, что следует, выполняется только в случае сбояif
условия, иначе говоря, еслиelse
условие истинно. Таким образомelse
можно смело опускать. (Объясняется подробно для неофитов там)c=lambda a:a-5+15*(a<3)
Циклы до 4-х предметов может быть лучше, чтобы снабдить кортеж вместо использования диапазона
против
источник
Потолок и пол
Если вы когда-нибудь захотите получить округленный результат для деления, так же, как и
//
для пола, вы можете использоватьmath.ceil(3/2)
для 15 или намного меньше-(-3//2)
для 8 байт.источник
n//1+1
ceil, но это означает, что ceil (n) = n + 1, но это должно работать для всех нецелых значенийround(x)
is(x+.5)//1
, +1 байт, но последний начинается с a(
, и еслиx
это сумма, состоящая из константы, это может быть полезно.Используйте
+=
вместоappend
иextend
можно сократить до:
B,
здесь создает одноэлементный кортеж, который можно использовать для расширения,A
как[B]
вA+=[B]
.можно сократить до:
источник
return 0
илиreturn 1
эквивалентноreturn False
илиreturn True
.-x
а неx*-1
.--8.32
а не-8.32*-1
. Или просто8.32
...A+=B
B
этоtuple
.Выбор одного из двух чисел на основе условия
Вы уже знаете, использовать выбор списка
[x,y][b]
с логическим значениемb
для троичного выраженияy if b else x
. Переменныеx
,y
иb
также могут быть выражениями, хотя следует учитывать, что обаx
иy
оцениваются, даже если они не выбраны.Вот некоторые потенциальные оптимизации, когда
x
иy
являются числами.[0,y][b] -> y*b
[1,y][b] -> y**b
[x,1][b] -> b or x
[x,x+1][b] -> x+b
[x,x-1][b] -> x-b
[1,-1][b] -> 1|-b
[x,~x][b] -> x^-b
[x,y][b] -> x+z*b
(илиy-z*b
), где z = yx.Вы также можете переключиться,
x
иy
если вы можете переписатьb
его вместо этого.источник
Используйте ~, чтобы индексировать в конце списка
Если
L
это список, используйте,L[~i]
чтобы получитьi
'-ый элемент сзади.Это
i
ый элемент обратногоL
. Дополнение к биту~i
равно-i-1
, и поэтому исправляет ошибку по одномуL[-i]
.источник
PEP448 - Дополнительные обобщения распаковки
С выпуском Python 3.5 манипулирование списками, кортежами, наборами и диктовками стало еще лучше.
Превращение итерируемого в набор / список
Сравните пары:
Гораздо короче! Однако обратите внимание, что если вы просто хотите преобразовать что-то в список и присвоить его переменной, обычная расширенная повторяемая распаковка будет короче:
Подобный синтаксис работает для кортежей:
что похоже на расширенную итеративную распаковку, но со звездочкой и запятой на другой стороне.
Присоединение к спискам / кортежам
Распаковка немного короче конкатенации, если вам нужно добавить список / кортеж к обеим сторонам:
Печать содержимого нескольких списков
Это не ограничено
print
, но это определенно откуда большая часть пробега. PEP448 теперь позволяет распаковывать несколько раз, например так:Обновление нескольких элементов словаря
Это, вероятно, случится не очень часто, но синтаксис можно использовать для экономии при обновлении словарей, если вы обновляете как минимум три элемента:
Это в основном сводит на нет любую необходимость
dict.update
.источник
Изменить
import *
наimport*
Если вы не слышали,
import*
сохраняет символы!только на 1 символ длиннее,
import math as m
и вы можете удалить все экземплярыm.
Даже одноразовое использование экономит время!
источник
если значение i бесполезно:
или же
источник
for i in[0]*x:s+=input()
чтобы сохранить другое место. Кроме того, вы можете удалить пробел между exec и первой кавычкой, чтобы получитьexec's+=input();'*x
for i in[0]*x:s+=input()