ทำไมไพ ธ อนไม่มีฟังก์ชั่นสัญญาณ?


241

ฉันไม่เข้าใจว่าทำไม Python จึงไม่มีsignฟังก์ชั่น มันมีabsในตัว (ซึ่งผมคิดว่าsignน้องสาว) signแต่ไม่มี

ใน python 2.6 มีcopysignฟังก์ชั่น (ในทางคณิตศาสตร์ ) แต่ไม่มีสัญญาณ ทำไมต้องเขียน a copysign(x,y)เมื่อคุณสามารถเขียน a signและได้รับcopysignโดยตรงจากabs(x) * sign(y)? หลังจะชัดเจนกว่านี้มาก: x ด้วยสัญลักษณ์ของ y ในขณะที่ copysign คุณต้องจำไว้ว่าถ้ามันเป็น x กับสัญลักษณ์ของ y หรือ y ด้วยสัญลักษณ์ของ x!

เห็นได้ชัดsign(x)ว่าไม่ได้ให้อะไรมากไปกว่าcmp(x,0)แต่มันจะอ่านได้ง่ายกว่านี้อีกด้วย (และสำหรับภาษาที่อ่านได้อย่างมากเช่นไพ ธ อนมันน่าจะเป็นข้อดีอย่างมาก)

ถ้าฉันเป็นนักออกแบบหลามผมจะได้รับวิธีการอื่น ๆ arond: ไม่มีcmpbuiltin signแต่ เมื่อคุณต้องการcmp(x,y)คุณสามารถทำsign(x-y)(หรือดียิ่งขึ้นสำหรับสิ่งที่ไม่ใช่ตัวเลขเพียงแค่ x> y - แน่นอนว่าสิ่งนี้ต้องได้sortedรับการยอมรับบูลีนแทนที่จะเป็นตัวเปรียบเทียบจำนวนเต็ม) สิ่งนี้จะมีความชัดเจนมากขึ้น: เป็นบวกเมื่อx>y(ในขณะที่cmpคุณต้องจำการประชุมเชิงบวกเมื่อแรกมีขนาดใหญ่กว่าแต่อาจเป็นวิธีอื่น ๆ ) แน่นอนว่ามีcmpเหตุผลในตัวเองสำหรับเหตุผลอื่น ๆ (เช่นเมื่อเรียงลำดับสิ่งที่ไม่ใช่ตัวเลขหรือหากคุณต้องการเรียงลำดับให้มีความเสถียรซึ่งไม่สามารถใช้กับบูลีนได้)

ดังนั้นคำถามคือ: ทำไมผู้ออกแบบ Python ตัดสินใจเลิกsignฟังก์ชั่นนอกภาษา ทำไมห่าก็รบกวนด้วยcopysignและไม่ใช่พ่อแม่sign?

ฉันพลาดอะไรไปรึเปล่า?

แก้ไข - หลังจากความคิดเห็นของ Peter Hansen ยุติธรรมพอที่คุณไม่ได้ใช้ แต่คุณไม่ได้พูดในสิ่งที่คุณใช้หลาม ใน 7 ปีที่ฉันใช้หลามฉันต้องการมันนับครั้งไม่ถ้วนและอันสุดท้ายคือฟางที่หักหลังอูฐ!

ใช่คุณสามารถผ่าน cmp ไปได้ แต่ 90% ของจำนวนครั้งที่ฉันต้องผ่านมันเป็นสำนวนแบบ lambda x,y: cmp(score(x),score(y))ที่จะใช้กับสัญญาณได้ดี

ในที่สุดฉันหวังว่าคุณจะเห็นว่าsignจะมีประโยชน์มากกว่าcopysignดังนั้นแม้ว่าฉันจะซื้อมุมมองของคุณทำไมต้องกังวลกับการกำหนดในคณิตศาสตร์แทนที่จะเป็นสัญญาณ? copysign มีประโยชน์มากกว่าเครื่องหมายอย่างไร


33
@dmazzoni: อาร์กิวเมนต์นี้ใช้ไม่ได้สำหรับคำถามทั้งหมดในไซต์นี้หรือไม่ เพียงแค่ปิด stackoverflow และถามคำถามทุกข้อไปยัง dev หัวข้อที่เกี่ยวข้องหรือรายชื่อผู้รับจดหมายของผู้ใช้!
Davide

43
สถานที่ที่เหมาะสมสำหรับคำถามคือสถานที่ที่น่าจะได้รับคำตอบ ดังนั้น stackoverflow เป็นสถานที่ที่เหมาะสม
Stefano Borini

23
-1: @Davide: "ทำไม" และ "ทำไมไม่ใช่" โดยทั่วไปแล้วคำถามไม่สามารถตอบได้ที่นี่ เนื่องจากผู้บริหารส่วนใหญ่ของการพัฒนา Python ไม่ตอบคำถามที่นี่คุณจึงไม่ค่อยได้รับคำตอบสำหรับคำถาม "ทำไม" หรือ "ทำไมไม่" นอกจากนี้คุณไม่มีปัญหาในการแก้ไข คุณฟังดูเหมือนคุณมีคำโม้ หากคุณมีปัญหา ("ฉันจะหลีกเลี่ยงการลงชื่อเข้าใช้ในตัวอย่างนี้ได้อย่างไร ... ") ที่สมเหตุสมผล "ทำไมไม่" ไม่สมเหตุสมผลสำหรับสถานที่นี้
S.Lott

31
คำถามอาจมีอารมณ์เล็กน้อย แต่ฉันไม่คิดว่ามันเป็นคำถามที่ไม่ดี ฉันแน่ใจว่าผู้คนจำนวนมากมองหาฟังก์ชั่นสัญญาณในตัวดังนั้นจึงสงสัยได้ว่าทำไมไม่มี
FogleBird

17
นี่เป็นคำถามที่มีวัตถุประสงค์อย่างสมบูรณ์แบบ:“ ทำไม” Python ขาดคุณสมบัติใด ๆ ที่เป็นคำถามที่ถูกต้องเกี่ยวกับประวัติความเป็นมาของการออกแบบภาษาที่สามารถตอบได้โดยการเชื่อมโยงไปยังการสนทนาที่เหมาะสมจาก python-dev หรือฟอรัมอื่น ๆ นักพัฒนาหลักเกิดแฮชหัวข้อ ก่อนหน้านี้ฉันได้ลองใช้ Google เพื่อหาข้อมูลประวัติศาสตร์ใน python-dev ด้วยตัวเองฉันสามารถเข้าใจได้ว่าทำไมผู้ใช้ใหม่ถึงภาษาอาจถึงจุดจบและมาถามที่นี่เพื่อหวังว่าจะได้รับคำตอบจาก Python ที่มีประสบการณ์มากกว่า!
แบรนดอนโรดส์

คำตอบ:


228

แก้ไข:

อันที่จริงมีการปะแก้ซึ่งรวมอยู่sign()ในคณิตศาสตร์แต่ไม่ได้รับการยอมรับเพราะพวกเขาไม่เห็นด้วยกับสิ่งที่มันควรจะกลับมาในทุกกรณีขอบ (+/- 0, +/- น่าน ฯลฯ )

ดังนั้นพวกเขาจึงตัดสินใจที่จะใช้เพียง copysign ซึ่ง (แม้ว่าเพิ่มเติม verbose) สามารถใช้ในการมอบหมายให้กับผู้ใช้พฤติกรรมที่ต้องการสำหรับกรณีขอบ - ซึ่งบางครั้งอาจจำเป็นต้องเรียกร้องให้cmp(x,0)


ฉันไม่รู้ว่าทำไมมันถึงไม่ใช่ตัว แต่ฉันมีความคิด

copysign(x,y):
Return x with the sign of y.

ที่สำคัญที่สุดcopysignคือ superset ของsign! การโทรcopysignด้วย x = 1 เหมือนกับsignฟังก์ชั่น ดังนั้นคุณสามารถใช้copysignและลืมมันได้

>>> math.copysign(1, -4)
-1.0
>>> math.copysign(1, 3)
1.0

หากคุณเบื่อที่จะผ่านการโต้แย้งทั้งสองคุณสามารถใช้signวิธีนี้และมันจะยังคงเข้ากันได้กับสิ่งที่ IEEE กล่าวถึงโดยผู้อื่น:

