Конкретні приклади максиму "єдиний спосіб зробити це" Python [закрито]


34

Я вивчаю Python і мене заінтригує наступний пункт у PEP 20 The Zen of Python :

Повинно бути один - і бажано лише один - очевидний спосіб це зробити. Хоча спочатку це може бути не очевидним, якщо ви не голландці.

Чи може хтось запропонувати конкретні приклади цієї максими? Мене особливо цікавить контраст з іншими мовами, такими як Рубі. Частина філософії дизайну Ruby (походить з Perl, я думаю?) Полягає в тому, що кілька способів зробити це - хороша річ. Хто-небудь може запропонувати кілька прикладів, що показують плюси та мінуси кожного підходу. Зауважте, я не після відповіді, яка краще (яка, мабуть, занадто суб’єктивна, щоб колись відповісти), а скоріше неупередженого порівняння двох стилів.

Відповіді:


47

Порівняно з такими мовами, як Perl, Python має обмежену кількість керуючих конструкцій:

  • тільки ifі ні unless,
  • лише forте, що воно повторюється над послідовностями і не має foreachстилю C або for,
  • лише whileте, що перевіряє стан кожного циклу, і ні do-while,
  • тільки if-elifі ні switch,
  • є лише одна конструкція коментарів #, і для кожного рядка ви можете сказати, коментується він чи ні, не дивлячись на попередні рядки.

Крім того, існує майже один спосіб відступити джерело; більшість випадків творчого відступу синтаксично виключаються.

Це полегшує розбір джерела Python для людини.

Існують спроби бути мінімальним, але повним у вбудованих типах та стандартній бібліотеці.

  • для змінного списку ви використовуєте єдиний вбудований listтип; це O (1) для більшості операцій, і вам ніколи не доведеться вибрати правильну реалізацію,
  • для незмінних списків, однаково, ви просто використовуєте tupleтип,
  • для карт ви використовуєте єдину вбудовану, dictяка в більшості випадків проклято ефективна, не потрібно розмірковувати, яку саме програму використовувати.

Python 3 поширює це на цілі числа: незалежно від того, наскільки велике ваше ціле число, ви використовуєте один і той же тип і ніколи не піклуєтесь про примус.

Пітон намагається уникати синтаксичного цукру. Але іноді він додає синтаксичний цукор просто для того, щоб зробити очевидним спосіб очевидним. Ви можете писати if foo is not Noneзамість того, if not (foo is None)що "не є" має спеціальний текст. Все ще foo is not Noneчитається легко, його не можна неправильно трактувати, і вам не потрібно думати, ви просто пишете очевидну річ.

Звичайно, більшість складних речей у Python можна зробити декількома способами. Ви можете додавати методи до класів за допомогою декларації чи простого призначення слотів, ви можете передавати аргументи функціям у багатьох творчих способах тощо. Це просто тому, що внутрішні мови мови в основному піддаються впливу.

Ключовим є те, що завжди є один спосіб, який повинен бути найкращим, все для обкладинки. Якщо існують інші способи, вони не додаються як рівнозначні альтернативи (як ifі unless), а лише піддаються внутрішній роботі. Повільно, але стабільно такі альтернативи застарівають (не усуваються!) Шляхом вдосконалення відомого найкращого механізму.

Декоратори завершують дзвінки функції AOP. До 2.6 вам довелося використовувати __metaclass__магічний член, щоб оголосити метаклас класу; тепер ви можете використовувати для цього той же синтаксис декоратора. До 3.0 у вас було два види рядків, орієнтовані на байт і Unicode, які ви могли ненароком змішати. Тепер у вас є єдиний Unicode strі єдиний бінарний прозорий bytes, який ви не можете помилково змішати.


3
Як і замітка, не забувайте """коментарів (доктрингів). Вони охоплюють кілька ліній.
asthasr

8
Літерали з потрійним котируванням - це лише рядки, такі ж, як і з цитатами з одним котируванням, але вони можуть охоплювати кілька рядків без уникнення кінців рядків. Буквальний рядок відразу після декларування вважається рядком doc, і це не коментар, він зазвичай доступний як __doc__атрибут. Але рядки - це область, де Python, безумовно, пропонує багато "правильних способів": використовувати одинарну, подвійну чи потрійну цитату, неявно приєднуватися до сусідніх літералів, використовувати rдля необроблених літералів тощо
9000

1
Я думаю, що коментар @ syrion стосувався "ви завжди можете вирішити, коментується рядок чи ні, просто подивившись на нього", що не відповідає дійсності "" "рядків.
blubb

2
"Це полегшує розбір джерела Python для людей." <- це суб'єктивно
Jiggy

Як змінилася декларація метакласу в 2.7? Не вдалося знайти шаблон декоратора в 2.7 документах для метакласів.
Нік Т

10

Ще пара прикладів:
len()функція замість методу, присутнього в кожній послідовності; якщо ви порівнюєте з Java у вас є .length,.size() , .getSize()і інші методи , щоб знайти число елементів в послідовності.

Іншим прикладом є той факт, що .join()це stringметод, а не метод, присутній у кожній послідовності. Вам не потрібно знати, чи параметр приєднання - це список, набір, розуміння чи все, що він буде працювати.


8

У C існує багато можливих способів збільшення значення змінної на одиницю:

i++     // Post-increment, returns the number before the increment
++i     // Pre-increment, returns the number after the increment
i += 1 

Кожне закінчується збільшенням значення i на 1, але кожен дещо інший.

У Python насправді існує лише один спосіб; просто додайте один.

i += 1

І хоча існує декілька синтаксично дійсних способів зробити це (наприклад i = i + 1), ви робите те саме з тими ж побічними ефектами.


1
Я не експерт, але, здається, цей приклад точно порушує ідею "єдиного способу зробити це". У нас є два способи це зробити, але який більш очевидний? На мій погляд, перший приклад є більш очевидним, тоді як другий - трохи більш лаконічним, але не менш читабельним чи очевидним для будь-якого програміста, який просунувся за межі самих основ. Дякую за вашу відповідь - це гарна їжа для роздумів.
Чарльз Ропер

@Peter (і @Charles): насправді i = i + 1це призначення, а не збільшення. Приріст у python - це i += 1. У мовах C-стилі , ви можете написати i++, ++iі i += 1.
Джош К

2
Не впевнені у вашому коментарі "багато плутанини", усі три ваші приклади C (ви пропустили i += 1, BTW) дають абсолютно однаковий результат. Єдиний раз, коли я бачу людей, що плутаються, це коли вони до- чи після нарощування змінної є частиною більшого виразу, і це, як правило, швидко виправляється, прочитавши відповідний розділ посилання на мову. Особисто я вибрав би те, що ви можете посилатися на п'ятий символ рядка обома str[4]або *(str+4), але, можливо, це було занадто просто ...
TMN

2
@TMN: деякі випадки, наприклад, max(i++, ++i)не вдається швидко виправити. У C є багато випадків поведінки "невизначених" та "залежних від впровадження", все це з поважної причини - але кожен може створити провал.
9000

@TMN: Не кажучи вже про 4 [str] (дійсний на C, може бути недійсним у C ++).
Ватін

6

Іншою можливістю можуть бути розуміння списку. У Python ви можете зробити це:

new_list = []
    for item in list_of_items:
       if item < 10:
           new_list.append(item)

Але "очевидний" спосіб (якщо ви голландський або ви більше знайомі з Python) робити це було б із розумінням списку:

new_list = [item for item in list_of_items if item < 10]

Це коротше, new_list створюється за один крок, він працює швидше, я вважаю, і він елегантний. З іншого боку, можна стверджувати, що він відчуває себе менш явним, але я думаю, що коли ти звикнеш до нього, це так само явно.


Для відступу та коду: додайте його до 4 пробілів, тоді він буде дотримуватися відступ.
Інка
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.