Tôi đã xem qua một số mã có dòng tương tự như
x[x<2]=0
Chơi với các biến thể, tôi vẫn còn bị mắc kẹt về những gì cú pháp này làm.
Ví dụ:
>>> 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]
Tôi đã xem qua một số mã có dòng tương tự như
x[x<2]=0
Chơi với các biến thể, tôi vẫn còn bị mắc kẹt về những gì cú pháp này làm.
Ví dụ:
>>> 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()
.
Câu trả lời:
Điều này chỉ có ý nghĩa với mảng NumPy . Hành vi với danh sách là vô dụng và dành riêng cho Python 2 (không phải Python 3). Bạn có thể muốn kiểm tra lại xem đối tượng ban đầu có thực sự là một mảng NumPy (xem thêm bên dưới) và không phải là một danh sách.
Nhưng trong mã của bạn ở đây, x là một danh sách đơn giản.
Từ
x < 2
là Sai tức là 0, do đó
x[x<2]
Là x[0]
x[0]
được thay đổi.
Ngược lại, x[x>2]
là x[True]
hoặcx[1]
Vì vậy, x[1]
được thay đổi.
Lý do tại sao điều này xảy ra?
Các quy tắc để so sánh là:
Khi bạn đặt hàng hai chuỗi hoặc hai kiểu số, thứ tự được thực hiện theo cách mong đợi (thứ tự từ vựng cho chuỗi, thứ tự số cho số nguyên).
Khi bạn đặt hàng kiểu số và không phải kiểu số, kiểu số sẽ xuất hiện trước.
Khi bạn đặt hàng hai loại không tương thích mà không phải là số, chúng được sắp xếp theo thứ tự bảng chữ cái của tên loại của chúng:
Vì vậy, chúng tôi có đơn đặt hàng sau
số <danh sách <chuỗi <tuple
Xem câu trả lời được chấp nhận cho Python so sánh chuỗi và int như thế nào? .
Nếu x là một mảng NumPy , thì cú pháp có ý nghĩa hơn vì lập chỉ mục mảng boolean . Trong trường hợp đó, x < 2
không phải là boolean; đó là một mảng boolean đại diện cho việc mỗi phần tử x
có nhỏ hơn 2. x[x < 2] = 0
sau đó chọn các phần tử x
nhỏ hơn 2 và đặt các ô đó thành 0. Xem Lập chỉ mục .
>>> 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
cho numpy.
[0 if i < 2 else i for i in x]
,.) Hay đây là phong cách được khuyến khích trong Numpy?
x[x<2]
sẽ trả về một mảng numpy, trong khi [0 if i<2 else i for i in x]
trả về một danh sách. Điều này là do x[x<2]
là một hoạt động lập chỉ mục (được gọi trong numpy / scipy / pandas là một hoạt động cắt do khả năng che giấu dữ liệu), trong khi khả năng hiểu danh sách là một định nghĩa đối tượng mới. Xem lập chỉ mục NumPy
>>> x = [1,2,3,4,5]
>>> x<2
False
>>> x[False]
1
>>> x[True]
2
Bool chỉ được chuyển đổi thành một số nguyên. Chỉ số là 0 hoặc 1.
x
và 2
được " sắp xếp nhất quán nhưng tùy ý " và thứ tự có thể thay đổi trong các triển khai Python khác nhau.
x<2 == false
?
bool
không được chuyển đổi sang một số nguyên, một bool
trong Python là một số nguyên
bool
là một lớp con của int
.
Mã gốc trong câu hỏi của bạn chỉ hoạt động trong Python 2. Nếu x
là một list
trong Python 2, thì so sánh x < y
là False
nếu y
là một int
eger. Điều này là do việc so sánh một danh sách với một số nguyên không có ý nghĩa. Tuy nhiên trong Python 2, nếu các toán hạng không thể so sánh được, thì việc so sánh dựa trên CPython dựa trên thứ tự bảng chữ cái của tên các loại ; Ngoài ra, tất cả các số đều đứng đầu trong các so sánh kiểu hỗn hợp . Điều này thậm chí còn không được nêu trong tài liệu của CPython 2 và các triển khai Python 2 khác nhau có thể cho các kết quả khác nhau. Điều đó được [1, 2, 3, 4, 5] < 2
đánh giá là False
vì 2
là một số và do đó "nhỏ hơn" so với một list
trong CPython. Sự so sánh hỗn hợp này cuối cùng đãđược coi là một tính năng quá tối nghĩa và đã bị loại bỏ trong Python 3.0.
Bây giờ, kết quả <
là a bool
; và bool
là một lớp con củaint
:
>>> isinstance(False, int)
True
>>> isinstance(True, int)
True
>>> False == 0
True
>>> True == 1
True
>>> False + 5
5
>>> True + 5
6
Vì vậy, về cơ bản bạn đang lấy phần tử 0 hoặc 1 tùy thuộc vào việc so sánh là đúng hay sai.
Nếu bạn thử mã ở trên bằng Python 3, bạn sẽ nhận được TypeError: unorderable types: list() < int()
do sự thay đổi trong Python 3.0 :
So sánh đơn hàng
Python 3.0 đã đơn giản hóa các quy tắc để so sánh thứ tự:
Các nhà khai thác đặt hàng so sánh (
<
,<=
,>=
,>
) nâng cao mộtTypeError
ngoại lệ khi các toán hạng không có một trật tự tự nhiên có ý nghĩa. Do đó, các biểu thức như1 < ''
,0 > None
hoặclen <= len
không còn hợp lệ, và ví dụ nhưNone < None
tăng lênTypeError
thay vì trả vềFalse
. Một hệ quả tất yếu là việc sắp xếp một danh sách không đồng nhất không còn hợp lý nữa - tất cả các phần tử phải được so sánh với nhau. Lưu ý rằng điều này không áp dụng cho toán tử==
and!=
: các đối tượng thuộc các kiểu không thể so sánh khác nhau luôn so sánh không bình đẳng với nhau.
Có nhiều kiểu dữ liệu làm quá tải các toán tử so sánh để thực hiện một điều gì đó khác biệt (khung dữ liệu từ gấu trúc, mảng của numpy). Nếu mã mà bạn đang sử dụng đã làm cái gì khác, đó là vì x
đã không phải là mộtlist
, nhưng một thể hiện của một số lớp khác với nhà điều hành <
ghi đè để trả về một giá trị mà không phải là một bool
; và giá trị này sau đó đã được xử lý đặc biệt bởi x[]
(aka __getitem__
/ __setitem__
)
+False
Xin chào Perl, xin chào JavaScript, bạn khỏe không?
UNARY_POSITIVE
opcode mà các cuộc gọi__pos__
__setitem__
thay vì __getitem__
trong phần cuối cùng của bạn. Ngoài ra, tôi hy vọng bạn không phiền vì câu trả lời của tôi được lấy cảm hứng từ phần câu trả lời của bạn.
__getitem__
mặc dù không kém có thể là __setitem__
và__delitem__
Cái này có một công dụng nữa: chơi gôn mã. Code golf là nghệ thuật viết các chương trình giải quyết một số vấn đề với càng ít byte mã nguồn càng tốt.
return(a,b)[c<d]
gần tương đương với
if c < d:
return b
else:
return a
ngoại trừ việc cả a và b đều được đánh giá trong phiên bản đầu tiên, nhưng không được đánh giá trong phiên bản thứ hai.
c<d
đánh giá True
hoặc False
.
(a, b)
là một tuple.
Lập chỉ mục trên tuple hoạt động giống như lập chỉ mục trên danh sách: (3,5)[1]
== 5
.
True
là bằng 1
và False
bằng với 0
.
(a,b)[c<d]
(a,b)[True]
(a,b)[1]
b
hoặc cho False
:
(a,b)[c<d]
(a,b)[False]
(a,b)[0]
a
Có một danh sách tốt trên mạng trao đổi ngăn xếp gồm nhiều thứ khó chịu mà bạn có thể làm với python để tiết kiệm một vài byte. /codegolf/54/tips-for-golfing-in-python
Mặc dù trong mã thông thường, điều này không bao giờ nên được sử dụng và trong trường hợp của bạn, nó có nghĩa là nó x
hoạt động như một thứ có thể được so sánh với một số nguyên và như một vùng chứa hỗ trợ cắt, đây là một sự kết hợp rất bất thường. Nó có thể là mã Numpy, như những người khác đã chỉ ra.
Code Golf is the art of writing programs
: ')
Nói chung nó có thể có nghĩa là bất cứ điều gì . Nó đã giải thích ý nghĩa của nó nếu x
là một list
hay numpy.ndarray
nhưng nói chung nó chỉ phụ thuộc vào cách các toán tử so sánh ( <
, >
, ...) và cũng là get / set-item (cách [...]
-syntax) được thực hiện.
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!
Bởi vì:
x < value
tương đương với x.__lt__(value)
x[value]
tương đương với x.__getitem__(value)
x[value] = othervalue
là (cũng gần đúng) tương đương với x.__setitem__(value, othervalue)
.Điều này có thể được tùy chỉnh để làm bất cứ điều gì bạn muốn. Chỉ là một ví dụ (bắt chước lập chỉ mục numpys-boolean một chút):
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
Vì vậy, bây giờ hãy xem điều gì sẽ xảy ra nếu bạn sử dụng nó:
>>> 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])
Lưu ý rằng đây chỉ là một khả năng. Bạn có thể tự do thực hiện hầu hết mọi thứ bạn muốn.