Создание метода private в подклассе python - PullRequest
25 голосов
/ 16 января 2009

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

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. Возможно ли это?

РЕДАКТИРОВАТЬ: «логическая» причина этого в том, что я не хочу, чтобы пользователи вызывали методы в неправильном порядке.

Ответы [ 13 ]

29 голосов
/ 02 мая 2011

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

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

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

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

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

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

27 голосов
/ 17 января 2009

Нет способа сделать это в Python. Скорее не пифонично, это так.

Как сказал бы Гвидо, мы все здесь взрослые.

Вот хорошее краткое изложение философии всего, что в Python является общедоступной .

12 голосов
/ 17 января 2009

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

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

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

#define private public
#include <module>
11 голосов
/ 17 января 2009

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

def _i_am_private(self):
    """If you call me from a subclass you are a naughty person!"""
11 голосов
/ 17 января 2009

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

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

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

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

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

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


Редактировать На коде "idiot-proof".

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

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

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

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

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

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

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

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

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

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

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

7 голосов
/ 19 января 2009

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

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

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

7 голосов
/ 17 января 2009

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

#!/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
6 голосов
/ 17 января 2009

Изменение унаследованного метода с публичного на приватный нарушает наследование . В частности, это нарушает отношения is-a.

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

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

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

5 голосов
/ 16 января 2009

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

class Foo:
    def __blah():
        pass

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

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

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

1 голос
/ 02 ноября 2013
class MyClass(object): 
    def _prtectedfunc(self):
        pass # with one undersocre

    def __privatefunc(self):
        pass # with two undersocre

http://linuxwell.com/2011/07/21/private-protected-and-public-in-python/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...