web-dev-qa-db-ja.com

Python:このコードのif条件を回避しますか?

次のコード

a =func()
if a != None:
    b.append(a)

aはNoneに割り当てることができますが、ifステートメントを回避してコードを1行だけ使用する方法はありますか?

元の問題は次のとおりです

import xml.etree.ElementTree as etree

r = etree.parse(f).getroot()
b = etree.Element('register',{})

a = r.find('tag_name') # a may get None if did not find it
if a != None:
    b.append(a)

わかった、私はすべての答えを使ってこれを得た、個人的にはそれが最も複雑だと思うpythonこれまでに書いたことがある、笑

NS_MAP = {
    'spirit' : 'http://www.spiritconsortium.org/XMLSchema/SPIRIT/1.4',
    'app' : 'http://www.app.com/SPIRIT-app'
    }

mp=etree.Element('MemoryProperty', {'version':'alpha'})
mpt=etree.ElementTree(mp)


def copy_tags(tp, op, p, tn, ns='spirit'):
    c =  p.find('{%s}%s'%(NS_MAP[ns],tn))
    if c is not None:
        (op == '<-') and tp.append(c)
        return c    

for reg in regs:
    te = etree.Element('register',{})
    copy_tags(te,'<-',reg,'name')
    copy_tags(te,'<-',reg,'addressOffset')
    copy_tags(te,'<-',reg,'access')
    (lambda e, t: copy_tags(te,'<-',t,'usageConstraints',ns='app') if t is not None else None)(te, copy_tags(te,'|',reg,'vendorExtensions'))

    mp.append(te)

mpt.write('map_gen.xml')
27
Jerry Gao

Func()を事前に呼び出すことができ、テストステートメントと割り当てステートメントを1つのステートメントに結合する場合は、if-else式を使用してこれを行うことができます。

_b += [a] if a is not None else []
_

AがNoneでない場合、これは[a]をbに追加します-基本的にb.append(a)と同じ操作です

A is Noneの場合、[]がbに追加され、bは変更されません。

これは、bがリストであるか、少なくとも「+ =インプレース追加」をサポートしない限り機能しません。そうでない場合-おそらくそれがいくつかのカスタムオブジェクトである場合、これを行うことができるはずです:

_(b.append(a) if a is not None else None)
_

これは式であり、その副作用について評価された後、破棄されます。 aがNoneの場合、b.append(a)呼び出しは実行されません。どちらの場合でも、式の値はNoneですが、気にしないので無視されます。

Func()呼び出しをこれと組み合わせる場合は、funcを2回呼び出すことを回避するために、別のことを行う必要があります。 「+ =」構文を使用できる場合は、次のように実行できます。

_b += filter(None, [func()])
_

filter(None, <list>)は、すべての偽要素(含まれていないが0と[]も含む)が削除されたリストを返します。次に、このステートメントは[func()]または[]をbに追加します。

[編集済み]

最後に、最悪のシナリオの場合:func()を2回以上呼び出すことができない場合、andは使用できません_b += <list>_、andが必要です0、 ""、[]などを受け入れ、Noneandのみを除外するには、1行ですべてが必要です。ここでは、最も醜いコード行を示します。

_(lambda l, a: l.append(a) if a is not None else None)(b, func())
_

これは基本的に@ekhumoroのソリューションで、1行に圧縮されています。副作用のために、無名関数を定義して呼び出し、値を破棄し、関数を破棄します。

さて、これは1行ですが、元のコードよりも読みやすく、理解するのも容易ではありません。もし私があなただったら、私はオリジナルにこだわるか、ヘルパー関数を定義してそれを使用するという@ekhumoroのアイデアを採用します。

25
Ian Clelland

ここで間違った質問をしました。手がかりは、「10個以上のタグがあるので、3行から1行に取得できる場合、20行以上を保存します」というコメントへの返信にあります。

したがって、問題は実際には3行のコードがあるのではなく、3行のコードを不必要に繰り返していることです。関数を使用して繰り返し行を抽出することもできますが、この場合は実際にループが必要なように思えます。

THE_TAGS = ('tag1', 'tag2', 'and so on')
for tag in THE_TAGS:
    a = r.find(tag) # a may get None if did not find it
    if a != None:
        b.append(a)

または、別のリストに追加する必要がある場合:

def extract_tag(r, tag_name, to):
    a = r.find(tag_name) # a may get None if did not find it
    if a != None:
        to.append(a)

extract_tag(r, 'tag1', b)
extract_tag(r, 'tag2', c)
5
Duncan

実際の問題を攻撃し、明確にするために2行で実行します。

temp = [r.find(tag) for tag in list_of_tags]
b.extend(x for x in temp if x is not None)

注意: Element.extendはPython 2.7/3.2の新機能です。

2
John Machin

短い答え:そうではありません。

より長い答え:これを本当に避けたい場合は(おそらく、この動作を実装したい-----非None値のみを追加したい)-いくつかの異なるコードブロックから)、基になる周りのプロキシとしてクラスを作成できます- bオブジェクトを追加し、appendメソッドで詳細を非表示にします。

class NonNoneAppender:
    def __init__(self, obj):
        if not hasattr(obj, 'append') or not callable(obj.append):
            raise ValueError, "Object must have append method"
        self.__obj = obj
    def append(self, item):
        if item is not None:
            return self.__obj.append(item)
    def __getattr__(self, attr):
        return getattr( self.__obj, attr)      

...そして、あなたは次のようなことをすることができます:

b = NonNoneAppender(b)

しかし、これがあなたのコードにとってまったく意味があるとは思えません。

0
Jim Dennis

おそらく、コードから単一のifステートメントを削除しようとしているのではありません...

したがって、明白な答えは関数を使用することです:

import xml.etree.ElementTree as etree

def append(parent, child):
    if child is not None:
        parent.append(child)

r = etree.parse(f).getroot()
b = etree.Element('register',{})

append(b, r.find('tag_name'))
0
ekhumoro