我遇到了一些代码,类似于
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]
我遇到了一些代码,类似于
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]
TypeError: unorderable types: list() < int()
。
Answers:
这仅对NumPy数组有意义。列表的行为是无用的,并且特定于Python 2(不是Python 3)。您可能需要仔细检查原始对象是否确实是NumPy数组(请参见下文)而不是列表。
但是在您的代码中,x是一个简单的列表。
以来
x < 2
是False,即0,因此
x[x<2]
是 x[0]
x[0]
被改变。
相反,x[x>2]
是x[True]
或x[1]
因此,x[1]
得到改变。
为什么会这样?
比较的规则是:
当您对两个字符串或两个数字类型进行排序时,将以预期的方式进行排序(字符串的字典顺序,整数的数字顺序)。
订购数字类型和非数字类型时,数字类型优先。
当您订购两种都不兼容的不兼容类型时,它们都不是数字,则按其名称的字母顺序排序:
因此,我们有以下顺序
数字<列表<字符串<元组
有关Python如何比较字符串和整数的信息,请参见可接受的答案。。
如果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
import
numpy。
[0 if i < 2 else i for i in x]
。)还是Numpy中这种鼓励的风格?
x[x<2]
将返回一个numpy数组,而[0 if i<2 else i for i in x]
返回一个列表。这是因为x[x<2]
是索引操作(由于能够屏蔽数据,因此在numpy / scipy / pandas中称为切片操作),而列表理解是新的对象定义。请参阅NumPy索引编制
>>> x = [1,2,3,4,5]
>>> x<2
False
>>> x[False]
1
>>> x[True]
2
布尔值仅转换为整数。索引为0或1。
x<2 == false
?
bool
不转换为整数,bool
Python中的
bool
是一个子类的int
。
在你的问题的原代码只能在Python 2.如果x
是list
在Python 2中,比较x < y
是False
,如果y
是int
埃格尔。这是因为将列表与整数进行比较没有意义。但是在Python 2中,如果操作数不具有可比性,则比较在CPython中基于类型名称的字母顺序;此外,所有数字在混合类型比较中都排在第一位。CPython 2的文档中甚至没有阐明这一点,不同的Python 2实现可能会产生不同的结果。这是[1, 2, 3, 4, 5] < 2
计算结果为False
,因为2
是一个数字,因此多了一个“小”list
的CPython的。最终,这种混合的比较被视为功能过于模糊,并已在Python 3.0中删除。
现在,结果<
为bool
;并且bool
是一个子类的int
:
>>> isinstance(False, int)
True
>>> isinstance(True, int)
True
>>> False == 0
True
>>> True == 1
True
>>> False + 5
5
>>> True + 5
6
因此,基本上,您将元素0或1取决于比较是对还是错。
如果您在Python 3中尝试上面的代码,则会TypeError: unorderable types: list() < int()
由于Python 3.0中的更改而得到:
订购比较
Python 3.0简化了排序比较的规则:
排序比较操作符(
<
,<=
,>=
,>
)提出一个TypeError
例外,当操作数没有意义的自然顺序。因此,这样的表达式1 < ''
,0 > None
或者len <= len
不再有效,并且如None < None
加薪TypeError
,而不是返回False
。必然的结果是,对异构列表进行排序不再有意义-所有元素必须彼此可比。请注意,这不适用于==
和!=
运算符:不同类型的对象总是比较彼此不相等。
有许多数据类型使比较运算符过载,以执行不同的操作(来自pandas的数据帧,numpy的数组)。如果您正在使用的代码做了别的东西,那是因为x
是不是一个list
,而是与运营商的一些其他类的实例<
覆盖,以返回的值是不是一个bool
; 然后由x[]
(aka __getitem__
/ __setitem__
)专门处理此值
+False
嗨,Perl,嗨,JavaScript,大家好吗?
UNARY_POSITIVE
操作码调用的__pos__
__setitem__
不是__getitem__
在上一节中。另外,我希望您不要介意我的答案受到那部分答案的启发。
__getitem__
尽管同样可以做到,__setitem__
以及__delitem__
这还有另一种用途:编码高尔夫。代码高尔夫是编写程序的艺术,该程序可以在尽可能少的源代码字节中解决某些问题。
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做很多讨厌的事情,以节省一些字节。/codegolf/54/tips-for-golfing-in-python
尽管在常规代码中永远不要使用它,但是在您的情况下,这意味着x
它既可以与整数进行比较,又可以作为支持切片的容器,这是非常不寻常的组合。正如其他人指出的那样,这可能是Numpy代码。
Code Golf is the art of writing programs
:')
一般来说,这可能意味着任何事情。这是已经解释这是什么意思,如果x
是list
或numpy.ndarray
,但一般只取决于如何比较运算符(<
,>
,...)以及如何了get / set项([...]
-syntax)来实现。
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])
请注意,这只是一种可能性。您可以自由实施几乎所有想要的东西。