>>> sign = functools.partial(math.copysign, 1) # either of these
>>> sign = lambda x: math.copysign(1, x) # two will work
>>> sign(-4)
-1.0
>>> sign(3)
1.0
>>> sign(0)
1.0
>>> sign(-0.0)
-1.0
>>> sign(float('nan'))
-1.0

ประการที่สองโดยปกติเมื่อคุณต้องการสัญลักษณ์ของบางสิ่งคุณก็แค่คูณมันด้วยค่าอื่น และแน่นอนว่าเป็นสิ่งที่copysignทำ

ดังนั้นแทนที่จะ:

s = sign(a)
b = b * s

คุณสามารถทำได้:

b = copysign(b, a)

และใช่ฉันประหลาดใจที่คุณใช้ Python เป็นเวลา 7 ปีและคิดว่าcmpสามารถลบออกได้ง่ายและแทนที่ด้วยsign! คุณไม่เคยใช้คลาสด้วย__cmp__วิธีการหรือไม่? คุณไม่เคยโทรหาcmpและระบุฟังก์ชั่นเครื่องมือเปรียบเทียบแบบกำหนดเองหรือไม่?

โดยสรุปแล้วฉันก็พบว่าตัวเองต้องการsignฟังก์ชั่นเหมือนกัน แต่copysignด้วยข้อโต้แย้งแรกว่า 1 จะใช้ได้ดี ฉันไม่เห็นด้วยที่signจะมีประโยชน์มากกว่าcopysignที่ฉันแสดงให้เห็นว่ามันเป็นเพียงส่วนหนึ่งของฟังก์ชั่นเดียวกัน


35
ใช้ให้[int(copysign(1, zero)) for zero in (0, 0.0, -0.0)] [1, 1, -1]ที่ควรได้รับ[0, 0, 0]ตามen.wikipedia.org/wiki/Sign_function
user238424

12
@Andrew - คำสั่งการโทรของ @ user238424 ถูกต้อง copysign(a,b)ส่งกลับ a ด้วยเครื่องหมายของ b - b คืออินพุตที่แตกต่างกัน a คือค่าที่จะทำให้เป็นมาตรฐานด้วยสัญลักษณ์ของ b ในกรณีนี้ผู้แสดงความคิดเห็นแสดงให้เห็นว่า copysign (1, x) แทนการลงชื่อ (x) ล้มเหลวเนื่องจากมันส่งคืน 1 สำหรับ x = 0 ในขณะที่เครื่องหมาย (0) จะประเมินเป็น 0
PaulMcG

7
ทุ่นลอยถือ "เครื่องหมาย" แยกต่างหากจาก "ค่า"; -0.0 เป็นจำนวนลบแม้ว่าดูเหมือนว่าจะมีข้อผิดพลาดในการใช้งาน เพียงแค่ใช้cmp()จะให้ผลลัพธ์ที่ต้องการอาจจะเกือบทุกกรณีทุกคนจะดูแลเกี่ยวกับ: ==>[cmp(zero, 0) for zero in (0, 0.0, -0.0, -4, 5)] [0, 0, 0, -1, 1]
pythonlarry

11
s = sign(a) b = b * sไม่เท่ากับb = copysign(b, a)! ไม่พิจารณาสัญลักษณ์ของ b เช่นถ้าa=b=-1รหัสแรกจะส่งกลับ 1 ในขณะที่สองส่งคืน -1
Johannes Jendersie

14
การดูคำจำกัดความการแทนที่ที่ผิดพลาดการเทียบเท็จสำหรับการคูณด้วยเครื่องหมาย (a) คำอธิบายที่ผิดสำหรับแรงจูงใจของ copysign และการแทนที่ที่ถูกต้อง "cmp (x, 0)" ถูกกล่าวถึงในคำถามแล้ว - มี ข้อมูลไม่มากและมันก็ไม่ชัดเจนสำหรับฉันว่าทำไมคำตอบนี้คือ "ยอมรับ" ด้วยคะแนนโหวตมากมาย
kxr

59

