Советы по игре в гольф на Python


248

Какие общие советы у вас есть для игры в гольф на Python? Я ищу идеи, которые могут быть применены к задачам кода-гольфа и которые, по крайней мере, несколько специфичны для Python (например, «удалить комментарии» - это не ответ).

Пожалуйста, оставьте один совет за ответ.


27
О, я вижу целый набор вопросов, подобных этому, для каждого языка ...
Р. Мартиньо Фернандес

4
@ Martinho Я согласен. Просто начал эквивалент C ++ . Я не думаю, что это плохо, поскольку мы не видим повторных ответов на многие из этих типов вопросов.
Marcog

50
Мне нравится вопрос, но я должен постоянно повторять себе: «Это ТОЛЬКО для развлечения, а не для производственного кода»
Грег

2
Разве этот вопрос не должен быть постом вики сообщества?
дорукайхан

3
@dorukayhan Нету; это действительный код-гольф советы вопрос, просить советы о сокращении питона кода для CG'ing целей. Такие вопросы совершенно уместны для сайта, и ни один из этих тегов прямо не говорит о том, что вопрос должен быть CW'd, в отличие от SO, который требовал, чтобы CG-вызовы были CW'd. Кроме того, написание хорошего ответа и поиск таких советов всегда заслуживают чего-то, что отнимается, если речь идет о вики сообщества.
Эрик Outgolfer

Ответы:


152

Используйте a=b=c=0вместо a,b,c=0,0,0.

Используйте a,b,c='123'вместо a,b,c='1','2','3'.


2
Это хороший совет в целом :)

28
Обратите внимание, что это не обязательно будет работать для определения изменяемых объектов, которые вы будете изменять на месте. a = b = [1] фактически отличается от a = [1]; b = [1]
isaacg

6
Самое смешное в первом совете - это то, что он работает и на Java.
Джастин

1
@Justin Да, но только с примитивными типами
HyperNeutrino

11
Но НИКОГДА не используйте a = b = c = [] или любое инстанцирование объекта, поскольку все переменные будут указывать на один и тот же экземпляр. Это, вероятно, не то, что вы хотите.
PhE

146

Условия могут быть длинными. В некоторых случаях вы можете заменить простой условный на (a,b)[condition]. Если conditionэто правда, то bвозвращается.

сравнить

if a<b:return a
else:return b

К этому

return(b,a)[a<b]

37
Это не совсем то же самое. Первый оценивает только выражение, которое возвращается, а второй всегда оценивает их оба. Эти из них делают короткое замыкание: a if a<b else bиa<b and a or b
Marinus

3
(lambda(): b, lambda(): a)[a < b]()сделай свое собственное короткое замыкание с лямбдами
Ming-Tang

3
@marinus, они не равны: просто рассмотрите P and A or Bдля любого, который дает bool(A)=False. Но (P and [A] or [B])[0]сделаю работу. См. Diveintopython.net/power_of_introspection/and_or.html для справки.
kgadek

6
Лямбды намного длиннее условного выражения.
user2357112

18
@ user2357112 Но они заставляют вас выглядеть намного круче, когда вы их используете. :]
Чейз Райс

117

Замечательная вещь, которую я сделал однажды:

if 3 > a > 1 < b < 5: foo()

вместо:

if a > 1 and b > 1 and 3 > a and 5 > b: foo()

Операторы сравнения Python качаются.


Используя то, что в Python 2 все сравнимо, вы также можете избежать andоператора таким образом. Например, если a, b, cи dявляются целыми числами,

if a<b and c>d:foo()

можно сократить на один символ до:

if a<b<[]>c>d:foo()

При этом каждый список больше любого целого.

Если cи dесть списки, это становится еще лучше:

if a<b<c>d:foo()

22
Конечно, если бы это было на самом деле в гольф, это было бы3>a>1<b<5
Rafe Kettler

4
Люблю симметрию. Напоминает мне старый трюк с гольфом в Perl для нахождения минимума $ a и $ b: [$a => $b]->[$b <= $a]:)
Саймон Уитакер

Обратите внимание, что второй пример (без списков) также можно выполнить с помощьюif(a<b)+(c>d):foo()
WorldSEnder

6
+ Должен быть *. Ан orбудет+
WorldSEnder

1
foo()if 3>a>1<b<5
Эрик Outgolfer

103

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

r=range
for x in r(10):
 for y in r(100):print x,y

6
На самом деле не сохранил ни одного байта.
user2357112

4
r = диапазон, а два других r - 9 символов; использование диапазона дважды составляет 10 символов. Не большая экономия в этом примере, но все, что нужно, это еще одно использование диапазона, чтобы увидеть значительную экономию.
Фрэнк

13
@Frank Дополнительный символ новой строки - другой символ.
L3viathan

2
Действительно, двух повторений слишком мало, чтобы сэкономить на длине имени функции пять. Вам нужно: длина 2: 6 повторений, длина 3: 4 повторения, длина 4 или 5: 3 повторения, длина> = 6: 2 повторения. АКА (длина-1) * (повторов-1)> 4.
Орджан Йохансен,

Обратите внимание, что это применимо ко всем языкам с первоклассными функциями.
bfontaine

94

Иногда ваш код Python требует, чтобы у вас было 2 уровня отступа. Очевидная вещь, которую нужно сделать - использовать один и два пробела для каждого уровня отступа.

Однако Python 2 считает символы табуляции и пробела разными уровнями отступа.

Это означает, что первый уровень отступа может быть одним пробелом, а второй - одним символом табуляции.

Например:

if 1:
 if 1:
\tpass

Где \tнаходится символ табуляции.


1
Круто, я никогда не думал об этом!
Жюль Оллеон

97
Это терпит неудачу в python3: вы больше не можете смешивать пробелы и табуляции (плохо для codegolf, но хорошо во всех других случаях).
Бакуриу

1
В Python 3.4 это работает нормально.
Трихоплакс

3
@trichoplax , в python 3.4.3 я получаюTabError: inconsistent use of tabs and spaces in indentation.
floorcat

Для справки, вкладка стоит 8 пробелов.
Эрик Outgolfer

87

Используйте подстановку строк и execдля работы с такими длинными ключевыми словами lambda, которые часто повторяются в вашем коде.

a=lambda b:lambda c:lambda d:lambda e:lambda f:0   # 48 bytes  (plain)
exec"a=`b:`c:`d:`e:`f:0".replace('`','lambda ')    # 47 bytes  (replace)
exec"a=%sb:%sc:%sd:%se:%sf:0"%(('lambda ',)*5)     # 46 bytes  (%)

Целевая строка очень часто 'lambda ', длиной 7 байт. Предположим, что ваш фрагмент кода содержит nвхождения 'lambda 'и имеет sдлину в байты. Затем:

  • plainОпция sбайт длиной.
  • replaceОпция s - 6n + 29байт длиной.
  • %Опция s - 5n + 22 + len(str(n))байт длиной.

Из графика байтов, сохраненногоplain для этих трех вариантов, мы можем видеть, что:

  • Для n <5 лямбд, вам лучше вообще ничего не делать.
  • При n = 5 запись exec"..."%(('lambda ',)*5)сохраняет 2 байта и является вашим лучшим вариантом.
  • Для n> 5 запись exec"...".replace('`','lambda ')- ваш лучший вариант.

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

          1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 (occurences)
       +---------------------------------------------------------
     3 |  -  -  -  -  -  -  -  -  -  -  -  -  -  -  r  r  r  r  r  
     4 |  -  -  -  -  -  -  -  -  -  r  r  r  r  r  r  r  r  r  r  
     5 |  -  -  -  -  -  -  -  r  r  r  r  r  r  r  r  r  r  r  r  
     6 |  -  -  -  -  -  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
     7 |  -  -  -  -  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
     8 |  -  -  -  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
     9 |  -  -  -  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
    10 |  -  -  %  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
    11 |  -  -  %  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
    12 |  -  -  %  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r = replace
    13 |  -  -  %  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r   % = string %
    14 |  -  %  %  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r   - = do nothing
    15 |  -  %  %  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
  (length)

Например, если строка lambda x,y:(длина 11) встречается в вашем коде 3 раза, лучше писать exec"..."%(('lambda x,y:',)*3).


