8

多くの異なるプロジェクトで、(適度に複雑で、おそらく評価にコストがかかる)式を評価し、それを使って何かを行う(たとえば、文字列のフォーマットに使用する)必要がある多くのコードを書いていることがわかりましたが、式がTrue/non-Noneの場合のみ。

たとえば、多くの場所で、私は次のようなことをすることになります。

result += '%s '%( <complexExpressionForGettingX> ) if <complexExpressionForGettingX> else ''

...これは基本的に、式の関数を返したいというより一般的な問題の特殊なケースですが、その式がTrueの場合に限ります。

f( e() ) if e() else somedefault

ただし、式を再入力する必要はありません(または、コストのかかる関数呼び出しの場合は、式を再評価します)。

明らかに、必要なロジックは、さまざまな長い方法で簡単に実現できます(たとえば、式を複数のステートメントに分割し、式を一時変数に割り当てることによって)が、それは少し厄介であり、これは非常に一般的な問題のように思われるため、 Pythonはかなりクールなので(特に機能的なものの場合)、それを行うための素晴らしい、エレガントで簡潔な方法があるかどうか疑問に思いました。

私の現在の最良のオプションは、それを処理するために短命のラムダを定義することです(複数のステートメントよりも優れていますが、少し読みにくいです):

(lambda e: '%s ' % e if e else '')( <complexExpressionForGettingX> )

または、次のような独自のユーティリティ関数を記述します。

def conditional(expr, formatStringIfTrue, default='')

...しかし、私はこれを多くの異なるコードベースで行っているので、組み込みのライブラリ関数またはそのようなものが存在する場合はいくつかの巧妙なPython構文を使用したいと思います

4

5 に答える 5

8

私は間違いなくワンライナーが好きです。しかし、時にはそれらは間違った解決策です。

プロのソフトウェア開発では、チームの人数が 2 人を超える場合、新しいコードを書くよりも、他の誰かが書いたコードを理解することに多くの時間を費やしています。ここに示されているワンライナーは間違いなく紛らわしいので、2行だけにしてください(投稿で複数のステートメントについて言及しましたが):

X = <complexExpressionForGettingX>
result += '%s '% X  if X else ''

これは明確で簡潔で、誰もがここで何が起こっているかをすぐに理解できます。

于 2013-01-15T12:27:26.503 に答える
4

Pythonには式のスコープがありません(Haskell'let'に相当するPythonはありますか)。おそらく、構文の乱用と混乱が利点を上回っているためです。

どうしても式スコープを使用する必要がある場合、最悪のオプションはジェネレーターの理解を乱用することです。

result += next('%s '%(e) if e else '' for e in (<complexExpressionForGettingX>,))
于 2013-01-15T12:13:18.787 に答える
3

条件付き書式設定関数を一度定義すると、繰り返し使用できます。

def cond_format(expr, form, alt):
    if expr:
        return form % expr
    else:
        return alt

使用法:

result += cond_format(<costly_expression>, '%s ', '')
于 2013-01-15T13:30:20.280 に答える
1

応答を聞いた後(みんなありがとう!)、新しいスコープを導入する唯一の方法であるため、新しい関数(またはラムダ関数)を定義せずにPythonで必要なことを達成する方法はないと確信しています。

わかりやすくするために、これは(ラムダではなく)再利用可能な関数として実装する必要があると判断したので、他の人の利益のために、最終的に思いついた関数を共有したいと思いました-複数の追加のフォーマット文字列に対応するのに十分な柔軟性があります引数(フォーマットを行うかどうかを決定するために使用されるメイン引数に加えて); また、正しいことを示し、使用法を説明するためのpythondocが付属しています(** kwargsがどのように機能するかわからない場合は、無視してください。これは実装の詳細であり、オプションのdefaultValue=kwargを実装するための唯一の方法でした。フォーマット文字列引数の変数リスト)。

def condFormat(formatIfTrue, expr, *otherFormatArgs, **kwargs):
""" Helper for creating returning the result of string.format() on a 
specified expression if the expressions's bool(expr) is True 
(i.e. it's not None, an empty list  or an empty string or the number zero), 
or return a default string (typically '') if not. 

For more complicated cases where the operation on expr is more complicated 
than a format string, or where a different condition is required, use:
(lambda e=myexpr: '' if not e else '%s ' % e)

formatIfTrue -- a format string suitable for use with string.format(), e.g. 
    "{}, {}" or "{1}, {0:d}". 
expr -- the expression to evaluate. May be of any type. 
defaultValue -- set this keyword arg to override

>>> 'x' + condFormat(', {}.', 'foobar')
'x, foobar.'

>>> 'x' + condFormat(', {}.', [])
'x'

>>> condFormat('{}; {}', 123, 456, defaultValue=None)
'123; 456'

>>> condFormat('{0:,d}; {2:d}; {1:d}', 12345, 678, 9, defaultValue=None)
'12,345; 9; 678'

>>> condFormat('{}; {}; {}', 0, 678, 9, defaultValue=None) == None
True

"""
defaultValue = kwargs.pop('defaultValue','')
assert not kwargs, 'unexpected kwargs: %s'%kwargs
if not bool(expr): return defaultValue

if otherFormatArgs:
    return formatIfTrue.format( *((expr,)+otherFormatArgs) )
else:
    return formatIfTrue.format(expr)
于 2013-01-23T14:17:15.217 に答える
0

おそらく、文字列を構築するためにこれを繰り返し実行する必要があります。filterよりグローバルなビューを使用すると、 (またはitertools.ifilter) が値のコレクションに対して必要な処理を行うことがわかる場合があります。

次のような結果になります。

' '.join(map(str, filter(None, <iterable of <complexExpressionForGettingX>>)))

Noneの最初の引数として使用すると、filter真の値を受け入れることを示します。単純な式を使用した具体的な例として:

>>> ' '.join(map(str, filter(None, range(-3, 3))))
'-3 -2 -1 1 2'

値の計算方法によっては、同等のリストまたはジェネレータ内包表記の方が読みやすい場合があります。

于 2013-01-15T14:18:02.157 に答える