|
|||||||
Странности языка Python, которые могут вас укусить
Время создания: 29.07.2019 23:51
Раздел: Разные закладки - Python
Запись: xintrea/mytetra_db_adgaver_new/master/base/1515947664l9aaz8z2uk/text.html на raw.githubusercontent.com
|
|||||||
|
|||||||
У языка Python, как и у любого другого, есть совершенно непонятные моменты, которые неплохо бы разобрать «по кирпичикам». Этим и займемся. Хорошим способом получить максимальную отдачу от приведенных здесь примеров будет их прочтение в хронологическом порядке: — Внимательно просмотрите исходный код примера. Если вы опытный программист на Python, то обязательно попробуете предсказать, что будет на выходе. — Взгляните на результат и:
P.S. Вы также можете воспользоваться командной строкой, установив wtfpython: $ npm install -g wtfpython Теперь просто запустите wtfpython в командной строке, которая откроет эту коллекцию в выбранном $PAGER. Примеры странностей языка Python Ну, что-то сомнительное… def square(x): """ Простая функция для вычисления квадрата числа путем сложения. """ sum_so_far = 0 for counter in range(x): sum_so_far = sum_so_far + x return sum_so_far def square(x): """ Простая функция для вычисления квадрата числа путем сложения. """ sum_so_far = 0 for counter in range(x): sum_so_far = sum_so_far + x return sum_so_far >>> square(10) 10 Для языка Python нет невозможного, но… Разве здесь не должно быть 100? Примечание. Если вы не можете воспроизвести это, попробуйте запустить файл mixed_tabs_and_spaces.py через оболочку. Объяснение:
Вывод (Python 3.x): TabError: inconsistent use of tabs and spaces in indentation Время для некоторых «хашбраунов»! some_dict = {} some_dict[5.5] = "Ruby" some_dict[5.0] = "JavaScript" some_dict[5] = "Python" Вывод: >>> some_dict[5.5] "Ruby" >>> some_dict[5.0] "Python" >>> some_dict[5] "Python" Дискриминация со стороны языка Python? «Python» уничтожил «JavaScript »? Объяснение: 5 (тип int) неявно преобразован в 5.0 (тип float) перед вычислением хеша Python. >>> hash(5) == hash(5.0) True Этот ответ из StackOverflow прекрасно объясняет причины. Изменение словаря во время итерации по нему x = {0: None}
for i in x: del x[i] x[i+1] = None print(i) Вывод: 0 1 2 3 4 5 6 7 Объяснение:
Удаление элемента списка в процессе итерации list_1 = [1, 2, 3, 4] list_2 = [1, 2, 3, 4] list_3 = [1, 2, 3, 4] list_4 = [1, 2, 3, 4]
for idx, item in enumerate(list_1): del item
for idx, item in enumerate(list_2): list_2.remove(item)
for idx, item in enumerate(list_3[:]): list_3.remove(item)
for idx, item in enumerate(list_4): list_4.pop(idx) Вывод: >>> list_1 [1, 2, 3, 4] >>> list_2 [2, 4] >>> list_3 [] >>> list_4 [2, 4] Вы можете догадаться, почему вывод [2, 4]? Объяснение: Не рекомендуется менять объект, который вы повторяете. Правильный способ сделать это – перебрать копию объекта, и list_3[:] делает именно это. >>> some_list = [1, 2, 3, 4] >>> id(some_list) 139798789457608 >>> id(some_list[:]) # Notice that python creates new object for sliced list. 139798779601192 Разница между del, remove и pop для языка Python:
Почему на выходе [2, 4]?
Обратные косые черты в конце строки Вывод: >>> print("\\ some string \\") >>> print(r"\ some string") >>> print(r"\ some string \")
File "<stdin>", line 1 print(r"\ some string \") ^ SyntaxError: EOL while scanning string literal Объяснение: Интерпретатор просто меняет поведение обратных косых черт, поэтому они проходят через себя и следующий символ. Вот почему обратная косая черта не работает в конце строки. Да, он существует! else для циклов. Одним из типичных примеров может быть: def does_exists_num(l, to_find): for num in l: if num == to_find: print("Exists!") break else: print("Does not exist") Вывод: >>> some_list = [1, 2, 3, 4, 5] >>> does_exists_num(some_list, 4) Exists! >>> does_exists_num(some_list, -1) Does not exist else в обработке исключений. Пример: try: pass except: print("Exception occurred!!!") else: print("Try block executed successfully...") Выход: Try block executed successfully... Объяснение:
is is not what it is! Ниже представлен известный во всем Интернете пример: >>> a = 256 >>> b = 256 >>> a is b True
>>> a = 257 >>> b = 257 >>> a is b False
>>> a = 257; b = 257 >>> a is b True Объяснение: Разница между is и ==:
То есть is для ссылочного равенства и == для равенства значений. Пример, чтобы прояснить ситуацию: >>> [] == [] True >>> [] is [] # Это два пустых списка в двух разных ячейках памяти. False is not … это не is (not …) >>> 'something' is not None True >>> 'something' is (not None) False Объяснение:
Функция внутри цикла и результат funcs = [] results = [] for x in range(7): def some_func(): return x funcs.append(some_func) results.append(some_func())
funcs_results = [func() for func in funcs] Вывод: >>> results [0, 1, 2, 3, 4, 5, 6] >>> funcs_results [6, 6, 6, 6, 6, 6, 6] Даже когда значения x были разными на каждой итерации до добавления some_func в funcs, все функции возвращали 6. //ИЛИ >>> powers_of_x = [lambda x: x**i for i in range(10)] >>> [f(2) for f in powers_of_x] [512, 512, 512, 512, 512, 512, 512, 512, 512, 512] Объяснение:
funcs = [] for x in range(7): def some_func(x=x): return x funcs.append(some_func) Вывод: >>> funcs_results = [func() for func in funcs] >>> funcs_results [0, 1, 2, 3, 4, 5, 6] Остерегайтесь измененных аргументов по умолчанию! def some_func(default_arg=[]): default_arg.append("some_string") return default_arg Вывод: >>> some_func() ['some_string'] >>> some_func() ['some_string', 'some_string'] >>> some_func([]) ['some_string'] >>> some_func() ['some_string', 'some_string', 'some_string'] Объяснение: Измененные по умолчанию аргументы функций в Python на самом деле не инициализируются каждый раз, когда вы вызываете функцию. Вместо этого в качестве значения по умолчанию используется последнее присвоенное им значение. Когда мы явно передали [] в some_func в качестве аргумента, значение по умолчанию переменной default_arg не использовалось, поэтому функция ожидаемо возвращалась. def some_func(default_arg=[]): default_arg.append("some_string") return default_arg Вывод: >>> some_func.__defaults__ #This will show the default argument values for the function ([],) >>> some_func() >>> some_func.__defaults__ (['some_string'],) >>> some_func() >>> some_func.__defaults__ (['some_string', 'some_string'],) >>> some_func([]) >>> some_func.__defaults__ (['some_string', 'some_string'],) Чтобы избежать ошибок из-за подобных аргументов, существует назначение None, которое используется по умолчанию, а также проверка того, передано ли какое-либо значение функции, соответствующей этому аргументу. Пример: def some_func(default_arg=None): if not default_arg: default_arg = [] default_arg.append("some_string") return default_arg Одинаковые операнды, разные истории! 1. a = [1, 2, 3, 4] b = a a = a + [5, 6, 7, 8] Вывод: >>> a [1, 2, 3, 4, 5, 6, 7, 8] >>> b [1, 2, 3, 4] 2. a = [1, 2, 3, 4] b = a a += [5, 6, 7, 8] Вывод: >>> a [1, 2, 3, 4, 5, 6, 7, 8] >>> b [1, 2, 3, 4, 5, 6, 7, 8] Объяснение:
Использование переменной, не определенной в области a = 1 def some_func(): return a
def another_func(): a += 1 return a Выход: >>> some_func() 1 >>> another_func() UnboundLocalError: local variable 'a' referenced before assignment Объяснение:
def another_func() global a a += 1 return a Вывод: >>> another_func() 2 Return return everywhere! def some_func(): try: return 'from_try' finally: return 'from_finally' Выход: >>> some_func() 'from_finally' Объяснение:
|
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|