web-dev-qa-db-fra.com

Python: éviter la condition if pour ce code?

pour le code suivant

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

a peut être affecté à None, existe-t-il un moyen d'éviter l'instruction if et de n'utiliser qu'une seule ligne de code?

le problème d'origine est le suivant

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)

ok, j'ai utilisé toutes les réponses et j'ai obtenu ceci, personnellement, je pense que c'est le plus complexe python que j'ai jamais écrit jusqu'à présent, lol

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

Si vous pouvez appeler func () au préalable et que vous souhaitez combiner les instructions de test et d'affectation en une seule instruction, vous pouvez le faire, avec une expression if-else:

b += [a] if a is not None else []

Si a n'est pas None, cela ajoutera [a] à b - essentiellement la même opération que b.append (a)

Si a est Aucun, cela ajoutera [] à b, ce qui laissera b inchangé.

Cela ne fonctionnera que si b est une liste, ou au moins prend en charge l'ajout sur place "+ =". Si ce n'est pas le cas - c'est peut-être un objet personnalisé, alors vous devriez pouvoir le faire:

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

Il s'agit d'une expression, évaluée pour ses effets secondaires, puis jetée. Si a est None, l'appel b.append(a) ne sera jamais exécuté. Dans les deux cas, la valeur de l'expression est None, mais nous ne nous en soucions pas, elle est donc ignorée.

Maintenant, si vous souhaitez combiner l'appel func () avec cela, vous devrez faire quelque chose de différent afin d'éviter d'appeler deux fois func. Si vous pouvez utiliser la syntaxe "+ =", vous pouvez le faire comme ceci:

b += filter(None, [func()])

filter(None, <list>) renvoie la liste avec tous les faux éléments (aucun inclus, mais également 0 et []) supprimés. Cette instruction va donc ajouter [func ()] ou [] à b.

[Modifié]

Enfin, dans le pire des cas: si vous ne pouvez pas appeler func () plus d'une fois, et vous ne pouvez pas utiliser b += <list>, et vous devez accepter 0, "", [], etc., et exclure uniquement None, et vous avez besoin de tout cela sur une seule ligne, voici la ligne de code la plus laide à ce jour:

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

Il s'agit essentiellement de la solution de @ ekhumoro, compressée en une seule ligne. Il définit une fonction anonyme, l'appelle, supprime la valeur, puis supprime la fonction, le tout pour le bien de l'effet secondaire.

Maintenant, c'est une seule ligne, mais ce n'est certainement pas plus facile à lire ou à comprendre que le code d'origine. Si j'étais vous, je m'en tiendrai à l'original, ou j'irais avec l'idée de @ ekhumoro de simplement définir une fonction d'aide et de l'utiliser.

25
Ian Clelland

Vous avez posé la mauvaise question ici. L'indice se trouve dans votre réponse à l'un des commentaires où vous dites "J'ai 10+ balises, si je peux obtenir 3 lignes à 1 ligne, j'économiserai 20+ lignes".

Donc, votre problème n'est pas que vous avez 3 lignes de code, mais que vous répétez inutilement 3 lignes de code encore et encore. Vous pouvez utiliser une fonction pour extraire les lignes répétées, mais il semble que dans ce cas, vous souhaitiez peut-être une boucle:

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)

Ou si vous devez ajouter à différentes listes:

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

Attaquer votre vrai problème et le faire en deux lignes pour plus de clarté:

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

Remarque: Element.extend est nouveau dans Python 2.7/3.2

2
John Machin

Réponse courte: pas vraiment.

Réponse plus longue: si vous vouliez vraiment éviter cela (peut-être parce que vous voulez implémenter ce comportement --- en ajoutant uniquement des valeurs non nulles) à partir de plusieurs blocs de code différents), vous pourriez créer une classe en tant que proxy autour du sous-jacent - b objet et masquer les détails dans sa méthode d'ajout.

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)      

... et ensuite vous pourriez faire quelque chose comme:

b = NonNoneAppender(b)

Cependant, je ne suis pas sûr que cela aurait du sens pour votre code.

0
Jim Dennis

Vraisemblablement, vous n'essayez pas de supprimer une seule instruction if de votre code ...

La réponse évidente est donc d'utiliser une fonction:

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