¿Por qué los métodos ‘privados’ de Python no son realmente privados?

6 minutos de lectura

¿Por que los metodos privados de Python no son realmente
Willurd

Python nos brinda la capacidad de crear métodos y variables ‘privados’ dentro de una clase anteponiendo guiones bajos dobles al nombre, como este: __myPrivateMethod(). ¿Cómo, entonces, se puede explicar este

>>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

>>> obj.myPublicMethod()
public method

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

>>> obj._MyClass__myPrivateMethod()
this is private!!

¡¿Cual es el trato?!

Explicaré esto un poco para aquellos que no lo entendieron del todo.

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

Creo una clase con un método público y un método privado y lo instalo.

A continuación, llamo a su método público.

>>> obj.myPublicMethod()
public method

A continuación, intento llamar a su método privado.

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

Todo se ve bien aquí; no podemos llamarlo. Es, de hecho, ‘privado’. Bueno, en realidad no lo es. Corriendo directorio() en el objeto revela un nuevo método mágico que Python crea mágicamente para todos sus métodos ‘privados’.

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

El nombre de este nuevo método siempre es un guión bajo, seguido del nombre de la clase, seguido del nombre del método.

>>> obj._MyClass__myPrivateMethod()
this is private!!

Tanto para la encapsulación, ¿eh?

En cualquier caso, siempre escuché que Python no admite la encapsulación, entonces, ¿por qué intentarlo? ¿Lo que da?

  • Lo mismo es cierto para Java o C # si usa la reflexión (que de alguna manera es lo que está haciendo allí).

    – 0x434D53

    22 de febrero de 2015 a las 10:24

  • Fue construido para propósitos de prueba unitaria, por lo que puede usar ese “truco” para probar los métodos privados de su clase desde el exterior.

    – waas1919

    12/04/2016 a las 16:10

  • ¿No es probar métodos privados un antipatrón? Los métodos privados se usarán en algún método público, de lo contrario, no se usará para siempre. Y la forma correcta de probar métodos privados (basado en mi aprendizaje hasta ahora de ThoughtWorks) es escribir pruebas solo para métodos públicos que cubran todos los casos. Si eso funciona bien, no necesita probar métodos privados desde el exterior.

    – Vishnu Narang

    22 de enero de 2017 a las 23:19


  • @VishnuNarang: Sí, eso es lo que se enseña a menudo. Pero como siempre, un enfoque casi “religioso” de “siempre hacer esto, Nunca hacer eso” es lo único que “nunca” es bueno. Si las pruebas unitarias se usan “solo” para pruebas de regresión o pruebas de API públicas, no necesita probar las privadas. Pero si realiza un desarrollo basado en pruebas unitarias, hay buenas razones para probar métodos privados durante el desarrollo (por ejemplo, cuando es difícil burlarse de ciertos parámetros inusuales/extremos a través de la interfaz pública).

    – Marco Freudenberger

    13 de febrero de 2017 a las 14:25

  • @MarcoFreudenberger Veo tu punto. Tengo experiencia en desarrollo guiado por pruebas unitarias. A menudo, cuando se vuelve difícil burlarse de los parámetros, la mayoría de las veces se resuelve cambiando y mejorando el diseño. Todavía tengo que encontrarme con un escenario en el que el diseño sea perfecto y aún así las pruebas unitarias sean extremadamente difíciles de evitar probar métodos privados. Estaré atento a esos casos. Gracias. Apreciaría si pudieras compartir un escenario de tu cabeza para ayudarme a entender.

    – Vishnu Narang

    13 de febrero de 2017 a las 18:56

La codificación de nombres se usa para garantizar que las subclases no anulen accidentalmente los métodos y atributos privados de sus superclases. No está diseñado para evitar el acceso deliberado desde el exterior.

Por ejemplo:

