Интересности и полезности Python |
||
МЕНЮ Искусственный интеллект Поиск Регистрация на сайте Помощь проекту ТЕМЫ Новости ИИ Искусственный интеллект Разработка ИИГолосовой помощник Городские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Техническое зрение Чат-боты Авторизация |
2018-09-04 20:17 Я уже несколько лет программирую на python, однако, недавно осознал, что множество полезных приёмов и интересных моментов прошли мимо меня, возможно, я не один такой, поэтому решил перечислить их здесь, надеюсь, данные приёмы пригодятся кому-то в работе или побудят познакомиться с этим языком поближе. Как и во многих языках в 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 больше не нужен. 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. Всего в языке три вида строк: обычные, обозначаемые кавычками без префиксов, сырыене обрабатываемые(raw), в которых спец-символы, вроде, не обрабатываются и вставляются как текст и собственно 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") # однако он не получил большого распространения print(s.substitute(res = [3, 4])) Теперь добавили ещё и 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) Однако, есть один архитектурный недостаток в реализации:
Недостаток, конечно, не большой, но всё же неприятно, что нельзя напрямую передавать kwargs в кеш, основанный на словаре, с другой стороны, если вы добавите в кортеж список, то такой кортеж тоже нельзя будет просто так добавить в словарь. Множества тоже создаются на основе хеш-таблицы, это значит, что значения должны быть хешируемы, кроме того само множество является изменяемым и не хешируемым типом, есть специальный тип frozenset — не изменяемое множество (не спрашивайте меня, зачем оно нужно). Обсуждали создание типа frozendict, однако пока его не добавили (хотя как минимум одно применение ему уже есть — в качестве 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): Внимательнее рассмотрим, чем просто * отличается от *args. def func(first, second, *, kwonly=True): print(first, second, kwonly) def func2(first, second, *args, kwonly=True): print(first, second, *args, kwonly) func(1) #-> TypeError: func() missing 1 required positional argument: 'second' func(1, 2) #-> 1 2 True func(1, 2, False) #-> TypeError: func() takes 2 positional arguments but 3 were given # используя * в объявлении вы укажите, что # ваша функция должна быть вызвана с двумя # позиционными параметрами func(1, 2, kwonly=False) #-> 1 2 False func2(1, 2, False) #-> 1 2 False True # *args заберёт в себя все позиционные # параметры, то есть вашу функцию может будет # вызывать с неограниченным (>2) числом # параметров С параметрами по умолчанию связана одна интересная особенность: они вычисляются на этапе компиляции модуля в байт-код, так что лучше не использовать там изменяемые типы. Объявим функцию, которая добавляет элемент в конец списка, если второй аргумент опущен, функция возвращает новый список в котором содержится только этот элемент. 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 [] Источник: m.vk.com Комментарии: |
|