Me deparei com um código com uma linha semelhante a
x[x<2]=0
Brincando com variações, ainda estou preso no que essa sintaxe faz.
Exemplos:
>>> 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]
python
python-2.7
numpy
aberger
fonte
fonte
TypeError: unorderable types: list() < int()
.Respostas:
Isso só faz sentido com matrizes NumPy . O comportamento com listas é inútil e específico para Python 2 (não Python 3). Você pode querer verificar novamente se o objeto original era de fato um array NumPy (veja mais abaixo) e não uma lista.
Mas em seu código aqui, x é uma lista simples.
Desde a
x < 2
é falso, ou seja, 0, portanto
x[x<2]
éx[0]
x[0]
é alterado.Por outro lado,
x[x>2]
éx[True]
oux[1]
Então,
x[1]
é alterado.Por que isso acontece?
As regras de comparação são:
Quando você pede duas strings ou dois tipos numéricos, a ordenação é feita da maneira esperada (ordenação lexicográfica para string, ordenação numérica para inteiros).
Quando você pede um tipo numérico e um não numérico, o tipo numérico vem primeiro.
Quando você ordena dois tipos incompatíveis onde nenhum é numérico, eles são ordenados pela ordem alfabética de seus nomes de tipo:
Então, temos a seguinte ordem
numérico <lista <string <tupla
Veja a resposta aceita para Como o Python compara string e int? .
Se x for um array NumPy , a sintaxe faz mais sentido por causa da indexação do array booleano . Nesse caso,
x < 2
não é booleano; é uma matriz de booleanos que representam se cada elemento dex
era menor que 2.x[x < 2] = 0
então seleciona os elementos dex
que eram menores que 2 e define essas células como 0. Veja Indexação .>>> 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
fonte
import
para entorpecido.[0 if i < 2 else i for i in x]
,.) Ou esse estilo é encorajado no Numpy?x[x<2]
retornará um array numpy, enquanto[0 if i<2 else i for i in x]
retorna uma lista. Isso ocorre porquex[x<2]
é uma operação de indexação (referida em numpy / scipy / pandas como uma operação de corte devido à capacidade de mascarar dados), enquanto a compreensão de lista é uma nova definição de objeto. Consulte a indexação NumPy>>> x = [1,2,3,4,5] >>> x<2 False >>> x[False] 1 >>> x[True] 2
O bool é simplesmente convertido em um número inteiro. O índice é 0 ou 1.
fonte
x
e2
são " ordenados de forma consistente, mas arbitrária " e que a ordem pode mudar em diferentes implementações Python.x<2 == false
?bool
não é convertido em um inteiro, abool
em Python é um inteirobool
é uma subclasse deint
.O código original em sua pergunta funciona apenas no Python 2. Se
x
for umlist
no Python 2, a comparaçãox < y
éFalse
sey
for umint
eger. Isso ocorre porque não faz sentido comparar uma lista com um inteiro. No entanto, no Python 2, se os operandos não são comparáveis, a comparação é baseada no CPython na ordem alfabética dos nomes dos tipos ; além disso, todos os números vêm primeiro em comparações de tipos mistos . Isso nem mesmo está explicitado na documentação do CPython 2, e diferentes implementações do Python 2 podem dar resultados diferentes. Isso é[1, 2, 3, 4, 5] < 2
avaliado comoFalse
porque2
é um número e, portanto, "menor" que alist
no CPython. Esta comparação mista foi eventualmenteconsiderado um recurso muito obscuro e foi removido no Python 3.0.Agora, o resultado de
<
é umbool
; ebool
é uma subclasse deint
:>>> isinstance(False, int) True >>> isinstance(True, int) True >>> False == 0 True >>> True == 1 True >>> False + 5 5 >>> True + 5 6
Então, basicamente, você está pegando o elemento 0 ou 1, dependendo se a comparação é verdadeira ou falsa.
Se você tentar o código acima no Python 3, obterá
TypeError: unorderable types: list() < int()
devido a uma alteração no Python 3.0 :Existem muitos tipos de dados que sobrecarregam os operadores de comparação para fazer algo diferente (dataframes de pandas, matrizes de numpy). Se o código que você estava usando fazia outra coisa, era porque não
x
era umlist
, mas uma instância de alguma outra classe com operador<
substituído para retornar um valor que não é umbool
; e este valor foi então tratado especialmente porx[]
(aka__getitem__
/__setitem__
)fonte
+False
Olá, Perl, ei JavaScript, como estão?UNARY_POSITIVE
opcode que chama o__pos__
__setitem__
vez de__getitem__
em sua última seção. Além disso, espero que você não se importe que minha resposta tenha sido inspirada por essa parte de sua resposta.__getitem__
embora igualmente poderia ter sido__setitem__
e__delitem__
Isso tem mais uma utilidade: código de golfe. O golfe do código é a arte de escrever programas que resolvam alguns problemas com o mínimo possível de bytes de código-fonte.
return(a,b)[c<d]
é aproximadamente equivalente a
if c < d: return b else: return a
exceto que tanto a quanto b são avaliados na primeira versão, mas não na segunda versão.
c<d
avalia paraTrue
ouFalse
.(a, b)
é uma tupla.A indexação em uma tupla funciona como a indexação em uma lista:
(3,5)[1]
==5
.True
é igual a1
eFalse
é igual a0
.(a,b)[c<d]
(a,b)[True]
(a,b)[1]
b
ou para
False
:(a,b)[c<d]
(a,b)[False]
(a,b)[0]
a
Há uma boa lista na rede de troca de pilha de muitas coisas desagradáveis que você pode fazer no python para economizar alguns bytes. /codegolf/54/tips-for-golfing-in-python
Embora no código normal isso nunca deva ser usado, no seu caso significaria que
x
atua tanto como algo que pode ser comparado a um inteiro e como um contêiner que suporta o fatiamento, o que é uma combinação muito incomum. Provavelmente é um código Numpy, como outros apontaram.fonte
Code Golf is the art of writing programs
: ')Em geral, pode significar qualquer coisa . Ele já foi explicado o que significa que se
x
é umlist
ounumpy.ndarray
mas em geral ele só depende de como os operadores de comparação (<
,>
...) e também como o get / set-item ([...]
-syntax) são implementadas.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!
Porque:
x < value
é equivalente ax.__lt__(value)
x[value]
é (aproximadamente) equivalente ax.__getitem__(value)
x[value] = othervalue
é (também aproximadamente) equivalente ax.__setitem__(value, othervalue)
.Isto pode ser personalizado para fazer qualquer coisa que quiser. Apenas como exemplo (imita uma indexação bit 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
Então, agora vamos ver o que acontece se você usá-lo:
>>> 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])
Observe que esta é apenas uma possibilidade. Você é livre para implementar quase tudo o que quiser.
fonte