Значение по умолчанию: пропустить первый [дубликат]

Ну, причина в том, что привязки выполняются при выполнении кода, и выполняется определение функции, ну ... когда функции определены.

Сравните это:

class BananaBunch:
    bananas = []

    def addBanana(self, banana):
        self.bananas.append(banana)

Этот код страдает от такого же неожиданного случая. bananas - это атрибут класса, и, следовательно, когда вы добавляете к нему вещи, он добавляется ко всем экземплярам этого класса. Причина в том, что это точно то же самое.

Это просто «Как это работает», и заставить его работать по-другому в функциональном случае, вероятно, будет сложно, а в случае класса вероятно невозможно или, по крайней мере, замедлить объект создание экземпляра, так как вам придется хранить код класса и выполнять его при создании объектов.

Да, это неожиданно. Но как только пенни падает, она прекрасно вписывается в то, как работает Python в целом. На самом деле, это хорошее учебное пособие, и как только вы поймете, почему это происходит, вы будете намного лучше читать python.

Это говорит о том, что он должен занимать видное место в любом хорошем учебнике Python. Потому что, как вы говорите, все рано или поздно сталкиваются с этой проблемой.

11
задан Mysticial 25 November 2011 в 00:05
поделиться

4 ответа

Если вам разрешено передавать пустую C-строку, когда у вас нет значения для второго параметра, вы можете использовать вспомогательный функтор, который будет проверять arg2 и возвращать значение по умолчанию, если оно пустое. Что-то вроде этого:

#define DEFAULT_ARG "arg2"

struct helper_class {
    char* operator()(char* arg)
    {
        if (*arg) return arg; else return DEFAULT_ARG;
    }
} helper;

class func {
    public:
    func(int arg1 , char* arg2 = "arg2", int arg3 = 1) {}
};

int main()
{
    func f1(42, helper(""), 9001);   // default 2nd argument
    func f2(42, helper("Its over 9000!"));
}

Не очень, я знаю ...

2
ответ дан jrok 21 August 2018 в 22:14
поделиться

Прямо сейчас вы можете использовать std :: bind для выполнения этой операции или в c ++ 14/17 вы можете использовать лямбда-функцию и выполнить то же самое.

1
ответ дан M.Baryłowicz 21 August 2018 в 22:14
поделиться

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

#include <iostream>

// cheap and cheerful Boost.Variant
struct StringOrInt {
    char *s;
    int i;
    bool is_string;
    StringOrInt(char *s) : s(s), i(0), is_string(true) {}
    StringOrInt(int i) : s(0), i(i), is_string(false) {}
    bool isInt() { return !is_string; }
    int asInt() { return i; }
    char *asString() { return s; }
};

struct Foo {
    int m1;
    char *m2;
    int m3;
    Foo(int arg1, StringOrInt arg2 = "arg2", int arg3 = 1) : m1(arg1) {
        if (arg2.isInt()) {
            arg3 = arg2.asInt();
            arg2 = "arg2";
        }
        m2 = arg2.asString();
        m3 = arg3;
    }
    void print() {
        std::cout << m1 << " " << m2 << " " << m3 << "\n";
    }
};

int main() {
    Foo(1, "HelloWorld").print();
    Foo(1, 2).print();
}

Обратите внимание, что с GCC это генерирует предупреждения, поскольку преобразование из строкового литерала в неконстантный char* является устаревшим и неразумным. Но это то, о чем вы просили, и исправление его, чтобы параметры char* и элемент данных были const char* достаточно легкими.

Существенная слабость заключается в том, что это не мешает вам писать Foo(1,2,3) , Чтобы проверить, что во время компиляции мне нужно несколько конструкторов. Чтобы проверить его во время выполнения, вы можете сделать третий параметр в другом классе, DefaultOrInt, где Default - это тип, используемый только для этой цели, поддерживающий только одно значение, используемое как значение по умолчанию для arg3. Тогда, если arg2.isInt() истинно, проверьте, что arg3.isInt() является ложным и если не выбрасывает logic_error.

2
ответ дан Steve Jessop 21 August 2018 в 22:14
поделиться

Кроме того, нельзя использовать перегруженные конструкторы. Это должно быть сделано одним конструктором.

Единственная причина, по которой я могу думать об этом требовании, состоит в том, что необязательные аргументы имеют один и тот же тип. В этом случае вы застряли, и вам захочется заглянуть в named constructor и / или с именем id .

В противном случае просто определите дополнительный конструктор. Это может привести к некоторому дублированию. значения по умолчанию.

Foo(int arg1 , char const *arg2 = "arg2", int arg3 = 1)
{
    construct(arg1, arg2, arg3);
}

Foo(int arg1, int arg3)
{
    construct(arg1, "arg2", arg3);
}
8
ответ дан tschale 21 August 2018 в 22:14
поделиться
  • 1
    Это некоторые действительно приятные идиомы, спасибо за обмен ссылками. Одна из потрясающих вещей о переполнении стека заключается в том, что вы можете произвольно просматривать темы и изучать интересные вещи :) +1 – Chris Parton 25 November 2011 в 03:42
Другие вопросы по тегам:

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