Поддерживает ли Python ключевое слово по умолчанию и аргументы переменной длины по умолчанию?

Прочитав другие ответы, я хотел что-то, что пройдет через предупреждение сравнения с плавающей запятой и не сломается под быстрой математикой. Появится следующий код:

/*
  Portable warning-free NaN test:
    * Does not emit warning with -Wfloat-equal (does not use float comparisons)
    * Works with -O3 -ffast-math (floating-point optimization)
    * Only call to standard library is memset and memcmp via <cstring>
    * Works for IEEE 754 compliant floating-point representations
    * Also works for extended precision long double
*/

#include <cstring>
template <class T> bool isNaN(T x)
{
  /*Initialize all bits including those used for alignment to zero. This sets
  all the values to positive zero but does not clue fast math optimizations as
  to the value of the variables.*/
  T z[4];
  memset(z, 0, sizeof(z));
  z[1] = -z[0];
  z[2] = x;
  z[3] = z[0] / z[2];

  /*Rationale for following test:
    * x is 0 or -0                                --> z[2] = 0, z[3] = NaN
    * x is a negative or positive number          --> z[3] = 0
    * x is a negative or positive denormal number --> z[3] = 0
    * x is negative or positive infinity          --> z[3] = 0
      (IEEE 754 guarantees that 0 / inf is zero)
    * x is a NaN                                  --> z[3] = NaN != 0.
  */

  //Do a bitwise comparison test for positive and negative zero.
  bool z2IsZero = memcmp(&z[2], &z[0], sizeof(T)) == 0 ||
                  memcmp(&z[2], &z[1], sizeof(T)) == 0;

  bool z3IsZero = memcmp(&z[3], &z[0], sizeof(T)) == 0 ||
                  memcmp(&z[3], &z[1], sizeof(T)) == 0; 

  //If the input is bitwise zero or negative zero, then it is not NaN.
  return !z2IsZero && !z3IsZero;
}

//NaN test suite
#include <iostream>

/*If printNaN is true then only expressions that are detected as NaN print and
vice versa.*/
template <class T> void test(bool printNaN)
{
  T v[10] = {-0.0, 0.0, -1.0, 1.0,
    std::numeric_limits<T>::infinity(),
    -std::numeric_limits<T>::infinity(),
    std::numeric_limits<T>::denorm_min(),
    -std::numeric_limits<T>::denorm_min(),
    std::numeric_limits<T>::quiet_NaN(),
    std::numeric_limits<T>::signaling_NaN()};
  for(int i = 0; i < 10; i++)
  {
    for(int j = 0; j < 10; j++)
    {
      if(isNaN(v[i] + v[j]) == printNaN)
        std::cout << v[i] << "+" << v[j] << " = " << v[i] + v[j] << std::endl;
      if(isNaN(v[i] - v[j]) == printNaN)
        std::cout << v[i] << "-" << v[j] << " = " << v[i] - v[j] << std::endl;
      if(isNaN(v[i] * v[j]) == printNaN)
        std::cout << v[i] << "*" << v[j] << " = " << v[i] * v[j] << std::endl;
      if(isNaN(v[i] / v[j]) == printNaN)
        std::cout << v[i] << "/" << v[j] << " = " << v[i] / v[j] << std::endl;
    }
  }
}

//Test each floating-point type.
int main()
{
  std::cout << "NaNs:" << std::endl;
  test<float>(true);
  test<double>(true);
  test<long double>(true);
  std::cout << std::endl << "Not NaNs:" << std::endl;
  test<float>(false);
  test<double>(false);
  test<long double>(false);
  return 0;
}
-2
задан Martijn Pieters 16 January 2019 в 17:42
поделиться

2 ответа

Вы можете иметь значение по умолчанию kwargs и все еще распаковывать с splat а-ля **kwargs

def john(name, dog, *args, bob="bob", **kwargs):
  print(name, dog, bob)

# "ream" is an unpacked arg
john("john", 1, "ream") # john 1 bob

# jane is an unpacked kwarg
john("john", 1, "ream", jane="jane") # john 1 bob

john("john", 1, "ream", bob="jane") # john 1 jane

Установить значение по умолчанию для *arg довольно сложно, потому что идея состоит в том, чтобы сделать функцию требовать этот вклад. Вы могли бы взглянуть на некоторые приемы в этом духе а-ля реализации встроенной функции range. Я бы просто сделал это kwarg, хотя.

0
ответ дан Charles Landau 16 January 2019 в 17:42
поделиться

Нет, *args и **kwargs - это универсальные аргументы, которые получают любые аргументы, для которых нет явных аргументов. Указание значений по умолчанию наносит ущерб их цели. Вместо этого, ваш пример значений по умолчанию может быть обработан с помощью существующего синтаксиса , здесь нет необходимости усложнять синтаксис определения функции.

Вы можете указать свои значения по умолчанию, указав аргументы обычного ключевого слова :

def foo(pos0, pos1='v', a=20, *args, **kwargs):
    pass

Я заменил (1, 'v') «default» другим аргументом ключевого слова, поскольку вы можете указать значения для ключевого слова аргументы с позиционным параметром ; foo(42, 'spam') установит pos1 в 'spam'.

Кроме того, вы всегда можете выполнить дальнейшую обработку внутри определяемой вами функции; значение args является кортежем, просто проверьте длину, чтобы проверить, нужно ли использовать значение по умолчанию для пропущенных значений. kwargs - это словарь, просто используйте kwargs.get(key, default) или kwargs.pop(key, default) или if key not in kwargs: или любой другой метод dict для обработки отсутствующих ключей.

0
ответ дан Martijn Pieters 16 January 2019 в 17:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: