питонский способ переписать назначение в операторе if - PullRequest
5 голосов
/ 19 сентября 2010

Есть ли предпочтительный питонский способ сделать это, что я бы сделал в C ++:


for s in str:
    if r = regex.match(s):
        print r.groups()

Мне действительно нравится этот синтаксис, потому что он намного чище, чем временные переменные везде.Единственный не слишком сложный способ - это


for s in str:
    r = regex.match(s)
    if r:
        print r.groups()

Я полагаю, что жалуюсь на довольно педантичный вопрос.Я просто скучаю по прежнему синтаксису.

Ответы [ 7 ]

10 голосов
/ 19 сентября 2010

Как насчет

for r in [regex.match(s) for s in str]:
    if r:
        print r.groups()

или чуть более функционально

for r in filter(None, map(regex.match, str)):
    print r.groups()
2 голосов
/ 19 сентября 2010

Возможно, это немного глупо, но использование атрибутов объекта функции для хранения последнего результата позволяет вам сделать что-то вроде этого:

def fn(regex, s):
    fn.match = regex.match(s) # save result
    return fn.match

for s in strings:
    if fn(regex, s):
        print fn.match.groups()

Или более обобщенно:

def cache(value):
    cache.value = value
    return value

for s in strings:
    if cache(regex.match(s)):
        print cache.value.groups()

Обратите внимание, что хотя сохраненное «значение» может быть набором из нескольких вещей, этот подход ограничен удержанием только одного такого за раз, поэтому может потребоваться более одной функции для обработки ситуаций, когда необходимо несколько значений сохраняться одновременно, например, во вложенных вызовах функций, циклах или других потоках. Таким образом, в соответствии с принципом DRY , вместо записи каждого, может помочь заводская функция:

def Cache():
    def cache(value):
        cache.value = value
        return value
    return cache

cache1 = Cache()
for s in strings:
    if cache1(regex.match(s)):
        # use another at same time
        cache2 = Cache()
        if cache2(somethingelse) != cache1.value:
            process(cache2.value)
        print cache1.value.groups()
          ...
1 голос
/ 19 сентября 2010

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

Так что извлеките код, который просто генерирует интересующие вас предметы:

def matching(strings, regex):
    for s in strings:
        r = regex.match(s)
        if r: yield r

и затем, когда вы хотите использоватьэто, сам цикл так же прост, как они получают:

for r in matching(strings, regex):
    print r.groups()
1 голос
/ 19 сентября 2010

Нет питонского способа сделать что-то, что не питонно.Это так по какой-то причине, потому что 1, разрешение операторов в условной части оператора if сделает грамматику довольно уродливой, например, если вы разрешите операторы присваивания в условиях if, почему бы не разрешить операторы if?как бы ты это написал?В языках, подобных C, такой проблемы нет, потому что в них нет операторов присваивания.Они обходятся только с помощью выражений присваивания и выражений выражений.

Вторая причина в том, что

if foo = bar:
    pass

выглядит очень похоже на

if foo == bar:
    pass

, даже если выдостаточно умны, чтобы набрать правильный, и даже если большинство членов вашей команды достаточно проницательны, чтобы заметить это, вы уверены, что тот, на кого вы смотрите сейчас, это именно то, что должно быть там?для нового разработчика вполне разумно видеть это и просто исправлять это (так или иначе), и теперь это определенно неправильно.

1 голос
/ 19 сентября 2010

Это может быть слишком упрощенный ответ, но вы бы могли подумать:

for s in str:
    if regex.match(s):
        print regex.match(s).groups()
1 голос
/ 19 сентября 2010

Есть рецепт для создания выражения присваивания, но он очень хакерский. Ваш первый вариант не компилируется, поэтому ваш второй вариант - путь.

## {{{ http://code.activestate.com/recipes/202234/ (r2)
import sys
def set(**kw):
    assert len(kw)==1

    a = sys._getframe(1)
    a.f_locals.update(kw)
    return kw.values()[0]

#
# sample
#

A=range(10)

while set(x=A.pop()):
    print x
## end of http://code.activestate.com/recipes/202234/ }}}

Как вы можете видеть, производственный код не должен касаться этого хака десятифутовой палкой в ​​двойном мешке.

0 голосов
/ 20 сентября 2010

Еще один ответ - использовать рецепт «Назначить и проверить», чтобы разрешить назначение и тестирование в одном утверждении, опубликованном в 1'й редакции O'Reilly Media за июль 2002 г. Python Cookbook , а также онлайн в Activestate. Это объектно-ориентированный, суть которого такова:

# from http://code.activestate.com/recipes/66061
class DataHolder:
    def __init__(self, value=None):
        self.value = value
    def set(self, value):
        self.value = value
        return value
    def get(self):
        return self.value

Это можно при желании слегка изменить, добавив показанный ниже пользовательский метод __call__(), чтобы обеспечить альтернативный способ извлечения значений экземпляров, который, хотя и менее явный, выглядит совершенно логичным для объекта DataHolder, чтобы думаю, когда позвонят.

    def __call__(self):
        return self.value

Разрешение переписать ваш пример:

r = DataHolder()
for s in strings:
    if r.set(regex.match(s))
        print r.get().groups()
# or
        print r().groups()

Как также отмечено в оригинальном рецепте, если вы часто его используете, добавление класса и / или его экземпляра в модуль __builtin__, чтобы сделать его доступным в глобальном масштабе, очень заманчиво, несмотря на возможные недостатки:

import __builtin__
__builtin__.DataHolder = DataHolder
__builtin__.data = DataHolder()

Как я уже упоминал в своем другом ответе на этот вопрос, следует отметить, что этот подход ограничен удержанием только одного результата / значения за раз, поэтому для обработки ситуаций, в которых требуется несколько значений, требуется более одного экземпляра. сохраняются одновременно, например, во вложенных вызовах функций, циклах или других потоках. Это не значит, что вы должны использовать его или другой ответ, просто потребуется больше усилий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...