#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
Искажение имен, о котором вы упоминаете в своем вопросе, полезно, если у вас есть нетривиальный метод, который будет переопределен, но вы все еще хотите иметь доступ к базовой версии. Смотрите документацию для получения дополнительной информации и примера.