Я не могу понять, почему у Python нет sign
функции. Он имеет abs
встроенную функцию (которую я считаю sign
сестрой), но нет sign
.
В Python 2.6 есть даже copysign
функция (по математике ), но без знака. Зачем писать, copysign(x,y)
когда вы можете просто написать, sign
а затем получить copysign
непосредственно от abs(x) * sign(y)
? Последнее было бы намного понятнее: x со знаком y, тогда как с copysign вы должны помнить, если это x со знаком y или y со знаком x!
Очевидно sign(x)
, ничего более не дает cmp(x,0)
, но это было бы гораздо более читабельно, чем это тоже (и для очень удобочитаемого языка, такого как python, это было бы большим плюсом).
Если бы я был дизайнером Python, я был бы по-другому: не cmp
встроенный, а a sign
. Когда вам нужно cmp(x,y)
, вы можете просто сделать a sign(x-y)
(или, что еще лучше для нечисловых вещей, просто x> y - конечно, для этого нужно было sorted
принять логическое значение вместо целочисленного компаратора). Это также будет более ясно: положительным , когда x>y
( в то время как с cmp
вы должны помнить конвенции плюсовой , когда первый является большим , но это может быть наоборот). Конечно, cmp
имеет смысл сам по себе по другим причинам (например, при сортировке нечисловых вещей или если вы хотите, чтобы сортировка была стабильной, что невозможно использовать просто с логическим значением)
Итак, вопрос: почему разработчики Python решили оставить sign
функцию вне языка? Почему, черт возьми, беспокоиться, copysign
а не его родитель sign
?
Я что-то упускаю?
РЕДАКТИРОВАТЬ - после комментария Питера Хансена. Достаточно справедливо, что вы не использовали его, но вы не сказали, для чего вы используете python. За 7 лет, что я использую питон, я нуждался в нем бесчисленное количество раз, и последняя - соломинка, которая сломала спину верблюду!
Да, вы можете передавать cmp, но в 90% случаев, когда мне нужно было передать его, была такая идиома
lambda x,y: cmp(score(x),score(y))
, которая отлично работала бы со знаком.
Наконец, я надеюсь, что вы согласны с тем, что это sign
было бы более полезно, чем copysign
, поэтому, даже если бы я купил ваше мнение, зачем беспокоиться об определении этого в математике, а не в знаке? Как может copysign быть настолько полезным, чем sign?
источник
Ответы:
РЕДАКТИРОВАТЬ:
Действительно, был патч, который включал
sign()
в математику , но он не был принят, потому что они не согласились с тем, что он должен возвращать во всех крайних случаях (+/- 0, +/- nan и т. Д.)Поэтому они решили реализовать только copysign, который (хотя и более многословный) можно использовать для делегирования конечному пользователю желаемого поведения для крайних случаев - что иногда может потребовать вызова
cmp(x,0)
.Я не знаю, почему он не встроенный, но у меня есть некоторые мысли.
Самое главное,
copysign
это суперсет изsign
! Вызовcopysign
с x = 1 аналогичен вызовуsign
функции. Таким образом, вы можете просто использоватьcopysign
и забыть об этом .Если вам надоело передавать два целых аргумента, вы можете реализовать
sign
этот способ, и он все равно будет совместим с материалом IEEE, упомянутым другими:Во-вторых, обычно, когда вам нужен знак чего-либо, вы просто умножаете его на другое значение. И, конечно, это в основном то, что
copysign
делает.Итак, вместо:
Вы можете просто сделать:
И да, я удивлен, что вы используете Python 7 лет и думаете, что
cmp
его так легко удалить и заменить наsign
! Вы никогда не реализовывали класс с помощью__cmp__
метода? Вы никогда не вызывалиcmp
и не указывали пользовательскую функцию сравнения?Таким образом, я обнаружил, что тоже хочу
sign
функцию, ноcopysign
с первым аргументом 1 будет работать нормально. Я не согласен, что этоsign
было бы более полезно, чемcopysign
, поскольку я показал, что это просто подмножество той же функциональности.источник
[int(copysign(1, zero)) for zero in (0, 0.0, -0.0)]
дает[1, 1, -1]
. Это должно было быть в[0, 0, 0]
соответствии с en.wikipedia.org/wiki/Sign_functioncopysign(a,b)
возвращает a со знаком b - b - переменный ввод, a - значение, которое нужно нормализовать со знаком b. В этом случае комментатор иллюстрирует, что copysign (1, x) в качестве замены для sign (x) завершается неудачно, так как он возвращает 1 для x = 0, тогда как sign (0) будетcmp()
даст желаемые результаты, вероятно, почти для каждого случая, о котором все будут заботиться:[cmp(zero, 0) for zero in (0, 0.0, -0.0, -4, 5)]
==>[0, 0, 0, -1, 1]
.s = sign(a) b = b * s
не эквивалентноb = copysign(b, a)
! Это не считает знак б. Например, еслиa=b=-1
первый код вернет 1, в то время как второй вернет -1«copysign» определяется IEEE 754 и частью спецификации C99. Вот почему это в Python. Функция не может быть полностью реализована с помощью abs (x) * sign (y) из-за того, как она должна обрабатывать значения NaN.
Это делает copysign () более полезной функцией, чем sign ().
Что касается конкретных причин, по которым IEEE signbit (x) не доступен в стандартном Python, я не знаю. Я могу делать предположения, но это было бы предположение.
Сам математический модуль использует copysign (1, x) как способ проверки, является ли x отрицательным или неотрицательным. В большинстве случаев иметь дело с математическими функциями, которые кажутся более полезными, чем иметь знак (x), который возвращает 1, 0 или -1, потому что есть еще один случай для рассмотрения. Например, следующее из математического модуля Python:
Там вы можете ясно увидеть, что функция copysign () является более эффективной, чем трехзначная функция sign ().
Вы написали:
Это означает, что вы не знаете, что cmp () используется не только для чисел, но и для других вещей. cmp ("This", "That") нельзя реализовать с помощью функции sign ().
Изменить, чтобы сопоставить мои дополнительные ответы в другом месте :
Вы обосновываете, что abs () и sign () часто рассматриваются вместе. Поскольку стандартная библиотека C не содержит какой-либо функции sign (x), я не знаю, как вы обосновываете свои взгляды. Есть abs (int) и fabs (double) и fabsf (float) и fabsl (long), но нет упоминания о знаке. Существуют «copysign ()» и «signbit ()», но они применяются только к номерам IEEE 754.
Что бы сложное число возвращало знак (-3 + 4j) в Python? abs (-3 + 4j) возврат 5.0. Это наглядный пример того, как abs () может использоваться в местах, где sign () не имеет смысла.
Предположим, что знак (x) был добавлен в Python как дополнение к abs (x). Если 'x' является экземпляром пользовательского класса, который реализует метод __abs __ (self), то abs (x) вызовет x .__ abs __ (). Для правильной работы, для обработки abs (x) таким же образом, Python должен получить слот sign (x).
Это чрезмерно для относительно ненужной функции. Кроме того, почему знак (x) должен существовать, а неотрицательный (x) и неположительный (x) не существует? Мой фрагмент из реализации математического модуля Python показывает, как copybit (x, y) можно использовать для реализации nonnegative (), чего не может сделать простой знак (x).
Python должен поддерживать лучшую поддержку математической функции IEEE 754 / C99. Это добавит функцию signbit (x), которая будет делать то, что вы хотите в случае с плавающей точкой. Он не будет работать для целых чисел или комплексных чисел, а тем более для строк, и не будет иметь имя, которое вы ищете.
Вы спрашиваете «почему», а ответ «знак (х) бесполезен». Вы утверждаете, что это полезно. Тем не менее, ваши комментарии показывают, что вы не знаете достаточно, чтобы иметь возможность сделать такое утверждение, а это значит, что вам придется показать убедительные доказательства его необходимости. Сказать, что NumPy реализует это, недостаточно убедительно. Вам нужно будет показать случаи улучшения существующего кода с помощью функции знака.
И что это выходит за рамки StackOverflow. Взять его вместо одного из списков Python.
источник
cmp()
ниsign()
:-)Еще один лайнер для знака ()
Если вы хотите, чтобы он возвращал 0 для x = 0:
источник
cmp(x, 0)
это эквивалентноsign
иlambda x: cmp(x, 0)
более читабельно, чем вы предлагаете.-1 if x < 0 else 1
?sign = lambda x: -1 if x < 0 else 1
на 15% быстрее . То же самое сsign = lambda x: x and (-1 if x < 0 else 1)
.Поскольку
cmp
был удален , вы можете получить ту же функциональность сОна работает
float
,int
и дажеFraction
. В случаеfloat
, уведомлениеsign(float("nan"))
равно нулю.Python не требует, чтобы сравнения возвращали логическое значение, и поэтому приведение сравнений к bool () защищает от допустимой, но необычной реализации:
источник
Только правильный ответ, соответствующий определению Википедии
Определение в Википедии гласит:
Следовательно,
Что для всех намерений и целей может быть упрощено до:
Это определение функции выполняется быстро и дает гарантированные правильные результаты для 0, 0.0, -0.0, -4 и 5 (см. Комментарии к другим неправильным ответам).
Обратите внимание, что ноль (0) не является ни положительным, ни отрицательным .
источник
Numpy имеет функцию знака, а также дает вам бонус к другим функциям. Так:
Только будьте осторожны, что результатом будет numpy.float64:
Для таких вещей, как json, это важно, поскольку json не знает, как сериализовать типы numpy.float64. В этом случае вы можете сделать:
чтобы получить регулярное плавание.
источник
Попробуйте запустить это, где х любое число
Приведение к bool () обрабатывает возможность того, что оператор сравнения не возвращает логическое значение.
источник
Да, правильная
sign()
функция должна быть, по крайней мере, в математическом модуле - как в numpy. Потому что это часто нужно для математического кода.Но
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
источник
В Python 2
cmp()
возвращает целое число: не требуется, чтобы результат был -1, 0 или 1, поэтомуsign(x)
он не совпадает сcmp(x,0)
.В Python 3
cmp()
была удалена в пользу богатого сравнения. Дляcmp()
, Python 3 предлагает это :что хорошо для cmp (), но опять же не может использоваться для sign (), потому что операторам сравнения не нужно возвращать логические значения .
Чтобы справиться с этой возможностью, результаты сравнения должны быть приведены к логическим значениям:
Это работает для любого,
type
который полностью упорядочен (включая специальные значения какNaN
или бесконечности).источник
Вам не нужно, вы можете просто использовать:
источник
x / abs(x)
требуется немного больше времени, чем просто цепочкаif/else
, или, если уж на то пошло, используется слизистый, но все же удовлетворительный,return (x > 0) - (x < 0)
для вычитанияbool
значений и возвратаint
True
и ,False
как1
и0
вы можете абсолютно сделать это и получить либо1
,0
или-1
.def sign(x): return (x > 0) - (x < 0)
не вернетbool
, он вернетint
- если вы пройдете,0
вы0
вернетесьЭто просто не так.
Лучший способ это исправить:
источник
Причина, по которой «знак» не включен, заключается в том, что если бы мы включили все полезные однострочные символы в список встроенных функций, Python больше не был бы легким и практичным для работы с ним. Если вы используете эту функцию так часто, то почему бы вам не сделать это самостоятельно? Это не так сложно или даже утомительно.
источник
abs()
не учтено.sign()
иabs()
часто используются вместе,sign()
является наиболее полезным из двух (IMO), и ни один из них не является труднодоступным или трудоемким для реализации (хотя он подвержен ошибкам, посмотрите, как этот ответ ошибается: stackoverflow.com/questions/1986152/… )sign()
сам по себе редко полезен. В большинстве случаев вы выбираете разные пути кода в зависимости от того, является ли переменная положительной или отрицательной, и в этом случае более удобно читать условие в явном виде.