Как и во многих языках в python 1 эквивалентно True, а 0 — False, то есть
1 == True.
Казалось бы, и что в этом такого? Однако, это имеет некоторые побочные эффекты, связанные с тем, что одинаковые объекты обязаны иметь одинаковые хеши, соответственно у вас не получится запихать в один словарь ключ 1 и True.
>>> a = {1: "one", 0: "zero", True: "true", False: "false"} # -> {1: 'true', 0: 'false'}
Так же это разрешает следующие операции:
>>> print(2 * False + True) # -> 1
В данном примере строки использовались в качестве значений словаря, однако, зачастую хочется использовать строки в качестве ключей словаря, меня всегда раздражало, что при создании словаря с помощью фигурных скобок, строки нужно указывать в кавычках, хотелось бы их опустить, это возможно, если создавать словарь через конструктор dict().
>>> {"one": 1, "two": 2, "three": 3} == dict(one=1, two=2, three=3) # -> True
Кроме того, с помощью фигурных скобок создаются не только словари, но и множества(set).
>>> a = {1, 2, 3}
Для объединения двух множеств мне почему-то хочется воспользоваться оператором +, наверно, из-за способа конкатенации строк. Однако, python не поддерживает данный оператор для множеств. Но разумеется, это не значит, что нам всегда придётся пользоваться функциями, создатели подошли к данному вопросу более системно и добавили в язык поддержку основных операций над множествами (а не только объединения) и «повесили» их на логические операторы.
a = {1, 2, 3} b = {0, 2, 4} print(a & b) # -> {2} print(a | b) # -> {0, 1, 2, 3, 4} print(a ^ b) # -> {0, 1, 3, 4} print(a - b) # -> {1, 3}, однако один арифметический # оператор всё же оставили
Продолжая разговор про словари, начиная с версии 3.7 спецификацией языка гарантируется, что словари сохраняют порядок вставки элементов, OrderedDict больше не нужен.
www.python.org/downloads/release/python-370
mail.python.org/pipermail/python-dev/2017-December/151283.html
d = dict(zero='Cero', one='Uno', two='Dos', three='Tres', four='Cuatro', five='Cinco', six='Seis', seven='Siete', eight='Ocho', night='Nueve') for index, (key, value) in enumerate(d.items()): print(f"{index} is {key} in England and {value} in Spain")
Обратите внимание не строку вывода, она начинается с префикса f — это особый тип строк, введённый в python 3.6.
Всего в python три вида строк: обычные, обозначаемые кавычками без префиксов, сырые\не обрабатываемые(raw), в которых спец-символы, вроде, \n не обрабатываются и вставляются как текст и собственно f-строки.
Созданы они были для упрощения вывода, python поддерживает огромное количество способов вывода:
print("result" + str(2)) # Простая конкатенация строк, python не осуществляет # автоматическое приведение всех аргументов к # строковому типу, это остаётся за программистом print("result", 2) # print может принимать несколько аргументов через запятую, # в таком случае они будут выводиться через пробел, # вам не нужны преобразовывать выводимые объекты в строку, # в отличие от предыдущего способа print("result %d" % 2) # %-синтаксис, сделан по аналогии с языком C. print("result %d %.2f" % (2, 2)) # https://docs.python.org/3.4/library/string.html#formatspec print("result %(name)s" % {"name": 2}) # также разрешено создавать именованные метки print("{}".format(2)) # У класса строки есть метод format() # он позволяет опускать тип выводимой переменной print("{0} {1} {0}".format(1, 2)) # так же можно указать номер переменной и таким образом # вывести её два раза # нумерация начинается с нуля # если число переданных переменных меньше использованных в выводе, будет сгенерированно исключение print("{} {}".format(2)) # -> IndexError: tuple index out of range print("{0} {0}".format(2, 3)) # -> 2 2 Однако если передано слишком много переменных # код отработает без ошибок from math import pi # при таком выводе так же поддерживаются строки формата print("{:.2f}".format(pi)) # -> 3.14 from string import Template # возможен и такой способ вывода s = Template("result $res") # однако он не получил большого распространения
Теперь добавили ещё и f-строки. В них доступны любые переменные из области видимости, можно вызывать функции, получать элементы по ключу, кроме того, они поддерживают строки формата.
from math import pi result = 4 name = "user" print(f"{name:84s} pi= {pi:.2f}, result={result}, {name[2]}") # -> user pi= 3.14, result=4, e from datetime import datetime print(f"{datetime.now():%Y:%m-%d}")
Кроме того они быстрее всех остальных способов вывода, так что, если вам доступен python3.6 рекомендуется использовать именно их.
Одна из наикрутейших фишек python — в нём упаковываются и распаковываются не объекты и примитивы, а параметры и коллекции.
def func(*argv, **kwargs)
Однако, есть один архитектурный недостаток в реализации:
- argv — кортеж, его значения нельзя изменять, нельзя добавлять или удалять значения
- kwargs — словарь, изменяемый, поэтому кеширование невозможно
Недостаток, конечно, не большой, но всё же неприятно, что нельзя напрямую передавать kwargs в кеш, основанный на словаре, с другой стороны, если вы добавите в кортеж список, то такой кортеж тоже нельзя будет просто так добавить в словарь.
Множества тоже создаются на основе хеш-таблицы, это значит, что значения должны быть хешируемы, кроме того само множество является изменяемым и не хешируемым типом, есть специальный тип frosenset — не изменяемое множество (не спрашивайте меня, зачем оно нужно).
Обсуждали создание типа frosendict, однако пока его не добавили (хотя как минимум одно применение ему уже есть — в качестве kwargs). За неизменяемый словарь приходится отдуваться namedtuple. А также за записи и простенькие классы.
Кто в студенческие\школьные годы писал циклы для вывода значений массива и бесился из-за запятой в конце, каждый раз решал, забить или переписать, чтобы было красиво, и только на курсе 2-3 узнал о методе join? Или я один такой?
Одна из неприятных особенностей метода join у строк — он работает только с элементами-строками, если в коллекции есть хоть одна не строка приходится использовать генераторное выражение, что выглядит слишком сложным решением такой простой задачи, однако, есть способ упростить вывод значений списков (без скобок).
a = list(range(5)) print(" ".join(a)) # -> TypeError: sequence item 0: expected str instance, int found print(" ".join(str(i) for i in a)) # -> 0 1 2 3 4 print(*a) # -> 0 1 2 3 4
Так как строки — тоже коллекции, то их так же можно «джойнить».
print('-'.join("hello")) # -> h-e-l-l-o
Рассмотрим строку из предыдущего примера.
print(" ".join(str(i) for i in a)) # -> 0 1 2 3 4
Генераторное выражение передано в ф-цию join без каких-нибудь скобок, круглые скобки можно опускать для упрощения чтения кода. Python заботится о выразительности.
print(sum(i**2 for i in range(10))) # -> 285
Кроме того, круглые скобки можно опускать и при создании кортежей:
article = "python", 2018, "LinearLeopard" # объявление кортежа theme, year, author = "python", 2018, "LinearLeopard"# распаковка кортежа theme, year, _ = "python", 2018, "LinearLeopard" # слева и справа должно # находиться одинакове число # переменных, можно подчеркнуть, # что вам какая-то не нужно, # обозначив её через # подчёркивание theme, _, _ = "python", 2018, "LinearLeopard" # имена могут повторяться theme, * author = "python", 2018, "LinearLeopard" # можно объявить жадный # параметр, который съест # все неподходящие, # разумеется, допустим # только один # жадный оператор
Звёздочку можно использовать и в объявления функций, таким образом можно создать параметры, которые можно указать только по ключу.
def sortwords(*wordlist, case_sensitive=False):
Можно передавать в ф-цию сколько угодно параметров без боязни, что один из них будет воспринят как значение параметра case_sensitive.
Можно и так.
def func(first, second, *, kwonly):
С параметрами по умолчанию связана одна интересная особенность: они вычисляются на этапе компиляции модуля в байт код, так что лучше не использовать там изменяемые типы. Объявим функцию, которая добавляет элемент в конец списка, если второй аргумент опущен, функция возвращает новый список в котором содержится только этот элемент.
def add_to(elem, collection=[]): collection.append(elem) return collection a = ["a", "c"] print(add_to("b", a)) # -> ['a', 'c', 'b'] print(add_to("a")) # -> ['a'] print(add_to("b")) # -> ['a', 'b'] Откуда здесь 'a'?
Значения по умолчанию ф-ция хранит в поле __defaults__, можно в любой момент узнать, что там находится.
print(add_to.__defaults__) # -> (['a', 'b'],)
Так как аргумент по умолчанию (пустой список) создался в момент старта программы и не пересоздаётся каждый раз заново, мы получили именно такое поведение.
Исправить подобное поведение можно, если сделать значение по умолчанию неизменяемым типом,
а список создавать в теле функции:
def add_to(elem, collection=None): collection = collection or [] collection.append(elem) return collection
Обратите внимание на команду
collection = collection or []
это более короткий (и менее понятный, хотя не для всех) аналог
collection = collection if collection else []
ссылка на оригинал статьи https://habr.com/post/421993/
Добавить комментарий