Соглашения об именах 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

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

Другие вопросы по тегам