4
это должно получить больше голосов, это очень полезный совет.
bigblind

7
это очень редко, что это работает. стоимость replaceогромна.
Boothby

4
Когда это работает, тем не менее, это очень помогает.
подземный

Интересно, никогда даже не думал об этом!
Клавдиу

Я добавил новый оператор для лямбды на моем языке, основанном на python: =>это просто строка = lambda . Например, f=>:0будет f = lambda: 0.
NoOneIsHere

78

Используйте расширенную нарезку, чтобы выбрать одну строку из многих

>>> for x in 0,1,2:print"fbboaaorz"[x::3]
... 
foo
bar
baz

против

>>> for x in 0,1,2:print["foo","bar","baz"][x]
... 
foo
bar
baz

В этом булевом двухстрочном случае можно также написать

b*"string"or"other_string"

за

["other_string","string"][b]

В отличие от чередования, это работает для строк любой длины, но может иметь проблемы с приоритетом операторов, если bвместо этого используется выражение.


Обратите внимание, что первый пример точно такой же длины, как иfor x in ("foo","bar","baz"): print x
Матин Улхак

1
@MateenUlhaq, это просто пример того, как xотображаются различные значения . Golfed часть является "fbboaaorz"[x::3]против ["foo","bar","baz"][x]Как xстоимость определяется будет другая часть вашего решения для гольфа.
gnibbler

72

Используйте `n`для преобразования целого числа в строку вместо использования str(n):

>>> n=123
>>> `n`
'123'

38
Хорошо, но не работает с Python3.
Александру

2
Внимание: действительно работает для целых чисел, но не для строк, например.
Накилон

41
Кстати. `` коротка для repr
Александру

9
Целые числа меньше -2 ** 31 или больше 2 ** 31-1 (длинные) получают в конце букву 'L'.
hallvabo

6
Это также может быть использовано для печати поплавков с полной точностью
gnibbler

69

Хранить таблицы поиска как магические числа

Скажем, вы хотите жестко закодировать булеву таблицу поиска, например, какое из первых двенадцати английских чисел содержит n.

0: False
1: True
2: False
3: False
4: False
5: False
6: False
7: True
8: False
9: True
10:True
11:True
12:False

Затем вы можете кратко реализовать эту таблицу поиска как:

3714>>i&1

с полученным 0или 1быть равным , Falseчтобы True.

Идея состоит в том, что магическое число хранит таблицу как цепочку битов bin(3714)= 0b111010000010, с nдесятой цифрой (от конца), соответствующей nзаписи таблицы. Мы nполучаем доступ к th-записи, сдвигая битовые nпробелы справа и беря последнюю цифру &1.

Этот способ хранения очень эффективен. Сравните с альтернативами

n in[1,7,9,10,11]
'0111010000010'[n]>'0'

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

 340954054>>4*n&15

извлечь соответствующий четырехбитный блок.


Можем ли мы получить пример результата для четырехбитного блока? Вы использовали правило для n-битного блока?
JeromeJ

8
Гекс может иногда быть еще меньше.
Joonazan

4
Это полезно для многих языков.
Cyoce

1
@Joonazan Hex меньше для чисел свыше 999 999 .
Матин Улхак

60

Свернуть два числовых цикла в один

Скажем, вы перебираете ячейки m*nсетки. Вместо двух вложенных forциклов, одного для строки и одного из столбцов, обычно короче использовать один цикл для итерации по m*nячейкам сетки. Вы можете извлечь строку и столбец ячейки внутри цикла.

Оригинальный код:

for i in range(m):
 for j in range(n):
  do_stuff(i,j)

Гольф-код:

for k in range(m*n):
  do_stuff(k/n,k%n)

По сути, вы перебираете декартово произведение двух диапазонов, кодируя пару (i,j)как x=i*n+j. Вы сохранили дорогой rangeвызов и уровень отступа внутри цикла. Порядок итерации неизменен.

Используйте //вместо /в Python 3. Если вы ссылаетесь iи jмного раз, это может быть быстрее , чтобы назначить их значение i=k/n, j=k%nвнутри цикла.


5
Это круто. Я никогда не осознавал, что это возможно!
theonlygusti

