2015-12-25 4 views
5

Ошибка при попытке установить значение аргумента класса, который наследует от str. Ошибка возникает только тогда, когда я пытаюсь получить доступ к аргументу с помощью myClass(arg = 'test'). Ошибка:Задайте значение аргумента в классе, который наследует от int или float или str

TypeError: 'arg' is an invalid keyword argument for this function 

вопрос показан в этом Exemple:

class A(str):  
    def __init__(self, arg): 
     pass 

A("test") # Works well 
A(arg = "test") # Fails 

только последняя строка вызывает ошибку. Предыдущая строка работает хорошо. Проблема такая же с классами, которые наследуются от int или float.

ОБНОВЛЕНИЕ (раствор):

Я нашел решение с этих ссылок:

Раствор является:

class A(str): 

    def __new__(cls, *args, **kwargs): 
     return str.__new__(cls) 

    def __init__(self, arg01): 
     print(arg01) 

A(arg01= "test") 

Я не знаю, почему это работает, и я буду исследовать его. Если у кого-то есть ясное объяснение, я заинтересован, и я благодарю его заранее.

UPDATE (мое объяснение):

Я не уверен, что на все, что я скажу, но это то, что я понял.

Представьте себе класс 'myClass' без какого-либо имущества. Когда я это делаю myInstance = myClass(), вот что происходит:

Выполнен метод myClass.__new__. Этот метод создаст объект myInstance. __new__ - это реальный конструктор (__init__ не является конструктором!). В псевдокоде __new__ выглядеть примерно так:

def __new__ (cls, *args, **kwargs): 

    myInstance = # Do some stuff to create myInstance, an object of the type passed as argument (cls). 
    # Add the method __init__ to myInstance. 
    # Call __init__ and pass to it the list 'args' and the dictionary 'kwargs' (both come from arguments of __new__). Pass to it also the object itself (self) : 
    obj.__init__(self, args, kwargs) : 
     # Do some stuff. 

ситуация немного отличается, когда мы используем неизменные типы (улица, целый, дробный, кортеж). В предыдущем псевдокоде я написал def __new__(cls, *args, **kwargs). С неизменяемыми типами псевдокод для метода __new__ более похож на этот def __new__(cls, anUniqueValue). Я не понимаю, почему поведение immutableTypes.__new__ отличается от других, но это так. Вы можете видеть это в этом примере:

class foo(): 

    def __init__(self): 
     pass 

foo.__new__(foo, arg = 1) 
# That works because the method __new__ look like this : def __new__(*args, **kargs). 

str.__new__(str, arg = 1) 
# That fails because we are trying to pass the attribute 'arg' to a method which look like this : def __new__(anUniqueValue). 

Оттуда мы можем понять, почему решение, представленное ранее, работает. Мы делаем редактирование метода __new__ неизменяемого типа, который работает так же, как и изменяемый тип.

def __new__(cls, *args, **kwargs): 
    return str.__new__(cls) 

Эти 2 строки преобразуют def __new__ (cls, anUniqueValue) в def __new__ (cls, *args, **kwargs)

Я надеюсь, что мое объяснение почти ясно и без так много ошибок.Если вы говорите по-французски, вы можете узнать больше по этой ссылке: http://sametmax.com/la-difference-entre-new-et-init-en-python/

+1

Возможно, связано с http://stackoverflow.com/questions/3748635/adding-optional-parameters-to-the-constructors-of-multiply-inheriting-subclasses, хотя я не уверен, что Алекс Мартелли точно означает " одинаково произвольный суперкласс ". – timgeb

+1

@Morgan, объяснение в связанном вопросе, может также быть * ее *, который может дать вам четкое объяснение;) –

+0

@Morgan не стесняйтесь отвечать на свой вопрос, когда узнаете, что именно происходит на. Я сам не полностью понял объяснения в связанных вопросах. – timgeb

ответ

2

То, что вы написали, по сути, правильно, есть несколько ошибок здесь и там.


class A(str): 

    def __new__(cls, *args, **kwargs): 
     return str.__new__(cls) 

    def __init__(self, arg01): 
     print(arg01) 

Это не совсем правильно: если вы не сдадите какой-либо аргумент str.__new__, новый экземпляр будет эквивалентом пустой строки.

class A(str): 

    def __new__(cls, arg): 
     return str.__new__(cls, arg) 

    def __init__(self, arg): 
     print(arg) 

В общем, __new__ и __init__ должны иметь такую ​​же подпись. Это не является обязательным требованием, но в этом случае вам необходимо пройти arg до str.__new__, поэтому вы должны перехватить arg.


myClass.__new__ Метод выполняется. Этот метод создаст объект myInstance. __new__ - это реальный конструктор (__init__ не является конструктором!). В псевдокоде __new__ выглядеть примерно так:

Это не ответственность __new__ называть __init__, как показано на этом простом примере:

class C: 

    def __new__(cls): 
     print('entering __new__') 
     self = super().__new__(cls) 
     print('exiting __new__') 
     return self 

    def __init__(self): 
     print('entering __init__') 
     super().__init__() 
     print('exiting __init__') 


C() 

# Output: 
# entering __new__ 
# exiting __new__ 
# entering __init__ 
# exiting __init__ 

Как вы можете видеть, в моем __new__ я Бесполезный 't звоните __init__ явно, и object.__new__ не звонит __init__.

__init__ автоматически вызывается самим интерпретатором Python всякий раз, когда __new__ возвращает экземпляр типа.


ситуация немного отличается, когда мы используем неизменные типы (улица, целый, дробный, кортеж).

Это не совсем так. Ситуация отличается от , когда мы наследуем от типа, который не использует реализацию по умолчанию __new__..

Реализация по умолчанию __new__ (т. Е. object.__new__) очень разрешительна и игнорирует каждый аргумент аргумента и ключевого слова. Если вы замените его на менее разрешительную реализацию, тогда будут возникать проблемы, подобные тем, которые вы наблюдаете.

Что важно понять, что проблема не возбужден самим не по умолчанию __new__, но тот факт, что наш __init__ не совместим с __new__.


foo.__new__(foo, arg = 1) 
# That works because the method __new__ look like this : def __new__(*args, **kargs). 
str.__new__(str, arg = 1) 
# That fails because we are trying to pass the attribute 'arg' to a method which look like this : def __new__(anUniqueValue). 

Вы его получили.Только один бит неправильно: правильная подпись для str.__new__ является:

def __new__(cls[, object[, encoding[, errors]]]) 

Все аргументы, кроме cls оба позиционных и ключевое слово аргумент. Фактически вы можете сделать:

>>> class C(str): 
...  def __init__(self, object): 
...   pass 
... 
>>> C('abc') 
'abc' 
>>> C(object='abc') 
'abc' 

Вы видите? Мы использовали подпись для __init__, которая совместима с str.__new__, и теперь мы можем избежать переопределения __new__!

+0

спасибо за эти замечания! – Morgan