本文共 2172 字,大约阅读时间需要 7 分钟。
有人问了这么个问题:有一系列恒星光谱,希望选出其中特定的两个光谱型的数据来画图,但是一直失败。我看了下,代码大概是这样的:(在原代码基础上简化了一下)
id_ok = []
n = len(dat_all)
for i in range(n):
if dat_all[i]["objtype"] == ("IV" or "III"):
id_ok.append(i)
n_ok = len(id_ok)
for j in range(n_ok):
# 这里省略画图步骤
plot(dat_all[id_ok[j]])
然后,只画出了第一类恒星(IV)的图,如果交换两者,还是只能画写在前面的那一种。
先解析一下原作者的设计意图:他希望能够判断第i个记录的objtype字段,如果是"IV"或者"III"则添加到列表中,记录下来,后面对添加后的列表进行画图。
估计很多人脑中已经有这个问题的十八种解决办法了……那么你可以拉到底,点一下广告和“在看”然后退出了,下面的内容不是针对你的。
首先解读一下上面那一段代码是怎么被python执行的。if那一句可以简化成:
if x == (a or b):
这句话从Python的语法来说,是先对(a or b)进行求值,然后和x进行==比较。
很多人觉得or作为一个逻辑运算符,前后应该是两个bool表达式。而实际上python的理解是,需要一个bool值的时候,如果你给了一个别的类型,那么非零非空的值就被理解成True,而0/0.0/""/[]/()/{}/None这样的,则被当做是False。此外,尽管其他类型表达式被当做bool使用,但是表达式本身还是原始值,不会被强行改为True/False。
其次,and/or是典型的短路运算符,意思就是当左值可以决定运算结果时,右值直接被忽略,表达式不会被求值,如果右侧表达式中有对变量的赋值,或者输出,都不会发生,因为彻底不执行。一旦发现and左边是False,或者or左边是True,整个运算直接返回左值,不再执行。
注意:这里是说的返回左值本身,而不是返回True/False!
也就是说,表达式 a or b,如果a不是False,或者上面说的可以当做False的其他值,那么就会返回a,否则返回b,实际上根本不检查b是T还是F还是别的啥,直接求值并返回。
a or b 可以当做是这么一个if表达式:a if a else b
然后,才是这个表达式和前面的x去判断是否相等。显然的,在前面的例子中,右侧的b彻底被忽略了,所以不管怎么调整顺序,肯定显示前者。
那么该怎么改呢?因为问的时候我正好在买菜……等我买完,对方已经自己解决了:
for i in range(n):
if dat_all[i]["objtype"] == "IV":
id_ok.append(i)
if dat_all[i]["objtype"] == "III":
id_ok.append(i)
嗯,解决方法不是最优的,但是也是解决了问题的。那么下面说说怎么做比较“高档”。
1,使用or连接多个条件
for i in range(n):
if dat_all[i]["objtype"] == "IV" or dat_all[i]["objtype"] == "III":
id_ok.append(i)
应该说,这才是or在这里的正确用法。
2,使用in运算符和list/tuple
for i in range(n):
if dat_all[i]["objtype"] in ("IV", "III"):
id_ok.append(i)
虽然看起来和之前有点像,但是这里用in运算符,实际上in执行的也是==操作。
显然的,这里用["IV", "III"]也可以,一样的。反正都是一次性使用。
3,数组运算
由于这实际上做的是从数组中选出目标的操作,所以可以直接用where:
id_ok = np.where(
(dat_all["objtype"] == "IV") |
(dat_all["objtype"] == "III") )
不过这里就稍微复杂一些了,这个|运算是咋回事?为啥要这么加括号?
首先说明一下,由于and/or这两个逻辑运算符,没法和数组结合,所以得用&和|运算符。前面一个条件是对整个数组做的,得到的是一个bool数组,后面也是。但是&|是位运算符,所以实际上反而是把True/False当做1/0来处理的,
至于括号呢,因为&|的运算符优先级比==高,所以得加上括号。这也很正常,计算运算符的优先级肯定要比比较运算符高,这是惯例。
4,直接用bool值作为下标
dat_all[
(dat_all["objtype"] == "IV") |
(dat_all["objtype"] == "III")
]
这样也可以的,np的数组可以直接用和数组长度一样的0/1数组来表达对元素的选择。
除了这些常用的办法,你还有啥建议,欢迎留言。这篇主要针对初学者,大牛们就别嫌我讲基础知识了~~
另外,这里对纪录数组(结构体数组)就不多做介绍了,大家就假装看懂了吧……反正前面有一篇讲到了。
欢迎关注“小林在线”
一个可能有点看不懂的公号
转载地址:http://xzima.baihongyu.com/