Я видел это в советах по JavaScript. Это довольно полезный трюк в большинстве языков.
Cyoce

7
Для справки, чтобы расширить это до 3 петель:for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
mbomb007

3
Для nциклов: repl.it/EHwa
mbomb007

В некоторых случаях itertools.productможет быть гораздо более кратким, чем вложенные циклы, особенно при создании декартовых произведений. a1, a2, b1, b2примеры декартовых произведений 'ab'и'12'
Aaron3468

54

Если следующий токен не начинается с eили E. Вы можете удалить пробел после числа.

Например:

if i==4 and j==4:
    pass

становится:

if i==4and j==4:
    pass

Использование этого в сложных однострочных операторах может сохранить довольно много символов.

РЕДАКТИРОВАТЬ: как указал @marcog, 4or aбудет работать, но не так, a or4как это путают с именем переменной.


37
if(i,j)==(4,4):еще короче и в этом особом случаеif i==j==4:
gnibbler

3
Связанный: 4or aработает, но неa or4
marcog

17
0orтакже не работает ( 0oэто префикс для восьмеричных чисел).
Набб

5
@Nabb Не то чтобы это 0 or xвсе равно имело значение, потому что всегда вернется x. Сможешь вырезать 0 or.
ɐɔı14uʎs

5
0orхорошо как часть более длинного числа все же. 10 or xэквивалентно 10or x.
Трихоплакс

54

Для целого числа nвы можете написать

  • n+1 как -~n
  • n-1 как ~-n

потому что бит флип ~xравен -1-x. При этом используется то же количество символов, но можно косвенно сократить пробелы или скобки для приоритета оператора.

Для сравнения:

while n-1:  #Same as while n!=1 
while~-n:

c/(n-1)
c/~-n

or f(n)+1
or-~f(n) 

(n-1)/10+(n-1)%10
~-n/10+~-n%10

Операторы ~и Унарный -выше приоритет , чем *, /, %, в отличие от двоичного файла +.


11
Вариант этого трюка, с которым я столкнулся сегодня: -~-xсохраняет один байт против (1-x).
Линн

4
Другое полезное приложение, которое a+b+1может быть более кратко написано как a-~b.
Стригоидес

И n-i-1это просто n+~i.
Руохола

51

Хороший способ конвертировать итерируемое в список на Python 3 :

представьте, что у вас есть итеративный, как

i = (1,2,3,4)
i = range(4)
i = (x**2 for x in range(5))

Но вам нужен список:

x=list(i)  #the default way
*x,=i      #using starred assignment -> 4 char fewer

Это очень полезно сделать список символов из строки

s=['a','b','c','d','e']
s=list('abcde')
*s,='abcde'

