ฉันเจอรหัสที่มีบรรทัดคล้ายกับ
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คือFalseif yเป็นinteger เนื่องจากการเปรียบเทียบรายการกับจำนวนเต็มไม่สมเหตุสมผล อย่างไรก็ตามในหลาม 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ยกแทนที่จะกลับTypeErrorFalseข้อสรุปคือการจัดเรียงรายการที่แตกต่างกันไม่สมเหตุสมผลอีกต่อไปองค์ประกอบทั้งหมดจะต้องเทียบเคียงซึ่งกันและกัน โปรดทราบว่าสิ่งนี้ใช้ไม่ได้กับตัวดำเนินการ==และ!=: ออบเจ็กต์ของประเภทที่หาที่เปรียบไม่ได้ที่แตกต่างกันจะเปรียบเทียบไม่เท่ากันเสมอ
มีประเภทข้อมูลจำนวนมากที่โอเวอร์โหลดตัวดำเนินการเปรียบเทียบเพื่อทำบางสิ่งที่แตกต่างออกไป (ดาต้าเฟรมจากแพนด้าอาร์เรย์ของ numpy) ถ้ารหัสที่คุณได้ใช้ทำอย่างอื่นมันเป็นเพราะxเป็นไม่ได้เป็นlistแต่ตัวอย่างของการเรียนอื่น ๆ บางอย่างกับผู้ประกอบการ<แทนที่ที่จะกลับค่าที่ไม่เป็นbool; และจากนั้นค่านี้ได้รับการจัดการโดยเฉพาะโดยx[](aka __getitem__/ __setitem__)
+Falseสวัสดี Perl เฮ้ JavaScript ทำอย่างไร?
UNARY_POSITIVEopcode ที่เรียก__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
True1False0
(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])
สังเกตว่านี่เป็นเพียงความเป็นไปได้อย่างหนึ่ง คุณมีอิสระที่จะใช้เกือบทุกอย่างที่คุณต้องการ