Python:避免此代码的 if 条件?

Python: avoiding if condition for this code?

提问人:Jerry Gao 提问时间:1/12/2012 最后编辑:JonasJerry Gao 更新时间:11/18/2023 访问量:72743

问:

对于以下代码

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

a 可以赋值为 None,有没有办法避免 if 语句,只使用一行代码?

原始问题如下

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')
python if-statement 控制流

评论

0赞 brc 1/12/2012
像这样的东西??很难说你在这里到底想做什么。b = [x for x in funcList if x is not None]
4赞 Jim Dennis 1/12/2012
通常认为使用 == 或 != 将对象与 None 进行比较是一个坏主意。“is”或“is not”是检查对象是否引用 None 的首选方法。(== 和 != 本质上是将 None 强制转换为布尔值、数值或字符串值进行比较,因此在语义上可能是错误的)。
0赞 Jerry Gao 1/12/2012
b 实际上是 xml.etree.ElementTree 的一个类,所以,我不确定 [] 表示法是否可以工作。
0赞 Donald Miner 1/12/2012
我认为他是在抱怨这样一个事实,即他只想附加 func() 的结果,如果它不为 null。但是,由于他必须检查,他在那里有一个尴尬的 if 语句。
0赞 RanRag 1/12/2012
@JerryGao:告诉我们你在尝试什么。

答:

43赞 Ian Clelland 1/12/2012 #1

如果可以事先调用 func(),并且想要将 test 和 assignment 语句组合成一个语句,那么可以使用 if-else 表达式执行此操作:

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

如果 a 不是 None,则会在 b 上添加 [a] -- 与 b.append(a) 的操作基本相同

如果 a None,则会在 b 上添加 [],这将使 b 保持不变。

除非 b 是一个列表,或者至少支持“+=”就地添加,否则这将不起作用。如果没有 - 也许是一些自定义对象,那么你应该能够这样做:

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

这是一个表达式,评估其副作用,然后扔掉。如果 a 为 None,则永远不会执行调用。无论哪种情况,表达式的值都是 None,但我们不关心它,因此会忽略它。b.append(a)

现在,如果你想将 func() 调用与此结合起来,那么你必须做一些不同的事情,以避免两次调用 func。如果你可以使用“+=”语法,那么你可以这样做:

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

filter(None, <list>)返回删除了所有 false 元素(包括 None 以及 0 和 [])的列表。然后,此语句将向 b 添加 [func()] 或 []。

[已编辑]

最后,对于最坏的情况:如果你不能多次调用 func(),并且你不能使用 ,并且你需要接受 0、“”、[] 等,并且只排除 ,并且你需要在一行上全部使用,这是迄今为止最丑陋的代码行:b += <list>None

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

这本质上是@ekhumoro的解决方案,压缩成一行。它定义了一个匿名函数,调用它,丢弃值,然后丢弃函数,所有这些都是为了副作用。

现在,这是一行,但它肯定不比原始代码更容易阅读或理解。如果我是你,我会坚持原来的,或者遵循@ekhumoro的想法,只定义一个帮助程序函数并使用它。

评论

0赞 Donald Miner 1/12/2012
问题是,你在哪里打电话?你可能不想多次调用这个东西。我真的很想看到这个解决方案,它被一个只被调用一次(在一行中)的函数调用所取代。func()a
0赞 Jerry Gao 1/12/2012
b 实际上是 xml.etree.ElementTree 的一个类,所以,我不确定 [] 表示法是否可以工作。
0赞 Matt 1/12/2012
为什么不只是 b+=[a] if a else []...而不是 if 部分,您仍然需要事先调用 a=func()。对不起,我想这是你不喜欢的部分
0赞 Jerry Gao 1/12/2012
你会把 = func() 放在你的一行中的什么位置?
0赞 Matt 1/12/2012
对于一句台词,我喜欢伊恩的......但似乎有点难以阅读/矫枉过正
-1赞 Abhranil Das 1/12/2012 #2

b+=list(set([r.find('tag_name')])-set([None]))

但它非常丑陋。更干净一点,但也更长了一行:

b.append(r.find('tag_name'))
b.remove(None)

不过还是不是很整洁。如果我是你,我会保留这句话。if

评论

0赞 John Machin 1/12/2012
-1 引发异常”b.append(None)TypeError: must be Element, not None
0赞 John Machin 1/14/2012
我正在使用 cElementTree。恕我直言,ElementTree 行为是一个错误。查看 bugs.python.org/issue13782
1赞 John Machin 1/14/2012
另一个问题:如果找到某些东西,则失败并显示 ValueError。r.find()b.remove(None)
1赞 ekhumoro 1/12/2012 #3

据推测,您不是要从代码中删除一个语句......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赞 Jerry Gao 1/12/2012
我只是想知道我是否可以避免如果,但这也很好。
6赞 Duncan 1/12/2012 #4

你在这里问错了问题。线索在于您对其中一条评论的回复,您说“我有 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)

评论

0赞 Jerry Gao 1/12/2012
我只是想知道我是否可以避免如果,但这也很好。我没有使用的原因是因为其中一个标签有不同的命名空间,只有一个......
0赞 John Machin 1/12/2012
@JerryGao:“不同的命名空间”应该不是问题......请解释。taglist = ["{ns1}tag1", "{ns2}tag2", etc]
0赞 Jerry Gao 1/12/2012
@JohnMachin就我而言,它是 taglist = [“{ns1}tag1”, “{ns1}tag2”,“{ns1}tag3”, ... , “{ns0}TAG”]
0赞 John Machin 1/12/2012
@JerryGao:你还没有说你的命名空间有什么问题。为什么你不能使用这个答案(或我的答案)?
2赞 John Machin 1/12/2012 #5

解决你真正的问题,为了清楚起见,分两行做:

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

注意:是 Python 2.7/3.2 中的新功能Element.extend

评论

0赞 Ian Clelland 1/12/2012
+1 表示扩展 -- 尽管您可能要注意它仅适用于 Python 2.7。
2赞 Jim Dennis 1/12/2012 #6

简短的回答:不是真的。

更长的答案:如果你真的想避免这种情况(也许是因为你想从几个不同的代码块---仅附加非 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)

但是,我不确定这对您的代码是否有任何意义。

评论

1赞 John Machin 1/12/2012
您也可以添加一个非 None 方法extend
0赞 Jim Dennis 1/12/2012
@John Machin:哎呀!嗯......是的,我应该有。那只是“for i in items: self.append(i)”
33赞 Lucas Vazquez 10/5/2019 #7

Python 3.8 海象操作员

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

评论

6赞 StationaryTraveller 11/22/2020
这真是太美了:)
0赞 Acccumulation 12/28/2022 #8

您可以添加所有内容并在末尾删除 Nones。或者,在您的特定用例中,您可以执行 .但是,这可能会慢一些,因为它将遍历整个树,而不是在第一个实例中停止。b = [a for a in b if b is not None]b.extend(r.findall('tag_name')[:1])

0赞 acinis 11/18/2023 #9

(应该对这个答案发表评论,但我没有足够的声誉)

请记住,海象操作员可能会非常令人惊讶。

  1. 海象分配到的变量将不是本地的,例如。如果阻止:

    if a := func():
        b.append(a)
    print(a) # a just leaked to upper scope
    
  2. Walrus 运算符的优先级较低,因此在比较中使用时必须用括号括起来,否则将首先评估比较。

    def func(x):
        return x
    
    b = []
    
    if a := func(7) == 7:
        b.append(a)
        print(a, "appended !") # prints: True appended !