1
набрав, *s,='abcde'а затем sвылетает мой интерактивный python3 с segfault :(
daniero

@daniero Ух ты. Только на интерактивной консоли? Звучит очень странно. Попробуйте это на чистой консоли или сообщите об ошибке
JBernardo

1
Мой Python 3.5 работает нормально.
NoOneIsHere

при г = (х ** 2 для й в диапазоне (5)) я получаю этот код возвращается <объект генератор <genexpr> в 0x03321690>
джордж

7
И если вы делаете это в выражении, вы можете сделать [*'abcde'].
Esolanging Fruit

46

Вместо этого range(x)вы можете использовать *оператор в списке чего угодно, если вам на самом деле не нужно использовать значение i:

for i in[1]*8:pass

в отличие от

for i in range(8):pass

Если вам нужно сделать это более двух раз, вы можете назначить любую итерацию переменной и умножить эту переменную на нужный вам диапазон:

r=1,
for i in r*8:pass
for i in r*1000:pass

Примечание : это часто длиннее exec"pass;"*8, поэтому этот трюк следует использовать только тогда, когда это невозможно.


@proudhaskeller Я думаю, что смысл строки, которую вы удалили, заключался в том, что «В дополнение к очевидной экономии символов, которую вы получаете, потому что [1]*8короче range(8), вы также можете сэкономить место, потому что for i in[...законно, а for i in range...нет».
подземный

о, верно, я этого не поняла исправлено сейчас
гордый haskeller

7
exec"pass;"*8значительно короче.
DJMcMayhem

1
если r=1, r*8это 8, и вы не можете перебрать номер. Я думаю, вы имели в видуr=[1]
Артемида Фаул

1
@ArtemisFowl, нет, все в порядке, запятая после 1 создает кортеж, который можно повторять.
Саша

43

Вы можете использовать старый добрый инопланетный смайлик, чтобы изменить последовательность:

[1, 2, 3, 4][::-1] # => [4, 3, 2, 1]

38

Расширенная повторяемая распаковка («Помеченное назначение», только Python 3)

Лучший способ объяснить это на примере:

>>> a,*b,c=range(5)
>>> a
0
>>> b
[1, 2, 3]
>>> c
4

Мы уже видели использование для этого - превращение итерируемого в список в Python 3 :

a=list(range(10))
*a,=range(10)

Вот еще несколько вариантов использования.

Получение последнего элемента из списка

a=L[-1]
*_,a=L

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

a=(L+[1])[0]
a,*_=L+[1]

Назначение пустого списка и других переменных

a=1;b=2;c=[]
a,b,*c=1,2

Удаление первого или последнего элемента из непустого списка

_,*L=L
*L,_=L

Это короче, чем альтернативы L=L[1:]и L.pop(). Результат также может быть сохранен в другом списке.

Советы любезно предоставлены @grc


Вау! Я написал a=1;L=[]так много раз. Удивительно, что вы можете сэкономить символы на чем-то таком простом, как это.
xnor

@xnor Это благодаря grc. Только с одним другим элементом это не так хорошо ( a,*L=1,), но все равно сохраняет один символ :)
Sp3000

не забывайте, что вы также можете получить как первый, так и последний элемент списка сa,*_,b=L
Cyoce

36

установить литералы в Python2.7

Вы можете написать наборы, подобные этому. S={1,2,3}Это также означает, что вы можете проверить членство, используя {e}&Sвместо e in Sкоторого один символ.


4
И это также сохраняет символ в ifs, так как нет пробелов ( if{e}&S:)
Artyer

1
Обратите внимание, что вы можете заменить not inна {e}-Sэтот трюк
Черная Сова Кай

35

Веками меня беспокоило, что я не мог придумать краткий способ получить весь алфавит. Если вы используете rangeдостаточно того, что R=rangeстоит иметь в вашей программе, то

[chr(i+97)for i in R(26)]

короче наивного

'abcdefghijklmnopqrstuvwxyz'

, но в противном случае он длиннее на один символ. Меня преследовало, что умный, требующий некоторых знаний о значениях ascii, оказался более многословным, чем просто ввод всех букв.

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

map(chr,range(97,123))

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

map(chr,range(65,91))

Я mapслишком много использую, я не знаю, как это никогда не происходило со мной.


4
Могу использовать это в реальном кодировании, я чувствую себя настолько глупо, когда
жестко кодирую

37
В реальном кодировании используйте string.lowercase- вот для чего оно.
Кевин С.

1
если вам нужны оба случая, самый короткий путь, который я знаю, - это фильтр (str.isalpha, map (chr, range (256))). Он чуть короче, чем s = map (chr, range (256)); s + = map (str.lower, s)
квинтопия

@quintopia: почему 256 вместо 122 ( ord('z'))? Помимо одинаковой длины ... Кроме того, если вам нужны буквенно-цифровые str.isalphaсимволы , замените в версии @ quintopia на str.isalnum. (Но если вам нужен только один регистр, вся строка из 36 символов не длиннее filter(str.isalnum,map(chr,range(90))).)
Тим Педерик

2
Если вы собираетесь быть несправедливым и использовать диапазон как R, моя версия короче, чем ваша оригинальная: '%c'*26%tuple(R(97,123))(всего 24 знака), если вы пишете, rangeона равна длине алфавита - заглавная версия короче
JBernardo

32

Хотя в python нет операторов switch, вы можете эмулировать их с помощью словарей. Например, если вам нужен такой переключатель:

switch (a):
    case 1:
        runThisCode()
        break
    case 2:
        runThisOtherCode()
        break
    case 3:
        runThisOtherOtherCode()
        break

Вы можете использовать ifзаявления, или вы могли бы использовать это:

exec{1:"runThisCode()",2:"runThisOtherCode()",3:"runThisOtherOtherCode()"}[a]

или это:

{1:runThisCode,2:runThisOtherCode,3:runThisOtherOtherCode}[a]()

что лучше, если все пути кода являются функциями с одинаковыми параметрами.

Для поддержки значения по умолчанию сделайте это:

exec{1:"runThisCode()"}.get(a,"defaultCode()")

(или это:)

­­{1:runThisCode}.get(a,defaultCode)()

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

exec{'key1':'code','key2':'code'}[key]+';codeThatWillAlwaysExecute'

И если вы просто хотите использовать переключатель для возврата значения:

def getValue(key):
    if key=='blah':return 1
    if key=='foo':return 2
    if key=='bar':return 3
    return 4

Вы можете просто сделать это:

getValue=lambda key:{'blah':1,'foo':2,'bar',3}.get(key,4)

2
Это то, что я хотел бы рассмотреть в дикой природе. Я так скучаю по своим заявлениям о смене! +1
HalosGhost

1
Хотя вместо использования словаря с пронумерованными ключами в первом примере, вы должны просто использовать список
Cyoce

1
Если в качестве ключей используются строки, dict(s1=v1,s2=v2,...,sn=vn)вместо {'s1':v1,'s2':v2,...,'sn':vn}2 * n-4 байт используется экономия, и лучше, если n> = 3
Black Owl Кай,

31

Если у вас есть два логических значения, aи b, если вы хотите , чтобы выяснить, как aи bистинны, использовать *вместо and:

if a and b: #7 chars

против

if a*b: #3 chars

если любое из значений равно false, оно будет оцениваться так же, как 0в этом операторе, а целочисленное значение имеет значение true, только если оно отлично от нуля.


9
Или вы могли бы использовать &: a=b=False,a&b
ɐɔıʇǝɥʇuʎs

3
использовать +для orесли вы можете гарантироватьa != -b
undergroundmonorail

2
|работает во всех ситуациях.
CalculatorFeline

1
*вместо and/ &&сохраняет несколько байтов во многих языках.
Wastl

26

Эксплойт 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действительных чисел, и вы хотите проверить, содержит ли он какие-либо отрицательные числа, производя логическое значение.

Ты можешь сделать

'-'in`l`

который проверяет наличие отрицательного знака в строке rep. Это короче, чем любой из

any(x<0for x in l)
min(l+[0])<0   

Во-вторых, min(l)<0произойдет сбой в пустом списке, поэтому вам придется хеджировать.


Конкатенация строк из одной цифры также эффективна в Python 3, хотя и менее: str(l)[2::5]12 байтов против 19 для ''.join(map(str,l)). Фактическая ситуация, когда это произошло (где lбыл оператор-генератор, а не список), спасла мне всего один байт ... который все еще стоит!
Тим Педерик

25

Функция с одной строкой может быть выполнена с помощью лямбды:

def c(a):
  if a < 3: return a+10
  else: return a-5

может быть преобразовано в (обратите внимание на пропущенное место 3andи 10or)

c=lambda a:a<3and a+10or a-5

21
или c=lambda a:a+[-5,10][a<3]. и и / или трюк более полезен, когда вы
зависите

3
В вашей функции else: может быть отброшено, так как returnостанавливает выполнение функции, поэтому все, что следует, выполняется только в случае сбоя ifусловия, иначе говоря, если elseусловие истинно. Таким образом elseможно смело опускать. (Объясняется подробно для неофитов там)
JeromeJ

c (-10) возвращает -15, а должно возвращать 0
Anvit

илиc=lambda a:a-5+15*(a<3)
JayXon

25

Циклы до 4-х предметов может быть лучше, чтобы снабдить кортеж вместо использования диапазона

for x in 0,1,2:

против

for x in range(3):

24

Потолок и пол

Если вы когда-нибудь захотите получить округленный результат для деления, так же, как и //для пола, вы можете использовать math.ceil(3/2)для 15 или намного меньше -(-3//2)для 8 байт.

math.floor(n)   : 13 bytes+12 for import
n//1            : 4  bytes

math.ceil(n)    : 12 bytes+12 for import
-(-n//1)        : 8  bytes

5
Это только спасло мне около 20 байтов, спасибо!
Морган Трепп

1
иногда вы можете обойтись без n//1+1ceil, но это означает, что ceil (n) = n + 1, но это должно работать для всех нецелых значений
fejfo

round(x)is (x+.5)//1, +1 байт, но последний начинается с a (, и если xэто сумма, состоящая из константы, это может быть полезно.
user202729

23

Используйте +=вместо appendиextend

A.append(B)  

можно сократить до:

A+=B,

B,здесь создает одноэлементный кортеж, который можно использовать для расширения, Aкак [B]в A+=[B].


A.extend(B)

можно сократить до:

A+=B

5
Во многих (но не во всех) случаях return 0или return 1эквивалентно return Falseили return True.
подземный

5
(1) работает, только если вы уже знаете, что число отрицательное, и в этом случае вы можете сохранить еще 2 символа, просто используя знак минус. -xа не x*-1. --8.32а не -8.32*-1. Или просто 8.32...
trichoplax

Цитируя ОП: Пожалуйста, оставьте один совет за ответ.
nyuszika7h

Обратите внимание, что в A+=B Bэто tuple.
Эрик Outgolfer

23

Выбор одного из двух чисел на основе условия

Вы уже знаете, использовать выбор списка [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его вместо этого.


22

Используйте ~, чтобы индексировать в конце списка

Если Lэто список, используйте, L[~i]чтобы получить i'-ый элемент сзади.

Это iый элемент обратного L. Дополнение к биту ~iравно -i-1, и поэтому исправляет ошибку по одному L[-i].


21

PEP448 - Дополнительные обобщения распаковки

С выпуском Python 3.5 манипулирование списками, кортежами, наборами и диктовками стало еще лучше.

Превращение итерируемого в набор / список

Сравните пары:

set(T)
{*T}

list(T)
[*T]

tuple(T)
(*T,)

Гораздо короче! Однако обратите внимание, что если вы просто хотите преобразовать что-то в список и присвоить его переменной, обычная расширенная повторяемая распаковка будет короче:

L=[*T]
*L,=T

Подобный синтаксис работает для кортежей:

T=*L,

что похоже на расширенную итеративную распаковку, но со звездочкой и запятой на другой стороне.

Присоединение к спискам / кортежам

Распаковка немного короче конкатенации, если вам нужно добавить список / кортеж к обеим сторонам:

[1]+T+[2]
[1,*T,2]

(1,)+T+(2,)
(1,*T,2)

Печать содержимого нескольких списков

Это не ограничено print, но это определенно откуда большая часть пробега. PEP448 теперь позволяет распаковывать несколько раз, например так:

>>> T = (1, 2, 3)
>>> L = [4, 5, 6]
>>> print(*T,*L)
1 2 3 4 5 6

Обновление нескольких элементов словаря

Это, вероятно, случится не очень часто, но синтаксис можно использовать для экономии при обновлении словарей, если вы обновляете как минимум три элемента:

d[0]=1;d[1]=3;d[2]=5
d={**d,0:1,1:3,2:5}

Это в основном сводит на нет любую необходимость dict.update.


6
Это выглядит хуже, чем Perl, но это работает ...
Mega Man

20

Изменить import *наimport*


Если вы не слышали, import*сохраняет символы!

from math import*

только на 1 символ длиннее, import math as mи вы можете удалить все экземплярыm.

Даже одноразовое использование экономит время!


19
>>> for i in range(x):s+=input()

если значение i бесполезно:

>>> for i in[0]*x:s+=input()

или же

>>> exec's+=input();'*x

8
Вы можете сделать второй пример, for i in[0]*x:s+=input()чтобы сохранить другое место. Кроме того, вы можете удалить пробел между exec и первой кавычкой, чтобы получитьexec's+=input();'*x
Джастин Пил

не должно быть второй строки:for i in[0]*x:s+=input()
micsthepick

Dupe (новее, но больше голосов)
user202729
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.