>>> class Foo(object):
...     def __init__(self):
...         self.__baz = 42
...     def foo(self):
...         print self.__baz
...     
>>> class Bar(Foo):
...     def __init__(self):
...         super(Bar, self).__init__()
...         self.__baz = 21
...     def bar(self):
...         print self.__baz
...
>>> x = Bar()
>>> x.foo()
42
>>> x.bar()
21
>>> print x.__dict__
{'_Bar__baz': 21, '_Foo__baz': 42}

Por supuesto, falla si dos clases diferentes tienen el mismo nombre.

  • docs.python.org/2/tutorial/classes.html. Apartado: 9.6 sobre Variables privadas y referencias locales de clase.

    – gjain

    17 de octubre de 2013 a las 0:41

  • Para aquellos de nosotros demasiado perezosos para desplazarse/buscar: Sección 9.6 enlace directo

    – cod3monk3y

    20 de febrero de 2014 a las 4:22


  • Debe poner un solo guión bajo para especificar que la variable debe considerarse privada. Una vez más, esto no impide que alguien acceda a eso.

    – igón

    29/09/2014 a las 21:31

  • Guido respondió a esta pregunta – “La razón principal para hacer que (casi) todo sea detectable fue la depuración: al depurar, a menudo necesitas romper las abstracciones” – Lo agregué como comentario porque es demasiado tarde, demasiadas respuestas.

    – Peter M. – representa a Mónica

    1 de febrero de 2016 a las 19:02

  • Si sigue el criterio de “prevenir el acceso deliberado”, la mayoría de los lenguajes OOP no admiten miembros verdaderamente privados. Por ejemplo, en C++ tiene acceso sin formato a la memoria y en C# el código de confianza puede usar la reflexión privada.

    – CodesInChaos

    13 de julio de 2016 a las 10:40

¿Por que los metodos privados de Python no son realmente
arun

Ejemplo de una función privada

import re
import inspect

class MyClass:

    def __init__(self):
        pass

    def private_function(self):
        try:
            function_call = inspect.stack()[1][4][0].strip()

            # See if the function_call has "self." in the beginning
            matched = re.match( '^self\.', function_call)
            if not matched:
                print 'This is a private function. Go away.'
                return
        except:
            print 'This is a private function. Go away.'
            return

        # This is the real function, only accessible inside the class #
        print 'Hey, welcome in to the function.'

    def public_function(self):
        # I can call a private function from inside the class
        self.private_function()

### End ###

  • self = MyClass() self.private_function(). 😀 Por supuesto que no funciona en las clases, pero solo tienes que definir una función personalizada: def foo(self): self.private_function()

    –Casey Kuball

    8 mayo 2012 a las 16:34


  • Por si no te quedó claro: Nunca haz esto en código real 😉

    – Sudo Bash

    12 de julio de 2013 a las 15:40

  • @ThorSummoner O simplemente function_call.startswith('self.').

    – nyuszika7h

    27 de agosto de 2014 a las 8:52

  • inspect.stack()[1][4][0].strip() <- ¿Qué son esos números mágicos 1, 4 y 0?

    – akhy

    23 de junio de 2016 a las 7:36

  • Esto se puede vencer con bastante facilidad haciendo self = MyClass(); self.private_function() y falla cuando se llama usando x = self.private_function() dentro de un método.

    – Voluntad

    22 de noviembre de 2018 a las 2:58

1646761038 938 ¿Por que los metodos privados de Python no son realmente
Tomas Ahle

Cuando vine por primera vez de Java a Python, odiado esta. Me asustó de muerte.

Hoy podría ser la única cosa me gusta más sobre Python.

Me encanta estar en una plataforma, donde las personas confían entre sí y no sienten la necesidad de construir muros impenetrables alrededor de su código. En lenguajes fuertemente encapsulados, si una API tiene un error y ha descubierto qué es lo que falla, es posible que aún no pueda solucionarlo porque el método necesario es privado. En Python la actitud es: “seguro”. Si crees que entiendes la situación, tal vez incluso la hayas leído, entonces todo lo que podemos decir es “¡buena suerte!”.

