Natknąłem się na kod z linią podobną do
x[x<2]=0
Bawiąc się wariacjami, wciąż tkwię w tym, co robi ta składnia.
Przykłady:
>>> 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
źródło
źródło
TypeError: unorderable types: list() < int()
.Odpowiedzi:
Ma to sens tylko w przypadku tablic NumPy . Zachowanie z listami jest bezużyteczne i specyficzne dla Pythona 2 (nie Pythona 3). Możesz chcieć dwukrotnie sprawdzić, czy oryginalny obiekt rzeczywiście był tablicą NumPy (patrz poniżej), a nie listą.
Ale w twoim kodzie tutaj x jest prostą listą.
Od
x < 2
jest fałszywe, czyli 0, dlatego
x[x<2]
jestx[0]
x[0]
zmienia się.Odwrotnie,
x[x>2]
jestx[True]
lubx[1]
Więc
x[1]
zmienia się.Dlaczego to się dzieje?
Zasady porównania to:
Kiedy zamawiasz dwa ciągi lub dwa typy liczbowe, porządkowanie odbywa się w oczekiwany sposób (porządek leksykograficzny dla łańcuchów, porządek numeryczny dla liczb całkowitych).
Kiedy zamawiasz typ numeryczny i nieliczbowy, typ numeryczny jest pierwszy.
Kiedy zamawiasz dwa niezgodne typy, w których żaden nie jest numeryczny, są one sortowane według kolejności alfabetycznej ich nazw typów:
Mamy więc następującą kolejność
numeryczne <lista <ciąg <krotka
Zobacz zaakceptowaną odpowiedź na pytanie Jak Python porównuje ciąg i int? .
Jeśli x jest tablicą NumPy , składnia ma większy sens ze względu na indeksowanie tablic logicznych . W takim przypadku
x < 2
nie jest w ogóle wartością logiczną; jest to tablica wartości logicznych reprezentujących, czy każdy elementx
był mniejszy niż 2.,x[x < 2] = 0
a następnie wybiera elementy,x
których były mniejsze niż 2 i ustawia te komórki na 0. Zobacz Indeksowanie .>>> 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
źródło
import
odrętwienie.[0 if i < 2 else i for i in x]
,.) A może jest to zachęcający styl w Numpy?x[x<2]
zwróci tablicę numpy, podczas gdy[0 if i<2 else i for i in x]
zwróci listę. Dzieje się tak, ponieważx[x<2]
jest to operacja indeksowania (określana w numpy / scipy / pandas jako operacja dzielenia ze względu na możliwość maskowania danych), podczas gdy rozumienie list jest nową definicją obiektu. Zobacz indeksowanie NumPy>>> x = [1,2,3,4,5] >>> x<2 False >>> x[False] 1 >>> x[True] 2
Wartość bool jest po prostu konwertowana na liczbę całkowitą. Indeks wynosi 0 lub 1.
źródło
x
i2
być „ uporządkowane konsekwentnie, ale dowolnie ” oraz że kolejność może się zmienić w różnych implementacjach Pythona.x<2 == false
?bool
nie jest konwertowane na liczbę całkowitą, abool
w Pythonie jest liczbą całkowitąbool
jest podklasą zint
.Oryginalny kod w twoim pytaniu działa tylko w Pythonie 2. Jeśli
x
jestlist
w Pythonie 2, porównaniex < y
jestFalse
wtedy, gdyy
jestint
eger. Dzieje się tak, ponieważ nie ma sensu porównywanie listy z liczbą całkowitą. Jednak w Pythonie 2, jeśli operandy nie są porównywalne, porównanie opiera się w języku CPython na kolejności alfabetycznej nazw typów ; dodatkowo wszystkie liczby zajmują pierwsze miejsce w porównaniach typu mieszanego . Nie jest to nawet opisane w dokumentacji CPythona 2, a różne implementacje Pythona 2 mogą dawać różne wyniki. Wartość ta jest[1, 2, 3, 4, 5] < 2
obliczana na,False
ponieważ2
jest liczbą, a zatem „mniejszą” niżlist
w CPythonie. Ostatecznie doszło do tego mieszanego porównaniauznana za zbyt mało znaną funkcję i została usunięta w Pythonie 3.0.Teraz wynik
<
jestbool
; ibool
jest podklasą zint
:>>> isinstance(False, int) True >>> isinstance(True, int) True >>> False == 0 True >>> True == 1 True >>> False + 5 5 >>> True + 5 6
Więc w zasadzie bierzesz element 0 lub 1 w zależności od tego, czy porównanie jest prawdziwe, czy fałszywe.
Jeśli wypróbujesz powyższy kod w Pythonie 3, otrzymasz
TypeError: unorderable types: list() < int()
ze względu na zmianę w Pythonie 3.0 :Istnieje wiele typów danych, które przeciążają operatory porównania, aby zrobić coś innego (ramki danych z pand, tablice numpy). Jeśli kod, którego używałeś, zrobił coś innego, to dlatego, że nie
x
był alist
, ale instancją innej klasy z<
przesłoniętym operatorem w celu zwrócenia wartości, która nie jestbool
; i ta wartość była następnie obsługiwana specjalnie przezx[]
(aka__getitem__
/__setitem__
)źródło
+False
Cześć Perl, hej JavaScript, jak się macie?UNARY_POSITIVE
opcode, który wywołuje__pos__
__setitem__
zamiast__getitem__
w swojej ostatniej sekcji. Mam również nadzieję, że nie masz nic przeciwko temu, że moja odpowiedź została zainspirowana tą częścią Twojej odpowiedzi.__getitem__
choć równie dobrze mogło być__setitem__
i__delitem__
Ma to jeszcze jedno zastosowanie: golf kodowy. Code golf to sztuka pisania programów, które rozwiązują jakiś problem w jak najmniejszej liczbie bajtów kodu źródłowego.
return(a,b)[c<d]
jest w przybliżeniu odpowiednikiem
if c < d: return b else: return a
z wyjątkiem tego, że zarówno a, jak i b są oceniane w pierwszej wersji, ale nie w drugiej.
c<d
ocenia doTrue
lubFalse
.(a, b)
jest krotką.Indeksowanie krotki działa jak indeksowanie listy:
(3,5)[1]
==5
.True
jest równa1
iFalse
równa się0
.(a,b)[c<d]
(a,b)[True]
(a,b)[1]
b
lub dla
False
:(a,b)[c<d]
(a,b)[False]
(a,b)[0]
a
W sieci wymiany stosów znajduje się dobra lista wielu paskudnych rzeczy, które możesz zrobić w Pythonie, aby zaoszczędzić kilka bajtów. /codegolf/54/tips-for-golfing-in-python
Chociaż w normalnym kodzie nigdy nie powinno to być używane, aw twoim przypadku oznaczałoby to, że
x
działa zarówno jako coś, co można porównać do liczby całkowitej, jak i jako kontener obsługujący cięcie na plasterki, co jest bardzo nietypową kombinacją. To prawdopodobnie kod Numpy, jak zauważyli inni.źródło
Code Golf is the art of writing programs
: ')Ogólnie może to oznaczać wszystko . Było to już wyjaśniono, co to znaczy, jeśli
x
jestlist
albonumpy.ndarray
ale w ogóle to zależy tylko od tego, jak operatorzy porównania (<
,>
...), a także w jaki sposób get / set-item ([...]
-syntax) są realizowane.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!
Dlatego:
x < value
jest równax.__lt__(value)
x[value]
jest (w przybliżeniu) odpowiednikiemx.__getitem__(value)
x[value] = othervalue
jest (również w przybliżeniu) równoważne zx.__setitem__(value, othervalue)
.Można to dostosować, aby robić wszystko, co chcesz. Na przykład (naśladuje nieco numpys-boolean indeksowanie):
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
Zobaczmy teraz, co się stanie, jeśli go użyjesz:
>>> 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])
Zauważ, że to tylko jedna możliwość. Możesz wdrożyć prawie wszystko, co chcesz.
źródło