Подтвердить что ты не робот

Создание метода private в подклассе python

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

class A:
    def __init__(self):
        #do something here

    def method(self):
        #some code here

class B(A):
    def __init__(self):
        A.__init__(self)
        #additional initialization goes here

    def method(self):
        #this overrides the method ( and possibly make it private here )

с этого момента, я не хочу, чтобы какой-либо класс, который простирался от B, мог вызвать method. Возможно ли это?

EDIT: "Логическая" причина заключается в том, что я не хочу, чтобы пользователи вызывали методы в неправильном порядке.

4b9b3361

Ответ 1

Python распространяется как источник. Сама идея частного метода имеет мало смысла.

Программист, который хочет расширить B, разочарованный проблемой конфиденциальности, смотрит на источник для B, копирует и вставляет исходный код для method в подкласс C.

Что вы получили благодаря "конфиденциальности"? Лучшее, на что вы можете надеяться, это расстроить ваших потенциальных клиентов на копирование и вставку.

В худшем случае они отбрасывают ваш пакет, потому что не могут его продлить.

И да, все открытые источники так или иначе расширяются. Вы не можете предвидеть все и всякое использование, к которому будет добавлен код. Предотвращение использования в будущем трудно сделать, когда код распространяется как источник.

Смотрите Как защитить код Python?


Изменить На "idiot-proof" code.

Во-первых, питон распространяется как источник в 90% случаев. Таким образом, любой идиот, который скачивает, устанавливает, а затем отказывается читать руководство по API и вызывает методы не в порядке, все еще имеет источник, чтобы выяснить, что пошло не так.

У нас есть три класса идиотов.

  • Люди, которые отказываются читать руководство по API (или обрезают его и игнорируют соответствующие части), и вызывают методы не в порядке, несмотря на документацию. Вы можете попытаться сделать что-то частное, но это не поможет, потому что они сделают что-то еще не так - и жалуются на это. [Я не буду называть имена, но я работал с людьми, которые, похоже, тратят много времени на неправильный вызов API. Кроме того, вы увидите такие вопросы на SO.]

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

  • Люди, которые смущены API и называют методы разными способами, которые вы можете себе представить (и некоторые из них вы не можете). Вы можете попробовать сделать что-то частное, но они никогда не получат API.

    Вы можете только помочь им, предоставив образец рабочего кода; даже тогда они будут вырезать и вставлять их неправильно.

  • Люди, которые отклоняют ваш API и хотят переписать его, чтобы сделать его "доказательством идиота".

    Вы можете предоставить им образец рабочего кода, но им не нравится ваш API и он будет настаивать на его переписывании. Они скажут вам, что ваш API сумасшедший, и они улучшили его.

    Вы можете вовлечь этих людей в эскалацию гонки вооружений "идиотистов". Все, что вы собрали, они разделяют.

В этот момент, что для вас сделало конфиденциальность? Некоторые люди откажутся это понимать; некоторые люди смущены этим; и некоторые люди хотят обойти это.

Как насчет публики, и пусть люди, которых вы называете "идиотами", узнаете из вашего кода?

Ответ 2

В отличие от популярной моды на эту тему, являются законными причинами для разграничения между публичными, частными и защищенными членами, независимо от того, работаете ли вы на Python или в более традиционной среде ООП. Много раз, по-видимому, вы разрабатываете вспомогательные методы для особо долговечной задачи на определенном уровне специализации объекта. Излишне говорить, что вы действительно не хотите, чтобы эти методы были унаследованы любым подклассом, потому что они не имеют смысла в специализированном контексте и даже не должны быть видимыми; и все же они видны, и они уменьшают полезность таких вещей, как табуляция, навигаторы объектов и другое системное программное обеспечение, потому что все на разных уровнях абстракции сглаживаются и сбрасываются вместе. Имейте в виду, что эти программные средства не являются тривиальными. Они всего лишь тривиальны, если вы студент и наслаждаетесь тем же делом миллион раз только потому, что вы учитесь, как.

Python исторически развит таким образом, что для реализации публичного/частного различия становится все труднее из-за идеологической инерции и проблем совместимости. Это простая истина. Было бы настоящей головной болью для всех, чтобы изменить то, что они делали. Следовательно, теперь у нас есть миллион поклонников Python, все из которых прочитали одни и те же одну или две оригинальные статьи, однозначно определяющие, что публичное/частное различие "непистотическое". Эти люди из-за отсутствия критической мысли или справедливости к широко распространенным, обычным практикам мгновенно используют этот случай, чтобы уловить предсказуемое множество апологетики - De Defensione Serpentis, которые, как я подозреваю, возникают не из рационального выбора сквозных пифонов ( питонический путь), но из-за пренебрежения другими языками, которые они либо не хотят использовать, не имеют опыта использования или не могут использоваться из-за работы.

Как уже говорилось, лучшее, что вы можете сделать в Python для создания эффекта, аналогичного частным методам, - это добавить имя метода с помощью __ (два символа подчеркивания). С другой стороны, единственное, что это делает, фактически говоря, это вставка имени трансформированного атрибута в объект __dict__. Например, скажем, у вас есть следующее определение класса:

class Dog(object):
    def __bark(self):
        print 'woof'

Если вы запустите dir(Dog()), вы увидите странный член, называемый _Dog__bark. В самом деле, единственная причина, по которой этот трюк существует, заключается в том, чтобы обойти проблему, которую я описал ранее: а именно, предотвращение наследования, перегрузки и замены супер-методов.

Мы надеемся, что в будущем будет реализована стандартизированная реализация частных методов, когда люди поймут, что ткани не должны иметь доступ к методам, посредством которых отдельная клетка реплицирует ДНК, а сознательный ум постоянно должен выяснить, как восстановить его ткани и внутренние органы.

Ответ 4

Вы можете префиксные методы и элементы с одним или двумя символами подчеркивания. Единственное подчеркивание подразумевает: "Пожалуйста, не используйте меня, я должен использоваться только этим классом", а двойной подчеркивание инструктирует компилятор Python манипулировать именем метода/члена с именем класса; до тех пор, пока класс и его подклассы не имеют одинакового имени, методы/члены могут считаться "private".

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

В конце концов, даже частные лица С++ не являются частными. Например, подумайте о старом трюке:

#define private public
#include <module>

Ответ 5

Я удивлен, что никто не упомянул об этом, но префикс имени метода одним подчеркиванием - это правильный способ маркировки его как "private". Конечно, это не очень личное, (как объяснялось в других ответах), но там вы идете.

def _i_am_private(self):
    """If you call me from a subclass you are a naughty person!"""

Ответ 6

Это может быть справедливое приближение. Лексическое определение области "спасения":

#!/usr/bin/env python

class Foo(object):
    def __init__(self, name):
        self.name = name
        self.bar()

    def bar(self):
        def baz():
            print "I'm private"
            print self.name

        def quux():
            baz()

        self.quux = quux


if __name__ == "__main__":
    f = Foo("f")
    f.quux()

    g = Foo("g")
    g.quux()

    f.quux()

Печать

I'm private
f
I'm private
g
I'm private
f

Ответ 7

"Все должно быть публично". Сторонники считают, что автор пытается скрыть полезный API от пользователей. Этот парень не хочет нарушать неоспоримый закон Python. Он хочет использовать некоторые методы для определения полезного API, и он хочет использовать другие методы для организации реализации этого API. Если между ними нет разделения, это не значит, что автор не идиот. Это означает, что автор был слишком ленив, чтобы фактически определить API.

В Python вместо того, чтобы маркировать свойства или методы как частные, они могут иметь префикс _ как слабый индикатор "внутреннего использования" или __ как немного более сильный. В модуле имена могут иметь префикс с _ одинаковым образом, и вы также можете поместить последовательность строк, которые составляют открытый API модулей в переменной с именем __all__.

Глупая консистенция - это хобгоблин маленьких умов.

Ответ 8

Изменение унаследованного метода от наследования наследования от public до private. В частности, он нарушает отношения is-a.

Представьте себе ресторанный класс с открытым открытым способом (т.е. ужином, и мы хотим щелкнуть знак передней двери от закрытого до открытого). Теперь нам нужен класс общественного питания, в котором будут представлены многие детали реализации ресторана (им обязательно нужны повара, кухни, блюда, поставщики продуктов питания и, возможно, даже подождать), но не имеют столовой, передних дверей или открытых дверей метод. Наследование из ресторана - ошибка! Может показаться, что все, что вам нужно сделать, это изменить метод открытых дверей на частные, поэтому никто не может его использовать, но тогда "любой объект общественного питания - это ресторан" является ложным, так как часть открытого интерфейса ресторана - это открытые двери. Лучше реорганизовать ресторан, добавив новый базовый класс, а затем и ресторан, и общественное питание вытекают из него.

Языки с понятием защищенного или частного наследования поддерживают эту идею наследования только для реализации, но Python не является одним из них. (И это не полезно на этих языках, за исключением редких случаев.) Обычно, когда запрашивается непубличное наследование, сдерживание (иначе называемое "отношение" ) является лучшим путем, вы можете даже сделать атрибут защищенным или приватным.

Заклинания Python, защищенные одним лидирующим подчеркиванием и частным с двойными лидирующими подчеркиваниями, с модификацией философии "соглашающихся взрослых", упомянутой в ответе Триптиха. "Опасные" атрибуты и методы вашего класса, например. те, которые могут привести к потере данных, должны быть непубличными (на то, чтобы сделать их защищенными или частными, зависят от других факторов), с общедоступными методами, используемыми для обеспечения более простого и безопасного интерфейса.

Ответ 9

Чтобы сделать метод частным, вы можете называть метод таким образом:

class Foo:
    def __blah():
        pass

class Bar(Foo):
    def callBlah():
        self.__blah() # will throw an exception

Но подклассы все еще могут найти ваши методы с помощью самоанализа, если они действительно этого хотят.

Но Python (по продуманному дизайну и выбору) не имеет понятия частных членов.

Ответ 10

Даже среди согласных взрослых есть причины, по которым вы не хотите выставлять методы производному классу. Вопрос в том, могу ли я иметь иерархию наподобие Parent > Child, где пользователь может получить либо родительский, либо детский, но не подвергаться каким-либо частным или защищенным методам. В следующем примере Child явно перегружает Parent.__ private, не подвергая его воздействию.

class Parent(object):
    def __private(self):
        print 'Parent'

    def go(self):
        self.__private()

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)
        self._Parent__private = self.__private

    def __private(self):
        print 'Child'

Ответ 12

В этой теме есть много хороших ответов, но вот несколько практичный ответ с практической точки зрения:

Вы должны скрыть (иначе документ) переменные и методы низкого уровня от общедоступных API. Поэтому всегда присоединяйте _ или __ к этим членам. Большой вопрос: должно ли это быть _ или __? Перспектива пуристического ООП состоит в том, чтобы всегда присоединять __ к закрытым членам и _ к "защищенным" методам (то есть доступным, переопределяемым из производного класса). __ гарантирует, что производный класс не может переопределить его. С другой стороны, это также затрудняет использование таких вещей, как setattr, тестируемость и читабельность.

Мое личное мнение (а также руководство по стилю Google) состоит в том, чтобы максимально избегать ___ и использовать _ для частных пользователей.

Но как насчет защищенных членов? Как мы говорим пользователям нашей библиотеки, что они должны/должны переопределить? Здесь я предпочитаю не использовать подчеркивание для защищенных членов и вместо этого полагаться на комментарии строки документации и, возможно, @abstractmethod в базовом классе. Одним из преимуществ здесь является то, что защищенные члены не будут исключены из различных генераторов документации.

Ответ 13

В этой теме есть много хороших ответов, но вот несколько практичный ответ с практической точки зрения:

Вы должны избегать большого количества частных членов из открытых API, intellisense, документов, import * и т.д. Поэтому всегда присоединяйте _ или __ к этим членам.

Большой вопрос: должно ли это быть _ или __? Цель ООП purist - всегда прикреплять __ к закрытым членам и _ для защищенных методов. __ делает имя искажения и затрудняет использование таких вещей, как setattrib, тестовые среды и снижает удобочитаемость. Поэтому я лично стараюсь избегать __ как можно больше и использовать _ для частных пользователей.

Но как насчет защищенных членов, которые мы хотим, чтобы производный класс использовал, но не как публичный API. Я предпочитаю не использовать подчеркивание вообще. Это позволяет этим членам получать публичные документы. Затем мы полагаемся на docstring, чтобы сообщить пользователю, что это защищенные члены, например:

class Class1:
  def _private1():
    pass

  def protected1():
    """(for derived classes) Does XYZ."""
    pass

  def public1()
    pass