Recuerde, la encapsulación no está ni siquiera débilmente relacionada con la “seguridad” o con mantener a los niños fuera del césped. Es solo otro patrón que debe usarse para hacer que una base de código sea más fácil de entender.

  • @CamJackson ¿Javascript es tu ejemplo? ¿El único lenguaje ampliamente utilizado que tiene herencia basada en prototipos y un lenguaje que favorece la programación funcional? Creo que JS es mucho más difícil de aprender que la mayoría de los otros lenguajes, ya que toma varios pasos ortogonales de la programación orientada a objetos tradicional. No es que esto evite que los idiotas escriban JS, simplemente no lo saben;)

    – K. Steff

    10 de abril de 2012 a las 1:45

  • Las API son en realidad un muy buen ejemplo de por qué es importante la encapsulación y cuándo se preferirían los métodos privados. Un método destinado a ser privado puede desaparecer, cambiar la firma o, lo que es peor, cambiar el comportamiento, todo sin previo aviso, en cualquier versión nueva posterior. ¿Recordará realmente su inteligente miembro adulto del equipo que accedió a un método destinado a ser privado dentro de un año cuando actualice? ¿Seguirá trabajando allí?

    – einocente

    10 de enero de 2014 a las 0:35

  • No estoy de acuerdo con el argumento. En el código de producción, lo más probable es que nunca use una API que tenga un error que me haga cambiar los miembros públicos para que “funcione”. Una API debería funcionar. Si no es así, presentaría un informe de error o crearía la misma API yo mismo. No me gusta la filosofía y no soy muy aficionado a Python, aunque su sintaxis hace que sea divertido escribir scripts más pequeños en…

    –Yngve Sneen Lindal

    19 de febrero de 2014 a las 11:45

  • Java tiene Method.setAccessible y Field.setAccessible. ¿También da miedo?

    – Tony

    24/04/2014 a las 17:15

  • La aplicación en Java y C++ no se debe a que Java desconfíe del usuario mientras que Python sí lo hace. Se debe a que el compilador y/o la máquina virtual pueden hacer varias suposiciones cuando se trata de cómo funciona su negocio si conocen esta información, por ejemplo, C ++ puede omitir una capa completa de direccionamiento indirecto al usar llamadas C antiguas regulares en lugar de llamadas virtuales, y eso Importa cuando se trabaja en material de alto rendimiento o alta precisión. Python, por su naturaleza, no puede hacer un buen uso de la información sin comprometer su dinamismo. Ambos idiomas apuntan a cosas diferentes, por lo que ninguno está “equivocado”

    – Shayne

    4 sep 2016 a las 11:25


1646761038 142 ¿Por que los metodos privados de Python no son realmente
xsl

Desde Sumérgete en Python, 3.9. Funciones privadas:

Estrictamente hablando, los métodos privados son accesibles fuera de su clase, pero no fácilmente accesibles. Nada en Python es verdaderamente privado; internamente, los nombres de los métodos y atributos privados se modifican y se modifican sobre la marcha para que parezcan inaccesibles por sus nombres de pila. Puede acceder al método __parse de la clase MP3FileInfo con el nombre _MP3FileInfo__parse. Reconozca que esto es interesante, luego prometa que nunca lo hará en código real. Los métodos privados son privados por una razón, pero como muchas otras cosas en Python, su privacidad es, en última instancia, una cuestión de convención, no de fuerza.

¿Por que los metodos privados de Python no son realmente
tony meyer

La frase comúnmente utilizada es “aquí todos somos adultos que consienten”. Al anteponer un guión bajo simple (no exponer) o un guión bajo doble (ocultar), le está diciendo al usuario de su clase que pretende que el miembro sea ‘privado’ de alguna manera. Sin embargo, está confiando en que todos los demás se comporten de manera responsable y lo respeten, a menos que tengan una razón convincente para no hacerlo (por ejemplo, depuradores y finalización de código).

