Особенности Python, о которых я даже не подозревал
В последнее время у меня появилось новое хобби – чтение документации Python просто для удовольствия! Когда вы читаете на досуге, то, как правило, замечаете интересные «лакомые кусочки», которые в противном случае пропустили бы. Итак, вот перечень «кусочков», которые заставили меня сказать:
О! Вы можете сделать это на Python?
1. Атрибуты функций
Подобно тому, как вы можете устанавливать атрибуты классов и объектов, вы также можете устанавливать атрибуты функций.
def func(x):
intermediate_var = x**2 + x + 1
if intermediate_var % 2:
y = intermediate_var ** 3
else:
y = intermediate_var **3 + 1
# setting attributes here
func.optional_return = intermediate_var
func.is_awesome = 'Yes, my function is awesome.'
return y
y = func(3)
print('Final answer is', y)
# Accessing function attributes
print('Show calculations -->', func.optional_return)
print('Is my function awesome? -->', func.is_awesome)
Мы установили атрибуты «optional_return» в строке 10 и «is_awesome» в строке 11. Мы получили доступ к этим атрибутам вне функции позднее в строках 19 и 20. Результат кода:
Final answer is 2197
Show calculations --> 13
Is my function awesome? --> Yes, my function is awesome.
Это удобно, когда вы хотите, чтобы функция извлекала некую промежуточную переменную, но не возвращала её явно с оператором return каждый раз при вызове функции. Также обратите внимание, что атрибуты могут быть установлены как внутри определения функции, так и вне определения функции.
2. Цикл for-else
В Python вы можете добавить условие else в цикл for. Условие else будет срабатывать только в том случае, если во время выполнения в теле цикла не встретится оператор break.
my_list = ['some', 'list', 'containing', 'five', 'elements']
min_len = 3
for element in my_list:
if len(element) < min_len:
print(f'Caught an element shorter than {min_len} letters')
break
else:
print(f'All elements at least {min_len} letters long')
All elements at least 3 letters long
Обратите внимание, что else имеет отступ на уровне for, а не на уровне if. Здесь ни один элемент не имеет длины короче трёх. Таким образом, никогда не будет встречен оператор break. Следовательно, условие else будет запущено (после выполнения цикла for) и выведется результат, указанный выше.
Можно утверждать, что этого можно достичь с помощью отдельной переменной, которая отслеживает встретился ли оператор break. И, возможно, для другого человека, читающего код, это будет также менее запутанно. Далее приведен эквивалентный путь достижения того же результата:
my_list = ['some', 'list', 'containing', 'five', 'elements']
min_len = 3
no_break = True
for element in my_list:
if len(element) < min_len:
print(f'Caught an element shorter than {min_len} letters')
no_break = False
break
if no_break:
print(f'All elements at least {min_len} letters long')
Думаю, это полезно знать.
3. Разделители для int
Трудно визуально различить целые числа подобные 10000000 и 100000000 (они даже разные числа?). Мы не можем использовать запятые здесь, в Python, подобному тому, как мы используем их в английском языке, потому что Python интерпретирует это как кортеж из нескольких целых чисел.
У Python есть очень удобный способ справиться с этим: мы можем использовать подчеркивание как разделитель для улучшения читабельности. Таким образом, 1_000_000 будет интерпретироваться как целое число.
a = 3250
b = 67_543_423_778
print(type(a))
print(type(b))
print(type(a)==type(b))
<class 'int'>
<class 'int'>
True
4. eval () и exec ()
В Python есть возможность динамически считывать строку и обрабатывать её как часть Python кода. Это достигается использованием функций eval() и exec() (‘eval’ для вычисления выражений; и ‘exec’ для выполнения операторов).
a = 3
b = eval('a + 2')
print('b =', b)
exec('c = a ** 2')
print('c is', c)
b = 5
c is 9
В третьей строке функция eval() считывает входную строку как выражение Python, оценивает её и присваивает результат переменной b. В строке 6 функция exec() считывает входную строку как оператор Python и исполняет её.
Вы даже можете динамически передать созданные строки этим функциям. Например, вы можете создать 1000 переменных с именами х_0, х_1, .., х_999 без записи каждого объявления этих переменных вручную в коде. Может показаться, что это совершенно бессмысленно, но это не так.
В целом, в более широком контексте программирования (не только в отношении Python) использование eval/exec невероятно сильно, поскольку позволяет вам писать динамический код, который использует информацию, доступную во время выполнения, для решения проблем, которые не могут быть даже выражены во время компиляции. […] exec – это буквально интерпретатор Python, встроенный в Python, поэтому, если у вас есть особенно сложная проблема для разрешения, один из способов её решить – написать программу для *написания программы для её решения*, затем использовать exec для запуска этой второй программы.
Вы можете прочитать об этом в замечательном объяснении Стивена Д’Апрано.
5. Многоточие (Ellipsis)
Многоточие (или «…») - это встроенная константа Python, аналогичная таким встроенным константам как None, True, False и т.д. Её можно использовать по-разному, например, следующими способами (но, разумеется, не ограничиваясь ими):
5.1. Замена для ненаписанного кода
Подобно передаче, константы можно использовать в качестве замены, когда код не полностью написан, но требует некоторого заполнения для синтаксической правильности.
def some_function():
...
def another_function():
pass
5.2. Альтернатива NONE
None выбирают, когда хотят обозначить пустой ввод или возврат. Но иногда None может быть одним из ожидаемых входных или возвращаемых параметров функций. В этом случае Многоточие может служить заменой.
# calculate nth odd number
def nth_odd(n):
if isinstance(n, int):
return 2 * n - 1
else:
return None
# calculate the original n of nth odd number
def original_num(m=...):
if m is ...:
print('This function needs some input')
elif m is None:
print('Non integer input provided to nth_odd() function')
elif isinstance(m, int):
if m % 2:
print(f'{m} is {int((m + 1)/2)}th odd number')
else:
print(f'{m} is not an odd number')
original_num()
a = nth_odd(n='some string')
original_num(a)
b = nth_odd(5)
original_num(b)
original_num(16)
Функция nth_odd() вычисляет n-ое нечетное число, c учетом n. Функция original_num() вычисляет исходное число n, учитывая n-ое нечетное число. Здесь None – один из ожидаемых входных параметров функции original_num(), так что мы не можем использовать его как замену по умолчанию для аргумента m. Результат кода:
This function needs some input
Non integer input provided to nth_odd() function
9 is 5th odd number
16 is not an odd number
5.3. Нарезка массива в NumPy
NumPy использует многоточие для нарезки массива. Следующий код показывают два эквивалентных способа нарезки:
import numpy as np
a = np.arange(16).reshape(2,2,2,2)
print(a[..., 0].flatten())
print(a[:, :, :, 0].flatten())
[ 0 2 4 6 8 10 12 14]
[ 0 2 4 6 8 10 12 14]
Таким образом, ‘…’ показывает, что существует столько ‘:’, сколько необходимо.
Логическое значение Многоточия
В отличие от None (Логическое значение которого False), логическое значение Многоточия - True.
TL; DR
Итак, я обнаружил следующие интересные особенности.
Атрибуты Функций: присвоение атрибутов функциям, как и объектам.
Цикл for-else: отслеживание, был ли цикл выполнен без оператора break.
Разделители для int: 32_534_478 – это int.
eval() и exec(): читайте строки как код Python и запустите его.
Многоточие: универсальная встроенная константа.
Напутствие
Python – это не только полезный язык, но и действительно интересный. Все мы заняты своей жизнью, но это не мешает узнавать язык ради него самого. Я бы хотел узнать больше о Пасхальных Яйцах, которые вы, возможно, найдёте.
Комментариев нет:
Отправить комментарий