2016-09-02 2 views
31

Я просматривал какой-то код, и я заметил линию, которая привлекла мое внимание. Код похож на пример нижеЕсть ли причина для присвоения значения по умолчанию?

class MyClass: 
    def __init__(self): 
     pass 

    def call_me(self=''): 
     print(self) 

Это выглядит как и любой другой класс, который я видел, однако str в настоящее время передается в качестве значения по умолчанию для self.

Если я распечатать self, он ведет себя как нормальный

>>> MyClass().call_me() 
<__main__.MyClass object at 0x000002A12E7CA908> 

Это было давало мне покоя, и я не могу понять, почему это будет использоваться. Есть ли причина, почему пример str будет передан в качестве значения по умолчанию для self?

+10

Похоже, кто-то хотел, чтобы 'MyClass.call_me()' работал тоже. Не особенно хорошая идея, однако, они могли бы сделать это «classmethod». –

+0

Если 'call_me' вызывается из самого класса, а не из экземпляра, тогда' '' 'передается как экземпляр, а вызов метода не вызывает ошибку. –

ответ

28

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

MyClass.call_me() 

прекрасно работает так, даже если ничего не неявно передается как с экземплярами, предоставляется значение по умолчанию для этого аргумента. Если по умолчанию не было предоставлено, при вызове это, конечно же, повысило бы TypeError для аргументов, которые все мы любим. Что касается того, почему он выбрал пустую строку в качестве значения, только он знает.

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

Таким образом вы не озадачить любого чтения кода (как разработчик, который написал это сделал с вами ;-):

@staticmethod 
def call_me(a=''): 
    print(a) 

Если вместо этого вы должны иметь доступ к классу атрибутов вы всегда можете выбрать для декоратора classmethod. Оба эти (class и static декораторов) также служат вторичной целью сделать ваше намерение кристально чистым для других, читающих ваш код.

13

Короткий ответ: да. Таким образом, вы можете вызвать функцию как:

MyClass.call_me() 

без инстанцировании MyClass, который будет печатать пустую строку.

Чтобы дать более длинный ответ, нам нужно посмотреть, что происходит за кулисами.

При создании экземпляра класса, __new__ и __init__ призваны создать его, то есть:

a = MyClass() 

примерно эквивалентно:

a = MyClass.__new__(MyClass) 
MyClass.__init__(a) 

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

a.call_me() 

Он «заменен» MyClass.call_me(a).

Таким образом, имея параметр по умолчанию для call_me, вы можете вызвать эту функцию не только как метод экземпляра, и в этом случае self является самим экземпляром, но также и как метод статического класса.

Таким образом, вместо MyClass.call_me(a), только MyClass.call_me() называется. Поскольку список аргументов пуст, аргумент по умолчанию присваивается self и печатается нужный результат (пустая строка).