Я наткнулся на код со строкой, похожей на
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]
python
python-2.7
numpy
абергер
источник
источник
TypeError: unorderable types: list() < int()
.Ответы:
Это имеет смысл только с массивами 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]
меняется.Почему это происходит?
Правила для сравнения:
Когда вы заказываете две строки или два числовых типа, упорядочение выполняется ожидаемым образом (лексикографический порядок для строки, числовой порядок для целых чисел).
Когда вы заказываете числовой и нечисловой типы, числовой тип идет первым.
Когда вы заказываете два несовместимых типа, где ни один из них не является числовым, они упорядочиваются в алфавитном порядке их имен типов:
Итак, имеем следующий порядок
числовой <список <строка <кортеж
См. Принятый ответ на вопрос, как 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
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
Bool просто преобразуется в целое число. Индекс равен 0 или 1.
источник
x
и2
они « упорядочены последовательно, но произвольно » и что порядок может меняться в разных реализациях Python.x<2 == false
?bool
не преобразуется в целое число, abool
в 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.Теперь результат
<
: abool
; и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 :Есть много типов данных, которые перегружают операторы сравнения, чтобы делать что-то другое (фреймы данных из панд, массивы numpy). Если код , который вы использовали сделал что - то еще, это было потому , что
x
был неlist
, но с экземпляром некоторого другого класса с оператором<
переопределены вернуть значение, которое не являетсяbool
; и это значение затем было обработано специальноx[]
(также известное как__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
но в целом это зависит только от того, как операторы сравнения (<
,>
, ...) , а также как получить / установить-элемент ([...]
реализуются -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])
Обратите внимание, это всего лишь одна возможность. Вы можете реализовать практически все, что захотите.
источник