Comments 63
Любопытно, но я рад, что до всего этого дошел сам в процессе изучения
Зачем
somefoo = list(range(9))
, если range
уже возвращает список.>>> type(range(5))
<class 'range'>
Objects of type range are created using the range() function. They don’t support slicing, concatenation or repetition, and using in, not in, min() or max() on them is inefficient.
docs.python.org/release/3.0.1/library/stdtypes.html#sequence-types-str-bytes-bytearray-list-tuple-range
Благодаря вам, я теперь знаю, что range() возвращает не список)
>>> type(range(5))
<type 'list'>
Теперь вы знаете еще одно различие 2.# и 3.#.
Начать следовало бы с того, что «Pythonic» это путь использования Python правильно, знаючи, воспользовавшись существующими инструментами, применяя их там, где нужно. Иными словами, «как правильно программировать на Python» и не более того.
Хорошо что Python имеет такой путь, а точнее его прокладывают для первопроходцев, т.к. на других языках его не дают и, в результате чего, мы имеем сотни версий того, как правильно писать на других языках.
Хорошо что Python имеет такой путь, а точнее его прокладывают для первопроходцев, т.к. на других языках его не дают и, в результате чего, мы имеем сотни версий того, как правильно писать на других языках.
somecontaineriterator = iter(somecontainer) #unpythonic
some_container_iterator = iter(somecontainer) #pythonic
как-то попадалась библиотека для конструирования путей к файлам, позволяющая вместо
foo + "/" + baz
записывать простоfoo / baz
не напомните :?Pythonic — docs.python.org/library/os.path.html
Это, кстати, хоть и не Pythonic, но сама по себе идея отличная…
>>> bar = [] # pythonic
на днях, рассматривая логи коммитов, нашел удивительную чехорду патчей:
-foo = []
+foo = [ ]
затем-foo = [ ]
+foo = []
и так несколько раз. а как должно быть pythonic?
а нужно-ли делать, отступы на пустых строках, или нет:
def foo(x):
....
.... if x is None:
или
def foo(x):
.... if x is None:
?Верно
Отступы в строках делать не нужно. Это нигде не упоминается (поправьте, если не прав), но никакой необходимости в отбивке пустой строки нет, как ни крути.
foo = []
(об этом и в PEP 8 говорится)Отступы в строках делать не нужно. Это нигде не упоминается (поправьте, если не прав), но никакой необходимости в отбивке пустой строки нет, как ни крути.
Вот что примечательно: Отбивку IDE обычно делает автоматом и, если позже применить к такому коду pypi.python.org/pypi/pep8, то валидатор на отбивку ругнётся, хотя в PEP 8, таки да, об этом нет ни слова.
value = (foo.bar()['first'][0]*baz.ham(1, 2)[5:9] # pythonic + verify(34, 20)*skip(500, 360))
не-а. «The preferred place to break around a binary operator is *after* the operator, not before it.» (© pep-0008)
print("{} is {}, {} and lives in {}.".format(person[0], person[1], person[2], person[3]))
Если по новому стилю определять позиционные параметры, необходимо в фигурных скобках указывать их позицию:
print("{0} is {1}, {2} and lives in {3}.".format(person[0], person[1], person[2], person[3]))
А иначе — ValueError: zero length field name in format
Ну по поводу "\" несколько спорно.
Часто это удобней, чем вставлять скобки (например, этих скобок там уже и так много).
В том же Django в исходниках видел много раз.
Часто это удобней, чем вставлять скобки (например, этих скобок там уже и так много).
В том же Django в исходниках видел много раз.
>> Не используйте «from foo import *»
Как раз сегодня столкнулся.
У меня есть 2 модуля: один с объектами-контейнерами, и второй с фабриками, где вызывается rest api, парсится xml и штампуются готовые объекты.
Во втором модуле используются ВСЕ объекты первого.
Что может случиться плохого, если я импортирую их как «from module1 import *»?
Запихивать всё в один модуль не очень круто: несколько дюжин тупых объектов, и файл легко разростется на тысячи строчек кода. Импортировать же явно всю эту безразмерную кучу объектов тоже не красиво. «Засорение» глобального пространства имен в этом конкретном случае не выглядит как источник проблем.
Как раз сегодня столкнулся.
У меня есть 2 модуля: один с объектами-контейнерами, и второй с фабриками, где вызывается rest api, парсится xml и штампуются готовые объекты.
Во втором модуле используются ВСЕ объекты первого.
Что может случиться плохого, если я импортирую их как «from module1 import *»?
Запихивать всё в один модуль не очень круто: несколько дюжин тупых объектов, и файл легко разростется на тысячи строчек кода. Импортировать же явно всю эту безразмерную кучу объектов тоже не красиво. «Засорение» глобального пространства имен в этом конкретном случае не выглядит как источник проблем.
а
на Windows как сработает? Я правда не в курсе…
«Общие исключения» — это к pythonic/unpythonic не относится. Это для всех ЯП верно в равной степени вроде бы.
«Функции являются объектами» — что то пример как то не в тему… Так же можно сказать что в C функции — объекты. Может кривой перевод?
Ну и отметить, что речь о Python3 не помешало бы.
>>> foo = "path1/path2/path3"
>>> baz = "somefile"
>>> os.path.join(foo, baz)
на Windows как сработает? Я правда не в курсе…
«Общие исключения» — это к pythonic/unpythonic не относится. Это для всех ЯП верно в равной степени вроде бы.
«Функции являются объектами» — что то пример как то не в тему… Так же можно сказать что в C функции — объекты. Может кривой перевод?
Ну и отметить, что речь о Python3 не помешало бы.
а
>>> foo = «path1/path2/path3»
>>> baz = «somefile»
>>> os.path.join(foo, baz)
на Windows как сработает? Я правда не в курсе…
отлично работает…
«Функции являются объектами» — что то пример как то не в тему… Так же можно сказать что в C функции — объекты. Может кривой перевод?
Ничего кривого в переводе нет, сказано именно то, что хотел и сказал автор. В C функции — объекты? Простите, но вы несете какой-то бред! В C можно делать так?:
def some_func():
return 42
some_func.some_property = 42
some_func.some_method = some_func
print(some_func.some_property)
print(some_func.some_method() == some_func())
Т.е. пример с os.path.join() выведет не
Насчет «функции есть объекты» — я не ставил этот факт под сомнение (и не утверждал что в C функции это объекты тоже), а именно указал что пример не совсем убедительный. Передавать функцию в качестве аргумента другой функции можно во многих языках, в том числе в НЕ объектно-ориентированных), даже в С можно (по ссылке), не говоря уж о функциональных ЯП. И я не воспринимаю пример из статьи как доказательство того, что функции — объекты.
Привели бы в статье пример, который привели сейчас — ни слова не возразил бы.
Ишь, налетели))
path1/path2/path3\somefile
а самый что ни на есть path1\path2\path3\somefile
? Если так, то здорово, я не задавался этим вопросом раньше (НЕ использовать os.path.join НЕ призываю, просто уточнил).Насчет «функции есть объекты» — я не ставил этот факт под сомнение (и не утверждал что в C функции это объекты тоже), а именно указал что пример не совсем убедительный. Передавать функцию в качестве аргумента другой функции можно во многих языках, в том числе в НЕ объектно-ориентированных), даже в С можно (по ссылке), не говоря уж о функциональных ЯП. И я не воспринимаю пример из статьи как доказательство того, что функции — объекты.
Привели бы в статье пример, который привели сейчас — ни слова не возразил бы.
Ишь, налетели))
Логика работы os.path.join() аналогичка «cd ..».
os.path.join("/a/b/", «c») -> "/a/b/c"
os.path.join("/a/b/", "/c") -> "/c"
os.path.join("/a/b/", «c») -> "/a/b/c"
os.path.join("/a/b/", "/c") -> "/c"
Я имею в виду — развернет ли оно POSIX слеши "/" в виндовые бекслеши "\", если аргументы уже содержат в себе слеши или нет?
т.е. корректна ли запись
в Windows, или нужно писать что то в стиле
Например если в линуксе задать путь в виндовом стиле (с бекслешами)
то выведет чушь
Я бы сам попробовал, просто не на чем.
т.е. корректна ли запись
os.path.join("a/b/", "c")
в Windows, или нужно писать что то в стиле
os.path.join(*"a/b/".split("/"), "c")
Например если в линуксе задать путь в виндовом стиле (с бекслешами)
os.path.join(r"c:\a\b\c", "d")
то выведет чушь
'c:a\\b\\c/d'
Я бы сам попробовал, просто не на чем.
здесь терминологическая путаница — понятие first-class object (aka значение) и object в ООП (который содержит свойства и методы) — это две разные штуки.
функции в С не являются first-class object — ими являются указатели. а функции в python и то и другое. ;)
функции в С не являются first-class object — ими являются указатели. а функции в python и то и другое. ;)
В Си (точнее, в C++, т.к. в Си вообще нет объектов) функции не являются объектами.
И даже не являются переменными. Есть только типизированные указатели на функцию, для которых есть операция вызова ().
И даже не являются переменными. Есть только типизированные указатели на функцию, для которых есть операция вызова ().
Чуть выше пояснил. habrahabr.ru/blogs/python/114731/#comment_3706010
>Не используйте «from foo import *»
Все зависит от места применения, если это файл с правилами роутинга (например urls в django) то как раз хорошая идея написать from foo.views import *
Вот тут:
Тоже не корректность, ибо данный случай конечно правилен, но если вы хотите изменять элементы массива достаточно большим алгоритмом (чтоб без lambda), то придется-таки делать while.
Все зависит от места применения, если это файл с правилами роутинга (например urls в django) то как раз хорошая идея написать from foo.views import *
Вот тут:
>>> counter = 0 # unpythonic
>>> while counter < len(somecontainer):
... callable_consuming_container_elements(somecontainer[counter])
... counter += 1
...
...
>>> for item in somecontainer: # pythonic
... callable_consuming_container_elements(item)
Тоже не корректность, ибо данный случай конечно правилен, но если вы хотите изменять элементы массива достаточно большим алгоритмом (чтоб без lambda), то придется-таки делать while.
Хотя многое из описанного уже знал, но этот топик безусловно идет в избранное.
Читаю dive into python — там есть большая часть написанного. На редкость удачное руководство.
Классы не предназначены для группировки функциональности
Не понял как это понимать. В классе не должно быть статических методов или не должно быть только их, или ещё что?
И ещё вопрос по модулям — видел разные варианты: от весь код модуля в init до «один файл — один класс», как и различные комбинации (что-то в инит, где-то несколько классов в файле, где-то один). Какой стиль pythonic?
А вообще неплохо бы автокорректор какой-то чтобы был, расставлял что pythonic, а что нет. Я вот в своём коде на python практически не вижу отличий от php, а исходя из «уходом от принципа «существует много способов сделать это»» делаю формальный вывод, что код pythonic (раз код работает, значит я нашёл единственный способ сделать это :) ), хотя интуитивно понимаю, что нет, способ не единственный и вряд ли оптимальный по любому критерию, кроме легкости чтения php-шником, изучающим python :(
Под «Классы не предназначены для группировки функциональности» понимается следующее. Очень часто программисты чистых ООП языков по привычки пишут код полностью классами. Хотя очень часто в этом нет необходимости. Например в Java вся математика собрана в классе Math, т.к. по другому реализовать язык не позволяет. В python же не нужно делать подобные классы, когда можно просто реализовать набор функций в модуле.
По поводу ухода от «существует много способов сделать это». Это больше касается разработки языка, к этому стремятся разработчики Python. К этому стоит стремится и когда пишешь собственную функциональность.
По поводу ухода от «существует много способов сделать это». Это больше касается разработки языка, к этому стремятся разработчики Python. К этому стоит стремится и когда пишешь собственную функциональность.
Грубо говоря, модуль используется там, где привычно использовать глобальные классы, а классы там, где вложенные?
Привычно оставляет единственный способ «сделать это» (например изменить состояние объекта) полная инкапсуляция данных и разграничение уровней доступа к методам на public (интерфейсы), protected, private и т. п., то есть нельзя извне обратиться к свойству объекта, кроме как через публичные методы объекта, предусмотренные разработчиком. В python же, с его полной интроспекцией, это практически невозможно, как я понял? Или я вообще не понял о чём фраза «К этому стоит стремится и когда пишешь собственную функциональность»?
Привычно оставляет единственный способ «сделать это» (например изменить состояние объекта) полная инкапсуляция данных и разграничение уровней доступа к методам на public (интерфейсы), protected, private и т. п., то есть нельзя извне обратиться к свойству объекта, кроме как через публичные методы объекта, предусмотренные разработчиком. В python же, с его полной интроспекцией, это практически невозможно, как я понял? Или я вообще не понял о чём фраза «К этому стоит стремится и когда пишешь собственную функциональность»?
>Классы не предназначены для группировки функциональности
В том смысле, что если у вас есть набор каких-то функций, которые не работают над общими (инкапсулированными?) данными, то их лучше оформить не как класс со статическими методами а как модуль с набором простых функций. Пример:
В то же время если нужно работать с общими данными, например формирование запроса в CURL или работа с картинкой, то нужно это оформлять в виде класса, чтоб не передавать обрабатываемые данные первым аргументом (как делают в CURL или в GD в PHP)
Насчет того как код модуля распределять по файлам, я рекомендаций, к сожалению, не встречал. Тоже интересно. Наверное если один класс не имеет смысла без другого, то лучше их в одном файле оставить. А если классы отчуждаемы, то в разных. Но это моя догадка только.
Корректоры для Python есть, Pylint например, но я с ним не работал, не знаю что он проверяет а что нет. Вообще научиться писать pythonic код не очень сложно как мне кажется. Пара статей вроде этой и вроде ясно.
В том смысле, что если у вас есть набор каких-то функций, которые не работают над общими (инкапсулированными?) данными, то их лучше оформить не как класс со статическими методами а как модуль с набором простых функций. Пример:
#UNPYTHONIC
# math.py
class trig:
@staticmethod
sin(self, val):
pass
@staticmethod
cos(self, val):
pass
@staticmethod
tan(self, val):
pass
#PYTHONIC
# math/trig.py
sin(val):
pass
cos(val):
pass
tan(self, val):
pass
В то же время если нужно работать с общими данными, например формирование запроса в CURL или работа с картинкой, то нужно это оформлять в виде класса, чтоб не передавать обрабатываемые данные первым аргументом (как делают в CURL или в GD в PHP)
Насчет того как код модуля распределять по файлам, я рекомендаций, к сожалению, не встречал. Тоже интересно. Наверное если один класс не имеет смысла без другого, то лучше их в одном файле оставить. А если классы отчуждаемы, то в разных. Но это моя догадка только.
Корректоры для Python есть, Pylint например, но я с ним не работал, не знаю что он проверяет а что нет. Вообще научиться писать pythonic код не очень сложно как мне кажется. Пара статей вроде этой и вроде ясно.
Самое распространенное забыли: Использовать enumerate
По-поводу использования from foo import * — это вполне допустимо, если вы объявляете
Тогда область видимости не засоряется.
__all__ = ["echo", "surround", "reverse"] # список используемых штук из модуля
Тогда область видимости не засоряется.
А это чего за конструкция? Какой тип возвращает?
{ line.strip() for line in a_file }
{ line.strip() for line in a_file }
set docs.python.org/library/stdtypes.html#set-types-set-frozenset. Типа неупорядоченный список уникальных значений
Ну и генератор сета работает только в Python3 вроде. В 2.x можно делать так
Ну и генератор сета работает только в Python3 вроде. В 2.x можно делать так
set([line.strip() for line in a_file])
это сет. Такую конструкцию в третьей ветке ввели
«Используйте стандартную библиотеку» это надо вырезать на камне и поставить в центре каждого города. В ней действительно очень много всего, а народ продолжает писать свои велосипедики… Например сам долго писал какие-то свои парсеры, вместо строки import csv :)
«Списки предназначены для хранения однотипных данных.»
чего это вдруг?
*args
чего это вдруг?
*args
Это семантически верно. Обычно в списках хранят однотипные данные, которые последовательно (и однотипно) кто-то обрабатывает. А для разнотипных значений, которые должны обрабатываться вместе, служат кортежи (typles). Например тот же *arg — кортеж.
В питоне просто не стали делать это правило строгим, чтобы не путать людей. Но во многих языках, в том же Хаскеле например, можно только так.
В питоне просто не стали делать это правило строгим, чтобы не путать людей. Но во многих языках, в том же Хаскеле например, можно только так.
Хорошая статья для начинающих.
А есть еще вопросы «неоднозначной питоничности»
Например использование функциональных фич вроде генераторов и лямбд.
Как только новичок удосуживается таки взять и разобраться с ними, это как правило начинает создавать больше проблем, чем решать, так как итоговый код получается плохо читаемым, плохо отлаживаемым и сложным для рефакторинга.
В итоге, если вы можете упихать функцию в 10 строк, хотя на С или Java она бы занимала 100, то лучше этого не делать и обойтись 30-ю.
А есть еще вопросы «неоднозначной питоничности»
Например использование функциональных фич вроде генераторов и лямбд.
Как только новичок удосуживается таки взять и разобраться с ними, это как правило начинает создавать больше проблем, чем решать, так как итоговый код получается плохо читаемым, плохо отлаживаемым и сложным для рефакторинга.
В итоге, если вы можете упихать функцию в 10 строк, хотя на С или Java она бы занимала 100, то лучше этого не делать и обойтись 30-ю.
Sign up to leave a comment.
Pythonic