我遇到了一些类似于
的代码x[x<2]=0
使用各种变体,我仍然坚持这种语法的作用。
示例:
>>> x = [1,2,3,4,5]
>>> x[x<2]
1
>>> x[x<3]
1
>>> x[x>2]
2
>>> x[x<2]=0
>>> x
[0, 2, 3, 4, 5]
答案 0 :(得分:117)
这仅适用于 NumPy数组。列表的行为是无用的,并且特定于Python 2(不是Python 3)。您可能需要仔细检查原始对象是否确实是NumPy数组(请参见下文),而不是列表。
但是在你的代码中,x是一个简单的列表。
由于
x < 2
是假的 即0,因此
x[x<2]
是x[0]
x[0]
变了。
相反,x[x>2]
为x[True]
或x[1]
因此,x[1]
会发生变化。
为什么会这样?
比较规则是:
当您订购两个字符串或两个数字类型时,排序以预期的方式完成(字符串的字典顺序,整数的数字排序)。
订购数字和非数字类型时,数字类型首先出现。
当您订购两个不兼容的类型(两者都不是数字)时,它们按类型名的字母顺序排序:
所以,我们有以下顺序
数字&lt;列表&lt;字符串&lt;元组
请参阅 How does Python compare string and int? 的接受答案。
如果x是NumPy数组,则由于布尔数组索引,语法更有意义。在这种情况下,x < 2
根本不是布尔值;它是一组布尔值,表示x
的每个元素是否小于2. x[x < 2] = 0
然后选择小于2的x
元素并将这些单元格设置为0 。请参阅 Indexing 。
>>> x = np.array([1., -1., -2., 3])
>>> x < 0
array([False, True, True, False], dtype=bool)
>>> x[x < 0] += 20 # All elements < 0 get increased by 20
>>> x
array([ 1., 19., 18., 3.]) # Only elements < 0 are affected
答案 1 :(得分:45)
>>> x = [1,2,3,4,5]
>>> x<2
False
>>> x[False]
1
>>> x[True]
2
bool简单地转换为整数。索引是0或1。
答案 2 :(得分:14)
您问题中的原始代码仅适用于Python 2.如果{2}是{2}} {2},那么x
的比较list
x < y
False
是y
eger。这是因为将列表与整数进行比较是没有意义的。但是在Python 2中,如果操作数不具有可比性,则比较基于alphabetical ordering of the names of the types上的CPython;另外所有数字在混合型比较中排在第一位。这甚至没有在CPython 2的文档中详细说明,并且不同的Python 2实现可能会给出不同的结果。这是int
评估为[1, 2, 3, 4, 5] < 2
,因为False
是一个数字,因此比CPython中的2
“更小”。这种混合比较最终是deemed to be too obscure a feature,并在Python 3.0中被删除。
现在,list
的结果是<
;和bool
is a subclass of int
:
bool
所以基本上你取的是元素0或1,取决于比较是真还是假。
如果您在Python 3中尝试上面的代码,由于a change in Python 3.0,您将获得>>> isinstance(False, int)
True
>>> isinstance(True, int)
True
>>> False == 0
True
>>> True == 1
True
>>> False + 5
5
>>> True + 5
6
:
订购比较
Python 3.0简化了排序比较的规则:
当操作数没有有意义的自然时,排序比较运算符(
TypeError: unorderable types: list() < int()
,<
,<=
,>=
)会引发>
异常排序。因此,TypeError
,1 < ''
或0 > None
等表达式不再有效,例如len <= len
提升None < None
而不是返回TypeError
。一个必然结果是,对异构列表进行排序不再有意义 - 所有元素必须相互比较。请注意,这不适用于False
和==
运算符:不同无比类型的对象总是相互比较不相等。
有许多数据类型重载比较运算符来执行不同(来自pandas,numpy数组的数据帧)。如果您使用的代码执行了其他操作,那是因为!=
不是x
,而是覆盖了运算符list
的其他类的实例返回不是<
的值;然后,bool
(又名x[]
/ __getitem__
)专门处理此值
答案 3 :(得分:9)
这还有一个用途:代码高尔夫。 Code golf是编写程序的艺术,可以在尽可能少的源代码字节中解决一些问题。
return(a,b)[c<d]
大致相当于
if c < d:
return b
else:
return a
除了a和b都在第一个版本中评估,但不在第二个版本中评估。
c<d
评估为True
或False
(a, b)
是一个元组
对元组建立索引就像在列表上建立索引一样:(3,5)[1]
== 5
True
等于1
,False
等于0
。
(a,b)[c<d]
(a,b)[True]
(a,b)[1]
b
或False
:
(a,b)[c<d]
(a,b)[False]
(a,b)[0]
a
在堆栈交换网络上有一个很好的列表,你可以对python执行许多讨厌的事情以节省几个字节。 https://codegolf.stackexchange.com/questions/54/tips-for-golfing-in-python
虽然在普通代码中不应该使用它,但在你的情况下,这意味着x
既可以作为可以与整数进行比较的东西,也可以作为支持切片的容器,这是非常不寻常的组合。正如其他人所指出的,它可能是Numpy代码。
答案 4 :(得分:6)
一般来说,它可能意味着任何。已经解释了x
是list
或numpy.ndarray
时的含义,但一般情况下它只取决于比较运算符(<
,>
的方式, ...)以及如何实现get / set-item([...]
- 语法)。
x.__getitem__(x.__lt__(2)) # this is what x[x < 2] means!
x.__setitem__(x.__lt__(2), 0) # this is what x[x < 2] = 0 means!
由于:
x < value
相当于x.__lt__(value)
x[value]
(大致)等同于x.__getitem__(value)
x[value] = othervalue
(也大致)相当于x.__setitem__(value, othervalue)
。可以自定义此功能以执行您想要的任何。就像一个例子(模仿一点numpys-boolean索引):
class Test:
def __init__(self, value):
self.value = value
def __lt__(self, other):
# You could do anything in here. For example create a new list indicating if that
# element is less than the other value
res = [item < other for item in self.value]
return self.__class__(res)
def __repr__(self):
return '{0} ({1})'.format(self.__class__.__name__, self.value)
def __getitem__(self, item):
# If you index with an instance of this class use "boolean-indexing"
if isinstance(item, Test):
res = self.__class__([i for i, index in zip(self.value, item) if index])
return res
# Something else was given just try to use it on the value
return self.value[item]
def __setitem__(self, item, value):
if isinstance(item, Test):
self.value = [i if not index else value for i, index in zip(self.value, item)]
else:
self.value[item] = value
现在让我们看看如果你使用它会发生什么:
>>> a = Test([1,2,3])
>>> a
Test ([1, 2, 3])
>>> a < 2 # calls __lt__
Test ([True, False, False])
>>> a[Test([True, False, False])] # calls __getitem__
Test ([1])
>>> a[a < 2] # or short form
Test ([1])
>>> a[a < 2] = 0 # calls __setitem__
>>> a
Test ([0, 2, 3])
请注意,这只是一种可能性。你可以自由地实现你想要的一切。