"copysign" ถูกกำหนดโดย IEEE 754 และเป็นส่วนหนึ่งของข้อกำหนด C99 นั่นเป็นเหตุผลที่อยู่ในหลาม ไม่สามารถใช้งานฟังก์ชั่นเต็มรูปแบบโดยเครื่องหมาย abs (x) * (y) ได้เนื่องจากวิธีที่ควรจัดการกับค่า NaN

>>> import math
>>> math.copysign(1, float("nan"))
1.0
>>> math.copysign(1, float("-nan"))
-1.0
>>> math.copysign(float("nan"), 1)
nan
>>> math.copysign(float("nan"), -1)
nan
>>> float("nan") * -1
nan
>>> float("nan") * 1
nan
>>> 

ซึ่งทำให้ copysign () เป็นฟังก์ชันที่มีประโยชน์มากกว่า sign ()

สำหรับเหตุผลเฉพาะที่ทำให้การลงชื่อ (x) ของ IEEE ไม่สามารถใช้งานได้ใน Python มาตรฐานฉันไม่รู้ ฉันสามารถตั้งสมมติฐานได้ แต่มันจะเป็นการคาดเดา

โมดูลคณิตศาสตร์เองใช้ copysign (1, x) เป็นวิธีการตรวจสอบว่า x เป็นลบหรือไม่ลบ สำหรับกรณีส่วนใหญ่ที่เกี่ยวข้องกับฟังก์ชันทางคณิตศาสตร์ที่ดูเหมือนว่ามีประโยชน์มากกว่าการมีเครื่องหมาย (x) ซึ่งส่งกลับค่า 1, 0 หรือ -1 เนื่องจากมีกรณีน้อยกว่าที่ต้องพิจารณา ตัวอย่างเช่นต่อไปนี้มาจากโมดูลคณิตศาสตร์ของ Python:

static double
m_atan2(double y, double x)
{
        if (Py_IS_NAN(x) || Py_IS_NAN(y))
                return Py_NAN;
        if (Py_IS_INFINITY(y)) {
                if (Py_IS_INFINITY(x)) {
                        if (copysign(1., x) == 1.)
                                /* atan2(+-inf, +inf) == +-pi/4 */
                                return copysign(0.25*Py_MATH_PI, y);
                        else
                                /* atan2(+-inf, -inf) == +-pi*3/4 */
                                return copysign(0.75*Py_MATH_PI, y);
                }
                /* atan2(+-inf, x) == +-pi/2 for finite x */
                return copysign(0.5*Py_MATH_PI, y);

ที่นั่นคุณสามารถเห็นได้อย่างชัดเจนว่า copysign () เป็นฟังก์ชันที่มีประสิทธิภาพมากกว่าฟังก์ชั่นเครื่องหมายสามค่า ()

คุณเขียน:

ถ้าฉันเป็นนักออกแบบงูหลามฉันก็คงจะเป็นคนอื่น: ไม่มี cmp () ในตัว แต่เป็นเครื่องหมาย ()

หมายความว่าคุณไม่ทราบว่า cmp () ใช้สำหรับสิ่งอื่นนอกเหนือจากตัวเลข cmp ("This", "That") ไม่สามารถใช้งานร่วมกับฟังก์ชัน sign ()

แก้ไขเพื่อเปรียบเทียบคำตอบเพิ่มเติมของฉันที่อื่น :

คุณยึดหลักเหตุผลในการที่ abs () และเครื่องหมาย () ปรากฏบ่อยครั้งด้วยกัน เนื่องจากไลบรารีมาตรฐาน C ไม่มีฟังก์ชัน 'sign (x)' ของการเรียงลำดับใด ๆ ฉันไม่ทราบว่าคุณปรับความคิดเห็นของคุณอย่างไร มี abs (int) และ fabs (double) และ fabsf (float) และ fabsl (ยาว) แต่ไม่มีการกล่าวถึงสัญลักษณ์ มี "copysign ()" และ "signbit ()" แต่จะใช้กับหมายเลข IEEE 754 เท่านั้น

ด้วยตัวเลขที่ซับซ้อนแล้วสิ่งที่จะลงนาม (-3 + 4j) ผลตอบแทนใน Python จะถูกนำไปใช้อย่างไร abs (-3 + 4j) ส่งคืน 5.0 นี่เป็นตัวอย่างที่ชัดเจนว่า abs () สามารถใช้ในสถานที่ที่เครื่องหมาย () ไม่สมเหตุสมผลได้อย่างไร

สมมติว่าเครื่องหมาย (x) ถูกเพิ่มใน Python เป็นส่วนเสริมของ abs (x) ถ้า 'x' เป็นตัวอย่างของคลาสที่ผู้ใช้กำหนดซึ่งใช้วิธี __abs __ (ตัวเอง) ดังนั้น abs (x) จะเรียก x .__ abs __ () เพื่อให้ทำงานได้อย่างถูกต้องเพื่อจัดการ abs (x) ด้วยวิธีเดียวกัน Python จะต้องได้รับช่องสัญญาณ (x)

สิ่งนี้มากเกินไปสำหรับฟังก์ชั่นที่ไม่จำเป็น นอกจากนี้ทำไมเครื่องหมาย (x) จึงมีอยู่และไม่ใช่ค่าลบ (x) และไม่ใช่เชิงลบ (x) ไม่มีอยู่? ตัวอย่างข้อมูลจากการใช้งานโมดูลทางคณิตศาสตร์ของ Python แสดงให้เห็นว่าสามารถใช้ copybit (x, y) เพื่อใช้งาน nonnegative () ได้อย่างไรซึ่งเครื่องหมายอย่างง่าย (x) ไม่สามารถทำได้

Python ควรสนับสนุนได้รับการสนับสนุนที่ดีกว่าสำหรับฟังก์ชันคณิตศาสตร์ของ IEEE 754 / C99 นั่นจะเป็นการเพิ่มฟังก์ชัน signbit (x) ซึ่งจะทำสิ่งที่คุณต้องการในกรณีของการลอยตัว มันจะใช้ไม่ได้กับจำนวนเต็มหรือจำนวนเชิงซ้อนสตริงที่น้อยกว่ามากและจะไม่มีชื่อที่คุณต้องการ

คุณถามว่า "ทำไม" และคำตอบคือ "สัญญาณ (x) ไม่มีประโยชน์" คุณยืนยันว่ามันมีประโยชน์ แต่ความคิดเห็นของคุณแสดงให้เห็นว่าคุณไม่มีความรู้เพียงพอที่จะสามารถยืนยันได้ซึ่งหมายความว่าคุณจะต้องแสดงหลักฐานที่น่าเชื่อถือเกี่ยวกับความต้องการของมัน การพูดว่า NumPy ใช้มันไม่น่าเชื่อเพียงพอ คุณจะต้องแสดงกรณีของการปรับปรุงรหัสที่มีอยู่ด้วยฟังก์ชั่นเครื่องหมาย

และมันอยู่นอกขอบเขตของ StackOverflow ใช้แทนรายการ Python อย่างใดอย่างหนึ่ง


5
ดีฉันไม่ได้ว่าจะทำให้คุณมีความสุข แต่งูหลาม 3 มีค่าcmp()มิได้sign():-)
แอนทอนพี

4
การเขียนฟังก์ชั่นสัญญาณที่ดี () ที่ทำงานได้อย่างถูกต้องกับ IEEE 754 นั้นไม่สำคัญ นี่จะเป็นจุดที่ดีที่จะรวมไว้ในภาษาแทนที่จะปล่อยให้มันออกมาแม้ว่าฉันจะไม่ได้อธิบายรายละเอียดของประเด็นนี้ในคำถาม
Davide

2
ความคิดเห็นของคุณเกี่ยวกับวิธี "ถ้าคุณต้องการจัดเรียงให้มีความเสถียร" หมายความว่าคุณยังไม่ทราบว่าการเรียงลำดับที่มีเสถียรภาพนั้นทำงานอย่างไร คำสั่งของคุณที่ copysign และเครื่องหมายเทียบเท่าแสดงว่าคุณไม่ได้รู้มากเกี่ยวกับคณิตศาสตร์ IEEE 754 ก่อนโพสต์นี้ Python ควรใช้ฟังก์ชันคณิตศาสตร์ 754 ทั้งหมดในแกนกลางหรือไม่ ควรทำอย่างไรกับคอมไพเลอร์ที่ไม่ใช่ C99 แพลตฟอร์มที่ไม่ใช่ 754? "isnonnegative" และ "isnonpositive" เป็นฟังก์ชันที่มีประโยชน์ Python ควรรวมสิ่งเหล่านี้ด้วยหรือไม่ abs (x) เลื่อนไปที่ x .__ abs __ () ดังนั้นควรลงชื่อ (x) เลื่อนไปที่ x .__ sign __ () หรือไม่ มีความต้องการหรือความต้องการเล็กน้อยดังนั้นทำไมมันควรติดอยู่ในแกน
Andrew Dalke

2
math.copysign (1, float ("- nan")) ส่งคืน 1.0 แทน -1.0 เมื่อฉันลองใช้ใน 2.7
dansalmo

34

อีกหนึ่งซับสำหรับเข้าสู่ระบบ ()

sign = lambda x: (1, -1)[x<0]

หากคุณต้องการให้ส่งคืน 0 สำหรับ x = 0:

sign = lambda x: x and (1, -1)[x<0]

1
ทำไม? คำถามนั้นยอมรับว่าcmp(x, 0)เทียบเท่าsignและlambda x: cmp(x, 0)อ่านได้ง่ายกว่าที่คุณแนะนำ
ToolmakerSteve

1
แน่นอนฉันผิด ฉันสันนิษฐานว่ามีการระบุ 'cmp' เพื่อส่งกลับ -1,0, + 1 แต่ฉันเห็นว่าข้อมูลจำเพาะไม่รับประกัน
ToolmakerSteve

สวย. ตอบคำถามที่เริ่มต้น: python int หรือ float เป็น -1, 0, 1?
scharfmn

1
มีข้อได้เปรียบในการใช้รายการแทน-1 if x < 0 else 1หรือไม่?
Mateen Ulhaq

6
sign = lambda x: -1 if x < 0 else 1เป็น15% ได้เร็วขึ้น sign = lambda x: x and (-1 if x < 0 else 1)เช่นเดียวกันกับ
Mateen Ulhaq

26

ตั้งแต่cmpถูกลบคุณสามารถใช้ฟังก์ชันการทำงานเดียวกันได้

def cmp(a, b):
    return (a > b) - (a < b)

def sign(a):
    return (a > 0) - (a < 0)

การทำงานสำหรับfloat, และแม้กระทั่งint Fractionในกรณีของการfloatแจ้งให้ทราบsign(float("nan"))เป็นศูนย์

Python ไม่ต้องการให้การเปรียบเทียบคืนค่าบูลีนและบังคับให้มีการเปรียบเทียบกับบูล () เพื่อป้องกันการอนุญาต แต่การใช้งานที่ผิดปกติ:

def sign(a):
    return bool(a > 0) - bool(a < 0)

13

คำตอบที่ถูกต้องสอดคล้องกับข้อกำหนดของ Wikipedia เท่านั้น

นิยามในวิกิพีเดียอ่าน:

คำจำกัดความของสัญญาณ

ดังนั้น

sign = lambda x: -1 if x < 0 else (1 if x > 0 else (0 if x == 0 else NaN))

ซึ่งสำหรับทุกเจตนาและวัตถุประสงค์อาจง่ายต่อการ:

sign = lambda x: -1 if x < 0 else (1 if x > 0 else 0)

คำจำกัดความของฟังก์ชันนี้ดำเนินการอย่างรวดเร็วและรับประกันผลลัพธ์ที่ถูกต้องสำหรับ 0, 0.0, -0.0, -4 และ 5 (ดูความคิดเห็นต่อคำตอบที่ไม่ถูกต้องอื่น ๆ )

โปรดทราบว่าศูนย์ (0) เป็นค่าบวกหรือเชิงลบ


1
คำตอบนี้แสดงให้เห็นว่างูหลามที่มี แต่รวบรัดสามารถทรงพลังได้อย่างไร
NelsonGon

1
การเล่นโวหาร: รหัสไม่ได้ใช้คำจำกัดความของ WP มันจะแทนที่ประโยคกลางด้วยประโยคเริ่มต้นที่สิ้นสุด ในขณะที่สิ่งนี้มีความจำเป็นในการจัดการกับตัวเลขที่ไม่ใช่ของจริงเช่นน่านมันจะแสดงอย่างไม่ถูกต้องตามคำสั่ง WP โดยตรง ('ดังนั้น')
Jürgen Strobel

1
@ JürgenStrobelฉันรู้ว่าคุณหมายถึงอะไรและฉันก็คิดมานานแล้ว ฉันขยายคำตอบตอนนี้เพื่อให้เป็นทางการที่ถูกต้องในขณะที่รักษาเวอร์ชันที่ง่ายสำหรับกรณีการใช้งานส่วนใหญ่
Serge Stroobandt

10

numpy มีฟังก์ชั่นสัญญาณและให้โบนัสฟังก์ชั่นอื่น ๆ เช่นกัน ดังนั้น:

import numpy as np
x = np.sign(y)

เพียงแค่ระวังว่าผลลัพธ์นั้นเป็น numpy.float64:

>>> type(np.sign(1.0))
<type 'numpy.float64'>

สำหรับสิ่งต่างๆเช่น json เรื่องนี้เนื่องจาก json ไม่ทราบวิธีการจัดลำดับประเภท numpy.float64 ในกรณีนั้นคุณสามารถทำได้:

float(np.sign(y))

เพื่อรับโฟลตปกติ


10

ลองใช้วิธีนี้โดยที่ x คือหมายเลขใด ๆ

int_sign = bool(x > 0) - bool(x < 0)

การข่มขู่เพื่อบูล () จัดการความเป็นไปได้ที่โอเปอเรเตอร์การเปรียบเทียบจะไม่ส่งคืนบูลีน


เป็นความคิดที่ดี แต่ฉันคิดว่าคุณหมายถึง: int_sign = int (x> 0) - int (x <0)
yucer

ฉันหมายถึง: int_sign = lambda x: (x> 0) - (x <0)
yucer

1
@ ไม่มีเลยเขาหมายถึงนักแสดงที่จะบูล (ซึ่งเป็น subclass ของ int อยู่แล้ว) เพราะความเป็นไปได้ทางทฤษฎีที่เขาให้การเชื่อมโยงกับคำอธิบาย
Walter Tross

ข้อเสียเพียงอย่างเดียวของโครงสร้างนี้คืออาร์กิวเมนต์ปรากฏขึ้นสองครั้งซึ่งใช้ได้เมื่อตัวแปรเป็นตัวเดียวเท่านั้น
Walter Tross

5

ใช่sign()ฟังก์ชั่นที่ถูกต้องควรเป็นอย่างน้อยในโมดูลคณิตศาสตร์ - เนื่องจากเป็นฟังก์ชัน เพราะบ่อยครั้งที่มันต้องการโค้ดเชิงคณิตศาสตร์

แต่math.copysign()ยังมีประโยชน์อย่างอิสระ

cmp()และobj.__cmp__()... โดยทั่วไปมีความสำคัญสูงอย่างอิสระ ไม่เพียง แต่สำหรับโค้ดเชิงคณิตศาสตร์ พิจารณาเปรียบเทียบ / เรียงลำดับสิ่งอันดับวัตถุวันที่ ...

อาร์กิวเมนต์ dev ที่http://bugs.python.org/issue1640เกี่ยวกับการละเว้นmath.sign()เป็นสิ่งแปลกเนื่องจาก:

  • ไม่มีการแยก -NaN
  • sign(nan) == nan โดยไม่ต้องกังวล (เช่นexp(nan))
  • sign(-0.0) == sign(0.0) == 0 โดยไม่ต้องกังวล
  • sign(-inf) == -1 โดยไม่ต้องกังวล

- ตามที่เป็นอยู่ใน numpy


4

ในหลาม 2 cmp()กลับจำนวนเต็ม: มีความต้องการว่าผลจะเป็น -1, 0, 1 หรือไม่ดังนั้นไม่ได้เช่นเดียวกับsign(x)cmp(x,0)

ใน Python 3 cmp()ถูกลบออกไปเนื่องจากการเปรียบเทียบที่สมบูรณ์ สำหรับcmp()Python 3 แนะนำสิ่งนี้ :

def cmp(a, b):
    return (a > b) - (a < b)

ซึ่งใช้ได้สำหรับ cmp () แต่ไม่สามารถใช้อีกครั้งสำหรับการลงชื่อ () เนื่องจากตัวดำเนินการเปรียบเทียบไม่จำเป็นต้องส่งคืนบูลี

เพื่อจัดการกับความเป็นไปได้นี้จะต้องมีการเปรียบเทียบผลการเปรียบเทียบกับบูลีน:

 def sign(a):
    return bool(x > 0) - bool(x < 0)

สิ่งนี้ใช้ได้กับสิ่งใดก็ตามtypeที่ได้รับคำสั่งทั้งหมด (รวมถึงค่าพิเศษเช่นNaNหรืออินฟินิตี้)


0

คุณไม่ต้องการใช้คุณสามารถใช้:

If not number == 0:
    sig = number/abs(number)
else:
    sig = 0

4
มันชี้ให้เห็นว่าx / abs(x)ใช้เวลานานกว่าการผูกมัดเพียงเล็กน้อยif/elseเพื่อตรวจสอบว่าตัวแปรใดที่อยู่บน 0 หรือสำหรับเรื่องนั้นโดยใช้ความลื่นไหลที่ตอบสนองreturn (x > 0) - (x < 0)ต่อการลบboolค่าและคืนค่าint

1
งูหลามขนมTrueและFalseเป็น1และ0คุณอย่างสามารถทำเช่นนี้และได้รับการอย่างใดอย่างหนึ่ง1, หรือ0 จะไม่ส่งคืน a มันจะส่งคืนถ้าคุณผ่านคุณจะได้รับคืน-1def sign(x): return (x > 0) - (x < 0)boolint00

0

มันแค่ทำไม่ได้

วิธีที่ดีที่สุดในการแก้ไขปัญหานี้คือ:

sign = lambda x: bool(x > 0) - bool(x < 0)

-8

เหตุผลที่ไม่รวมถึง "เครื่องหมาย" คือถ้าเรารวมหนึ่งซับที่มีประโยชน์ไว้ในรายการฟังก์ชั่นในตัว Python จะไม่ง่ายและใช้งานได้จริงอีกต่อไป ถ้าคุณใช้ฟังก์ชั่นนี้บ่อยๆทำไมคุณไม่แยกตัวมันออกมาเองล่ะ? มันไม่ใช่ว่ามันยากจากระยะไกลหรือน่าเบื่อที่จะทำ


6
ฉันจะซื้อมันก็ต่อเมื่อabs()ถูกทิ้งไว้ด้วย sign()และabs()มักจะใช้ร่วมกันsign()เป็นประโยชน์มากที่สุดของทั้งสอง (IMO) และไม่มีใครยากหรือน่าเบื่อในการติดตั้งจากระยะไกล (แม้ว่าจะมีข้อผิดพลาดเกิดขึ้นให้ดูว่าคำตอบนี้ผิดอย่างไร: stackoverflow.com/questions/1986152/ ...... )
Davide

1
สิ่งที่อยู่ที่ผลลัพธ์เชิงตัวเลขของsign()ตัวเองนั้นไม่ค่อยมีประโยชน์ สิ่งที่คุณทำส่วนใหญ่ใช้พา ธ ของรหัสที่แตกต่างกันโดยขึ้นอยู่กับว่าตัวแปรนั้นเป็นค่าบวกหรือค่าลบและในกรณีนี้คุณสามารถอ่านเงื่อนไขการเขียนได้ชัดเจนยิ่งขึ้น
Antoine P.

3
abs () ถูกใช้บ่อยกว่าเครื่องหมาย () และฉันก็ชี้ให้คุณไปที่ตัวติดตาม NumPy ซึ่งแสดงให้เห็นว่าเครื่องหมายยาก () สามารถนำไปใช้งานได้อย่างไร สิ่งที่ควรลงชื่อ (-3 + 4j) เป็นอย่างไร ในขณะที่ abs (-3 + 4j) คือ 5.0 คุณยืนยันว่าเครื่องหมาย () และ abs () ปรากฏบ่อยครั้งด้วยกัน ไลบรารี่มาตรฐาน C ไม่มีฟังก์ชั่น 'เครื่องหมาย' คุณจะได้รับข้อมูลของคุณอยู่ที่ไหน?
Andrew Dalke
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.