ฉันเจอรหัสที่มีบรรทัดคล้ายกับ
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 เป็นรายการธรรมดา
ตั้งแต่
x < 2
เป็นเท็จคือ 0 ดังนั้น
x[x<2]
คือ x[0]
x[0]
ได้รับการเปลี่ยนแปลง
ในทางกลับกันx[x>2]
คือx[True]
หรือx[1]
ดังนั้นการx[1]
เปลี่ยนแปลง
ทำไมสิ่งนี้ถึงเกิดขึ้น?
กฎสำหรับการเปรียบเทียบคือ:
เมื่อคุณสั่งซื้อสองสตริงหรือสองประเภทตัวเลขการเรียงลำดับจะดำเนินการในลักษณะที่คาดไว้ (การจัดลำดับพจนานุกรมสำหรับสตริงการเรียงลำดับตัวเลขสำหรับจำนวนเต็ม)
เมื่อคุณเรียงลำดับตัวเลขและประเภทที่ไม่ใช่ตัวเลขประเภทตัวเลขจะมาก่อน
เมื่อคุณสั่งซื้อสองประเภทที่เข้ากันไม่ได้โดยที่ทั้งสองประเภทไม่เป็นตัวเลขจะเรียงลำดับตามลำดับตัวอักษรของชื่อประเภท
ดังนั้นเราจึงมีคำสั่งดังต่อไปนี้
ตัวเลข <list <string <tuple
ดูคำตอบที่ยอมรับสำหรับ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
จำนวน
[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
มี" สั่งซื้ออย่างต่อเนื่อง แต่พล "และการสั่งซื้ออาจมีการเปลี่ยนแปลงในการใช้งานที่แตกต่างกันหลาม
x<2 == false
?
bool
ไม่ถูกแปลงเป็นจำนวนเต็ม a bool
ใน Python เป็นจำนวนเต็ม
bool
เป็น subclassint
ของ
รหัสเดิมในคำถามของคุณใช้ได้เฉพาะใน Python 2 เท่านั้นหากx
เป็นlist
ใน Python 2 การเปรียบเทียบx < y
คือFalse
if y
เป็นint
eger เนื่องจากการเปรียบเทียบรายการกับจำนวนเต็มไม่สมเหตุสมผล อย่างไรก็ตามในหลาม 2 ถ้าตัวถูกดำเนินการจะไม่ได้เปรียบเปรียบเทียบอยู่ใน CPython ในการสั่งซื้อตามตัวอักษรของชื่อหรือประเภทที่ ; นอกจากนี้ตัวเลขทั้งหมดมาเป็นครั้งแรกในรถผสมชนิด สิ่งนี้ไม่ได้สะกดไว้ในเอกสารของ CPython 2 และการใช้งาน Python 2 ที่แตกต่างกันอาจให้ผลลัพธ์ที่แตกต่างกัน ที่[1, 2, 3, 4, 5] < 2
ประเมินเป็นFalse
เพราะ2
เป็นตัวเลขจึง "เล็กกว่า" list
ใน CPython การเปรียบเทียบแบบผสมนี้ในที่สุดถือว่าเป็นคุณลักษณะที่คลุมเครือเกินไปและถูกลบออกใน Python 3.0
ตอนนี้ผลลัพธ์ของ<
คือ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
ข้อสรุปคือการจัดเรียงรายการที่แตกต่างกันไม่สมเหตุสมผลอีกต่อไปองค์ประกอบทั้งหมดจะต้องเทียบเคียงซึ่งกันและกัน โปรดทราบว่าสิ่งนี้ใช้ไม่ได้กับตัวดำเนินการ==
และ!=
: ออบเจ็กต์ของประเภทที่หาที่เปรียบไม่ได้ที่แตกต่างกันจะเปรียบเทียบไม่เท่ากันเสมอ
มีประเภทข้อมูลจำนวนมากที่โอเวอร์โหลดตัวดำเนินการเปรียบเทียบเพื่อทำบางสิ่งที่แตกต่างออกไป (ดาต้าเฟรมจากแพนด้าอาร์เรย์ของ numpy) ถ้ารหัสที่คุณได้ใช้ทำอย่างอื่นมันเป็นเพราะx
เป็นไม่ได้เป็นlist
แต่ตัวอย่างของการเรียนอื่น ๆ บางอย่างกับผู้ประกอบการ<
แทนที่ที่จะกลับค่าที่ไม่เป็นbool
; และจากนั้นค่านี้ได้รับการจัดการโดยเฉพาะโดยx[]
(aka __getitem__
/ __setitem__
)
+False
สวัสดี Perl เฮ้ JavaScript ทำอย่างไร?
UNARY_POSITIVE
opcode ที่เรียก__pos__
__setitem__
แทนที่จะ__getitem__
อยู่ในส่วนสุดท้ายของคุณ ฉันหวังว่าคุณจะไม่ทราบว่าคำตอบของฉันได้รับแรงบันดาลใจจากส่วนนั้นของคำตอบของคุณ
__getitem__
จะเป็นไปได้อย่างเท่าเทียมกัน__setitem__
และ__delitem__
สิ่งนี้มีประโยชน์อีกอย่างหนึ่ง: code golf Code golf เป็นศิลปะในการเขียนโปรแกรมที่ช่วยแก้ปัญหาโดยใช้ซอร์สโค้ดไบต์น้อยที่สุด
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)
เทียบเท่ากับซึ่งสามารถปรับแต่งให้ทำอะไรก็ได้ที่คุณต้องการ เช่นเดียวกับตัวอย่าง (เลียนแบบการสร้างดัชนีแบบบูลีนบิต):
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])
สังเกตว่านี่เป็นเพียงความเป็นไปได้อย่างหนึ่ง คุณมีอิสระที่จะใช้เกือบทุกอย่างที่คุณต้องการ