Який стиль використовувати для невикористаних параметрів повернення у виклику функції Python


30

Чи є якийсь рекомендований / загальноприйнятий стиль кодування для обробки ситуацій, коли функція повертає кордону значень, але після цього використовується лише одне з цих значень (зверніть увагу, що це здебільшого призначено для функцій бібліотеки, які я не можу змінити - написання обгортки навколо дзвінок, мабуть, трохи надмірний…)? Замість того, щоб робити

a, b, c = foo()

а потім просто не використовуючи, bі cякий із наведених варіантів слід віддати перевагу (чи є інший?):

Варіант 1 (підкреслення)

a, _, _ = foo()

(що дуже зрозуміло і просто, але може зіткнутися з _ = gettext.gettextбагатьма програмами, які використовують переклад)

Варіант 2 (назва манекена)

a, unused, unused = foo()

(Я не дуже привабливий, я думаю, те саме стосується і інших імен, як dummy)

Варіант 3 (індекс)

a = foo()[0]

(для мене це ()[0]виглядає непітонічно ...)


Це на відміну від моєї колишньої відповіді, що відбувається з варіантом 3, коли тепер ви хочете посилатись на 2/3 повернених значень? Я видалив свою відповідь, бо зрозумів, що не знаю достатньо про Python, щоб виправдати це.
Крейдж

@Craige: Я не бачив вашої відповіді, перш ніж ви її видалили ... Ви питаєте, чи a, b = foo()[0:2]буде працювати? Якщо так: так, це так :)
user49643

Саме це я і запитував. Якщо це працює (як ви сказали, що це робиться), я б застосував варіант 3. Я повторно встановлюю свою відповідь з огляду на цю інформацію.
Крейдж

3
До речі, в ці дні ви можете використовувати досить гарний синтаксис для "розширеного" розпакування : a, *_ = foo()викине всі значення, окрім першого.
Бенджамін Ходжсон

Відповіді:


17

Використання підкреслення для невикористаних змінних безумовно прийнятно. Будьте попереджені, хоча в деяких кодових базах це не варіант, оскільки цей ідентифікатор зарезервований як скорочення gettext. Це найчастіше заперечення проти цього стилю (хоча, наскільки я можу судити, це питання не для більшості. Я все-таки рекомендую його і завжди використовую сам.

Імена люблять dummyабо, unusedяк правило, дратують мене особисто, і я не бачу їх страшенно часто (в Python, тобто - я знаю базу даних коду Delphi, яка використовує dummyвільно, і вона також просочилася в сценарії, пов'язані з відповідною програмою). Я б порадив вам проти цього.

Просто вилучення одного елемента з повернутого кортежу теж добре. Це також заощаджує певні клопоти з отриманням правильної кількості невикористаних значень. Зауважте, що це два можливі мінуси:

  • Він не підірветься, якщо кількість значень відрізняється від очікуваного. Це може бути корисно для виявлення змішань та помилок.
  • Він працює лише тоді, коли значення, що повертається, є послідовністю (це переважно кортежі та списки, але залишимось загальними). Назад, я знаю один клас у своєму коді (2D-вектор), який є ітерабельним і дає постійну кількість значень (і, таким чином, може використовуватися при розпакуванні завдань), але не підлягає індексації.

Я ж на самому справі згадати GetText в моєму питанні :) У всякому разі, я прийняв ваш відповідь - це , здається , що немає чіткого єдиного загальноприйнятого стилю , але ваша відповідь підняв деякі цікаві моменти.
user49643

Щоб уникнути проблем з gettext (або щоб уникнути подібних проблем у перекладачі), ви можете використовувати подвійні підкреслення (ака дандери) замість одиничного.
Зім

21

Пілінт звик мене робити так:

widget, _parent, _children = f()

Тобто невикористані результати мають описову назву з префіксом _. Pylint розглядає місцевих жителів з префіксом _ як невикористані, а глобалі або атрибути з префіксом _ як приватні.


3

Якщо у вашому проекті ви робите це лише один раз або дуже рідко запускаєте певну функцію, я б використовував Варіант 1, якщо ви знаєте, що gettextце не проблема в цьому модулі, інакше варіант 3.

З іншого боку, якщо ви робили це багато - і особливо, якщо кожен раз ви хочете отримати різний підмножина повернених значень (зробити обгортку, щоб просто повернути ті, про кого ви небайдужі), може бути корисно написати обгортку що ставить результати в названий кортеж або екземпляр якогось іншого описового класу, що дозволить вам:

bar = foo()

А потім працювати з bar.a, bar.bі bar.c.


2

Як говорили інші, підкреслення ( _) є стандартом. Але якщо підкреслення використовується для перекладів, я вважаю, що подвійна підкреслення - найкраща альтернатива.

var, __, value = "VAR=value".partition('=')

Краще за ці:

var, unused, value = "VAR=value".partition('=')

var, unused_del, value = "VAR=value".partition('=')

var, _del, value = "VAR=value".partition('=')


1

Я не-Python-програміст, але для мене третій варіант має найбільш сенс.

У варіанті 3 вам абсолютно зрозуміло, з якими цінностями вам цікаво мати справу. У варіантах 1 і 2 ви присвоюєте значення назад змінним, і таким чином вони можуть бути використані. Ви, можливо, називали їх незрозуміло, але неправильне називання насправді не є рішенням будь-якої проблеми.

Крім чіткості, чому ви хочете призначити невикористані значення слоту в пам'яті (як у варіантах 1 і 2)? Це було б поганим рішенням щодо управління пам'яттю.


Якщо ви завжди ставите його на одну і ту ж змінну, чи не буде проблема пам'яті лише розміром однієї змінної в даний момент часу? Я не думаю, що це має бути проблемою.
Майкл МакКуаде

-2

Ось загальне правило: якщо використовується лише 1 повернених значень, чому б просто не повернути це значення? У випадку, якщо прапор викликається з декількох місць, збережіть прапор для того ж і поверніть значення відповідно до цього прапора.

Редагувати:

У випадку, якщо я опинився у вашій ситуації, і я не записав цю функцію, я б, можливо, пішов на варіант 2. Я б зберігав імена манекенів там, щоб параметри можна було використовувати в разі виникнення необхідності. Нарізання списку буде трохи накладне. Можливо, ви можете зекономити кілька байт, щоб отримати небажані дані.


-1 Я здогадуюсь, що він не визначив функцію, і тому не може змінити те, що вона повертає. Я думаю, що він посилається на те, коли функція повертає 3 значення, але йому важливо лише 1 у своєму поточному випадку використання.
Крейдж

@Craige: Так, я мав на увазі функції, які я не міг змінити - я додав примітку до свого запитання, роз'яснюючи це.
user49643

Ви впевнені в накладних витратах? Я спробував дуже простий тест на ipython: %timeit a, _, _ = foo()порівняно, %timeit a = foo()[0]що призвів до 123ns проти 109ns, тобто нарізка здається насправді швидшою, ніж розпакування значення. Або ви мали на увазі якусь конкретну ситуацію?
user49643

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