Я натрапив на якийсь код із рядком, подібним до
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()
.
Відповіді:
Це має сенс лише для масивів NumPy . Поведінка зі списками є марною і специфічною для Python 2 (не Python 3). Можливо, вам доведеться ще раз перевірити, чи справді вихідний об'єкт був масивом NumPy (див. Далі), а не списком.
Але у вашому коді тут х - простий список.
Оскільки
x < 2
є False, тобто 0, отже
x[x<2]
є x[0]
x[0]
змінюється.
І навпаки, x[x>2]
є x[True]
абоx[1]
Отже, x[1]
змінюється.
Чому так трапляється?
Правила порівняння:
Коли ви замовляєте два рядки або два числові типи, упорядкування виконується очікуваним чином (лексикографічне впорядкування для рядка, числове впорядкування для цілих чисел).
Коли ви замовляєте числовий і нечисловий тип, числовий тип стає на перше місце.
Коли ви замовляєте два несумісні типи, жоден з яких не є числовим, вони впорядковуються за алфавітом їх назв типів:
Отже, маємо такий порядок
числовий <список <рядок <кортеж
Дивіться прийняту відповідь на тему Як Python порівнює рядок та int? .
Якщо x - масив NumPy , то синтаксис має більший сенс через індексацію булевого масиву . У такому випадку x < 2
це зовсім не логічне значення; це масив булевих символів, що вказує, чи x
не менше кожного елемента 2, x[x < 2] = 0
потім виділяє елементи, x
які були менше 2, і встановлює для цих комірок значення 0. Див. Індексація .
>>> 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
for 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
є « упорядкований послідовно , але довільно » і що впорядкування може змінитися в різних реалізаціях Python.
x<2 == false
?
bool
не перетворюється на ціле число, a 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.
Тепер результат <
є a 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
. Висновок полягає в тому, що сортування різнорідного списку більше не має сенсу - всі елементи повинні бути порівнянними між собою. Зауважте, що це не стосується операторів==
and!=
: об’єкти різних незрівнянних типів завжди порівнюють нерівні між собою.
Існує багато типів даних, які перевантажують оператори порівняння, щоб зробити щось інше (фрейми даних з панд, масиви numpy). Якщо код , який ви використовували зробив що - то ще, це було тому , що x
був НЕlist
, але з екземпляром деякого іншого класу з оператором <
перевизначені повернути значення, яке не є bool
; і це значення потім оброблялося спеціально x[]
(aka __getitem__
/ __setitem__
)
+False
Привіт, Perl, привіт, JavaScript, як справи?
UNARY_POSITIVE
opcode називається__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
але в цілому це залежить тільки від того, як оператори порівняння ( <
, >
, ...) , а також як отримати / встановити-елемент ( [...]
реалізуються -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-булеве індексування):
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])
Зверніть увагу, що це лише одна можливість. Ви можете реалізувати майже все, що забажаєте.