Соглашения об именах Python для атрибутов и методов, предназначенных для перезаписи
У меня есть некоторый объектно-ориентированный код в Python, где некоторые классы должны быть расширены, чтобы обеспечить отсутствующие пользовательские фрагменты кода (как шаблонный метод, но также с переменными), которые будут использоваться только суперклассом, а не клиентский код, использующий их.
Существуют ли какие-либо соглашения по стилю для таких абстрактных (или скучных, потому что их реализация в суперклассе будет либо pass
или поднять NonImplemented
исключение) методы и атрибуты?
Я просматривал PEP-0008, и он упоминает только о добавлении подчеркивания частным членам, не предназначенным для использования подклассами.
3 ответа
Прежде всего, я думаю, что вы ошибаетесь, когда говорите:
о добавлении подчеркивания к частным членам, не предназначенным для использования подклассами.
Фактически добавление метода / атрибута через подчеркивание - это соглашение 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.
Я обычно использую одно подчеркивание, например _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
но в конечном итоге выберите любое соглашение и задокументируйте его, также в приведенном выше случае базовый класс не может переопределить закрытый, вот способ:)
class B(A):
def _calc1(self):
return 'b1'
def _A__calc2(self):
return 'b2'
На самом деле не существует соглашения об именах для этих методов, потому что они будут иметь одно и то же имя при переопределении. В противном случае они не будут отменены! Я думаю, что метод, который нужно переопределить, делает что-то тривиальное, и, соответственно, документирует это достаточно хорошо:
class MyClass:
def aMethod():
'''Will be overridden in MyDerivedClass'''
pass
Упорядочивание имен, которое вы упоминаете в своем вопросе, полезно, если у вас есть нетривиальный метод, который будет переопределен, но вы все еще хотите иметь доступ к базовой версии. См. Документацию для получения дополнительной информации и примера.