х или у: приемлемая идиома или запутывание? - PullRequest
4 голосов
/ 31 августа 2010

Я должен извлечь значения из переменной, которая может быть None, с учетом некоторых значений по умолчанию. Я впервые написал этот код:

if self.maxTiles is None:
    maxX, maxY = 2, 2
else:
    maxX, maxY = self.maxTiles

Тогда я понял, что могу сократить его до:

maxX, maxY = self.maxTiles if self.maxTiles is not None else (2, 2)

Но потом я понял, что это может быть самым кратким и легко читаемым:

maxX, maxY = self.maxTiles or (2, 2)

Последний приемлем или слишком хакерский?

Ответы [ 6 ]

6 голосов
/ 31 августа 2010

В частности,

self.maxTiles if self.maxTiles is not None else (2, 2)

Я обнаружил, что "двойные отрицания" общего вида if not A: B else: C (как в выражениях, так и в выражениях) могут быть весьма запутанными / вводящими в заблуждение;это не буквально if not .. else, но перемещение not не устраняет «двойной негатив».

Итак, в общем, я просто переписываю такие конструкции в if A: C else: B.В этом конкретном случае, если бы я выбрал форму троичного оператора, я бы закодировал ее как

(2, 2) if self.maxTiles is None else self.maxTiles

По более общему вопросу: a = b or c хорошо тогда и только тогда, когда вы действительно хотите использовать c для любое ложное значение b - это не хорошо, чтобы иметь дело конкретно с b, являющимся None.IOW, b or c - лучший способ выразить

b if b else c

, но это , а не способ выразить подобное выражение, где основной тест вместо этого, b is None.Теоретически, если вы «знаете», что единственное возможное ложное значение для b - это None, они семантически эквивалентны, но это сильное ограничение «только возможное ложное значение» не будет очевидным для читателей / сопровождающих вашего кода- и если вам нужно добавить комментарий, объясняющий это, любые преимущества краткости, которые or может заявить, аннулируются ... лучше, когда это возможно, "сказать это в коде", а не делать код неясным и нужнымкомментарии, чтобы уточнить, что именно он делает и когда (действительно полезные комментарии - это скорее те, которые объясняют, а не что и когда [[сам код должен показывать это! -)]], а скорее почему когда не очевидно - какова цель приложения, обслуживаемая этим конкретным кусочком функциональности кода).

4 голосов
/ 31 августа 2010

Если вы делаете это в начале функции , я бы использовал более длинную форму, поскольку она более идиоматична и мгновенно распознаваема. Да, это больше строк, но вы едва сохраняете любые символы, а короткие строки, которые вписываются в 79 строк символов = хорошо.

Плюс, если вам когда-нибудь придется настроить логику или добавить больше шагов, вы, вероятно, в любом случае вернетесь к длинной форме.

4 голосов
/ 31 августа 2010

Наряду с ответом gddc (о проблемах предположения, что maxTiles является кортежем), я бы, вероятно, сделал второй вариант, но для ясности добавил бы скобки:

maxX, maxY = (self.maxTiles) if (self.maxTiles is not None) else (2, 2)
3 голосов
/ 31 августа 2010

Я избегаю синтаксиса y if x else z, когда могу.По сути, это уродливый, неинтуитивный синтаксис и одна из самых больших ошибок в дизайне Python.Это выражение не в порядке: x вычисляется перед y.Это не интуитивно понятно;это естественно читается как «если х то у, иначе г».Синтаксис Си дает нам установленный десятилетиями, универсально понятный порядок для этого: x? y:z.В Python это совершенно неправильно.

Тем не менее, троичный синтаксис в любом случае является неправильным механизмом для предоставления значения по умолчанию.В self.maxTiles if self.maxTiles is not None else (2, 2) обратите внимание на избыточность: вы должны указать self.maxTiles дважды.Это повторяется, поэтому для чтения кода требуется больше работы.Я должен прочитать его дважды, чтобы убедиться, что он не говорит, например: self.minTiles if self.maxTiles is not None else (2, 2).

self.maxTiles or (0,2) позволяет избежать этих проблем;это совершенно ясно с первого взгляда.

Одно предостережение: если self.maxTiles равно () или 0 или другому ложному значению, результат будет другим.Это, вероятно, приемлемо в зависимости от того, что вы делаете, но имейте это в виду.Это проблема при предоставлении значения по умолчанию для логического или целого числа, и вам действительно нужен тест is None.Я предпочитаю простые условные выражения, но иногда прибегаю к троичному выражению.

Edit;более ясный способ написания условной версии:

if self.maxTiles is None:
    maxX, maxY = 2, 2
else:
    maxX, maxY = self.maxTiles
1 голос
/ 31 августа 2010

Ваш код вполне приемлемая идиома. На самом деле я нахожу это более читабельным, чем первые два.

Мое единственное соображение - вы делаете две вещи в одной строке, чтобы задать значение по умолчанию и распаковать их в x, y. Возможно, будет более понятно, если вы разделите их на две части.

maxTiles = self.maxTiles or (2, 2)
maxX, maxY = maxTiles

Это также отвлекает от критики g.d.d.c, хотя на самом деле она не является серьезной.

0 голосов
/ 31 августа 2010

Мне не нравится использовать or и and в качестве замены для троичного оператора в Python.Я сталкивался с такими проблемами, как значение 0, которое слишком часто рассматривалось как "ложное", когда я только собирался проверить на None.Я считаю, что гораздо лучше быть явным, даже если оно более многословно, поэтому ваш второй пример лучше всего:

maxX, maxY = self.maxTiles if self.maxTiles is not None else (2, 2)
...