Соглашения об именовании Python для атрибутов и методов, предназначенных для перезаписи

#python #naming-conventions #template-method-pattern

#python #соглашения об именовании #шаблон-метод-шаблон

Вопрос:

У меня есть некоторый объектно-ориентированный код на Python, где некоторые классы предназначены для расширения, чтобы предоставить недостающие пользовательские биты кода (а-ля шаблон метода шаблона, но также с переменными), которые будут использоваться только суперклассом, а не использующим их клиентским кодом.

Существуют ли какие-либо соглашения о стиле для таких абстрактных (или скучных, потому что их реализация в суперклассе была бы pass или вызывала NonImplemented исключение) методов и атрибутов?

Я просматривал PEP-0008, и в нем упоминается только о добавлении символа подчеркивания к частным элементам, не предназначенным для использования подклассами.

Комментарии:

1. Насколько я знаю, соглашение заключается в том, чтобы документировать это в docstrings для класса… Я не думаю, что есть какое-то конкретное соглашение, кроме этого.

Ответ №1:

Я обычно использую одинарное подчеркивание, например, _myvar для защищенных (как в C ) методов / атрибутов, которые могут использоваться производными классами, и использую двойное подчеркивание, например, __var когда оно не должно использоваться кем-либо еще, и поскольку имена с двойным подчеркиванием на уровне определения класса искажены, поэтому их нельзя переопределить в производном классе, например

 class A(object):
    def result1(self): # public method
        return self._calc1()

    def result2(self): # public method
        return self.__calc2()

    def _calc1(self): # protected method, can be overridden in derived class
        return 'a1'

    def __calc2(self): # private can't be overridden
        return 'a2'


class B(A):
    def _calc1(self):
        return 'b1'

    def __calc2(self):
        return 'b2'

a = A()
print a.result1(),a.result2()
b = B()
print b.result1(),b.result2()
  

Здесь кажется, что производный класс B переопределяет оба _calc1 и __calc2 , но __calc2 не переопределяется, потому что его имя уже искажено именем класса и, следовательно, вывод

 a1 a2
b1 a2
  

вместо

 a1 a2
b1 b2
  

но в конечном итоге выберите любое соглашение и задокументируйте его, также в приведенном выше случае дело не в том, что базовый класс не может переопределить private, вот способ 🙂

 class B(A):
    def _calc1(self):
        return 'b1'

    def _A__calc2(self):
        return 'b2'
  

Ответ №2:

Прежде всего, я думаю, что вы ошибаетесь, когда говорите, что:

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

На самом деле добавление метода / атрибута с помощью подчеркивания — это соглашение Python, которое означает, что к этому методу / атрибуту не следует обращаться за пределами класса (и его подкласса), и я думаю, вы забыли прочитать о двойном подчеркивании, которое используется, чтобы сделать метод / атрибут невозможным для переопределения.

 class Foo(object):
    def __foo(self):
        print "foo"
    def main(self):
        self.__foo()


class Bar(Foo):
    def __foo(self):
        print "bar"


bar = Bar()
bar.main()
# This will print "foo" and not "bar".
  

Существует другой способ объявления метода-заглушки, который использует abc.ABCMeta и abc.abstractmethod.

Ответ №3:

На самом деле для этих методов не существует соглашения об именовании, потому что они будут иметь одно и то же имя, когда они будут переопределены. В противном случае они не были бы переопределены! Я думаю, что переопределяемый метод делает что-то тривиальное и документирует его соответствующим образом, достаточно хорошо:

 class MyClass:

  def aMethod():
    '''Will be overridden in MyDerivedClass'''
    pass
  

Искажение имен, о котором вы упоминаете в своем вопросе, полезно, если у вас есть нетривиальный метод, который будет переопределен, но вы все еще хотите иметь доступ к базовой версии. Смотрите документацию для получения дополнительной информации и примера.