Si realmente debe tener algo que sea privado, puede implementarlo en una extensión (por ejemplo, en C para CPython). En la mayoría de los casos, sin embargo, usted simplemente aprende el pitónico forma de hacer las cosas.

  • Entonces, ¿hay algún tipo de protocolo contenedor que se supone que debo usar para acceder a una variable protegida?

    – intuido

    10 mayo 2010 a las 18:56

  • No hay variables “protegidas” más de lo que hay “privadas”. Si desea acceder a un atributo que comienza con un guión bajo, puede hacerlo (pero tenga en cuenta que el autor desaconseja esto). Si debe acceder a un atributo que comienza con un doble guión bajo, puede modificar el nombre usted mismo, pero es casi seguro que no desea hacerlo.

    – Tony Mayer

    13 de mayo de 2010 a las 8:41

1646761039 191 ¿Por que los metodos privados de Python no son realmente
Pedro Mortensen

No es que no pueda sortear la privacidad de los miembros en ningún idioma (aritmética de punteros en C++ y reflejos en .NET/Java).

El punto es que obtiene un error si intenta llamar al método privado por accidente. Pero si quieres pegarte un tiro en el pie, adelante, hazlo.

No intenta proteger sus cosas mediante encapsulación OO, ¿verdad?

  • Entonces, ¿hay algún tipo de protocolo contenedor que se supone que debo usar para acceder a una variable protegida?

    – intuido

    10 mayo 2010 a las 18:56

  • No hay variables “protegidas” más de lo que hay “privadas”. Si desea acceder a un atributo que comienza con un guión bajo, puede hacerlo (pero tenga en cuenta que el autor desaconseja esto). Si debe acceder a un atributo que comienza con un doble guión bajo, puede modificar el nombre usted mismo, pero es casi seguro que no desea hacerlo.

    – Tony Mayer

    13 de mayo de 2010 a las 8:41

Nota IMPORTANTE:

Cualquier identificador del formulario __name (al menos dos guiones bajos iniciales, como máximo un guión bajo final) se reemplaza públicamente por _classname__namedonde classname es el nombre de la clase actual sin los guiones bajos iniciales.

Por lo tanto, __name no es accesible directamente, pero se puede acceder como_classname__name.

Esto no significa que pueda proteger sus datos privados, ya que se puede acceder a ellos fácilmente cambiando el nombre de la variable.

Fuente:

Sección “Variables privadas” en la documentación oficial: https://docs.python.org/3/tutorial/classes.html#tut-private

Ejemplo

class Cat:
    def __init__(self, name="unnamed"):
        self.name = name
    def __print_my_name(self):
        print(self.name)
        
        
tom = Cat()
tom.__print_my_name() #Error
tom._Cat__print_my_name() #Prints name

  • Esta no es una actualización importante, siempre ha sido así. Reemplazando el 3 con un 2 en tu enlace, docs.python.org/2/tutorial/classes.html#tut-private, revela casi exactamente el mismo texto en el que hiciste tu respuesta. NO una actualización.

    – Juan

    8 de julio de 2021 a las 10:07

  • Esto también es falso: __name no es “privado”, ya que es accesible usando _classname__name. Algo accesible NO es “privado”. No existe tal cosa como un atributo “privado”, en ningún lenguaje informático importante (AFAIK), es tan simple como eso. Puede decir que las variables locales en un método son “privadas”, pero solo si no son accesibles desde fuera del método de ninguna manera.

    – mike roedor

    27 de noviembre de 2021 a las 19:37


  • Eso ya está explicado en la respuesta. Sin embargo, con esa definición, y diciendo que “No existe tal cosa como un atributo privado, en ningún lenguaje informático importante”, entonces tenemos que redefinir “privado” en los lenguajes de programación. Pero hasta entonces, podemos usar lo que tenemos y llamarlo privado, ya que los documentos oficiales lo llaman “privado”.

    – Moradnejad

    28 de noviembre de 2021 a las 20:16

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad