Los miembros privados en Python
-
20-09-2019 - |
Pregunta
¿Cómo puedo hacer que los métodos y los miembros de datos privados en Python? O no de apoyo Python miembros privados?
Solución
variables de instancia “privado” que no se puede acceder desde el interior excepto un objeto, no existen en Python. Sin embargo, hay una convención que es seguido por la mayoría de código Python: un nombre prefijado con un guión (por ejemplo _spam) debe ser tratado como una parte no pública de la API (si es una función, un método o un conjunto de datos miembro). Se debe considerar una detalle de implementación y sujeto a cambios sin previo aviso.
Dado que no es un caso de uso válido para miembros de la clase-privada (es decir, para evitar nombrar choques de nombres con nombres definido por las subclases), hay soporte limitado para tal mecanismo, llamada renombrado de nombres. cualquier identificador de la forma __spam (al menos dos subrayado iniciales, a lo sumo uno subrayado de salida) es textualmente sustituido con
_classname__spam
, donde nombre de clase es el nombre de la clase actual con subrayado inicial (s) despojado. Este calandrado se realiza sin tener en cuenta a la posición sintáctica de la identificador, con tal de que se produce dentro de la definición de una clase.
Así, por ejemplo ,
class Test:
def __private_symbol(self):
pass
def normal_symbol(self):
pass
print dir(Test)
es la salida:
['_Test__private_symbol',
'__doc__',
'__module__',
'normal_symbol']
__private_symbol
debe considerarse como un método privado, pero aún así sería accesible a través de _Test__private_symbol
.
Otros consejos
Las otras respuestas proporcionan los detalles técnicos. Me gustaría hacer hincapié en la diferencia entre la filosofía Python en una mano y lenguajes como C ++ / Java (que supongo que usted está familiarizado con la base de su pregunta).
La actitud general en Python (y Perl para el caso) es que la 'privacidad' de un atributo es una solicitud para el programador en lugar de una valla de alambre de púas por el compilador / intérprete. La idea se resume bien en este correo y se refiere a menudo como "Estamos todos los adultos que consienten", ya que 'supone' que el programador es lo suficientemente responsable para no interferir con las entrañas. Los subrayado iniciales sirven como un amable mensaje diciendo que el atributo es interno.
Por otro lado, si hace desea acceder a los componentes internos para algunas aplicaciones (un ejemplo notable es como generadores de documentación pydoc), usted es libre de hacerlo. Es responsabilidad de usted como un programador para saber lo que está haciendo y hacerlo correctamente y no en la lengua a la fuerza que hace que las cosas es manera.
No hay private
de cualesquiera otros mecanismos de protección de acceso en Python. Existe una convención documentado en el guía de estilo de Python para indicar a los usuarios de su clase que no se debe acceder a determinados atributos.
-
_single_leading_underscore: débil indicador de "uso interno". P.ej.
from M import *
no importa objetos cuyo nombre empieza con un guión bajo. -
single_trailing_underscore_: usado por convención para evitar conflictos con palabra clave Python, por ejemplo,
Tkinter.Toplevel(master, class_='ClassName')
-
__ double_leading_underscore: al nombrar un atributo de clase, invoca nombre mangling (dentro clase FooBar, __boo convierte _FooBar__boo; ver más abajo)
.
Si el nombre de una función de Python, método de clase, o atributo comienza con (Pero no termina con) dos subraya, que es privado; todo lo demás es público. Python no tiene ningún concepto de métodos de clase protegidas (accesible sólo en su propia clase y descendiente clases). Los métodos de clase son ya sea privada (accesible sólo en su propio clase) o público (accesible desde en cualquier lugar).
Python no soporta directamente la privacidad. Programador necesita saber cuándo es seguro para modificar el atributo desde fuera, pero de todas formas con el pitón se puede lograr algo como privado con pequeños trucos. Ahora vamos a ver una persona puede poner cualquier cosa privada a él o no.
class Person(object): def __priva(self): print "I am Private" def publ(self): print " I am public" def callpriva(self): self.__priva()
Ahora cuando vamos a ejecutar:
>>> p = Person() >>> p.publ() I am public >>> p.__priva() Traceback (most recent call last): File "", line 1, in p.__priva() AttributeError: 'Person' object has no attribute '__priva' #Explanation : You can see here we are not able to fetch that private method directly. >>> p.callpriva() I am Private #Explanation : Here we can access private method inside class
A continuación, cómo alguien puede tener acceso a esa variable ???
Usted puede hacer como:
>>>p._Person__priva I am Private
wow, en realidad, si se está pitón cualquier variable comenzando con doble subrayado son “traduce” mediante la adición de un único guión bajo y el nombre de la clase al principio:
Nota: Si no desea cambiar el nombre, pero que todavía quiere enviar una señal para otros objetos que se mantenga alejado, se puede utilizar un solo nombres iniciales de subrayado con un guión inicial no están importados con las importaciones (con estrellas de módulo de importación *)
Ejemplo:
#test.py def hello(): print "hello" def _hello(): print "Hello private" #----------------------
#test2.py from test import * print hello() print _hello()
salida ->
hello Traceback (most recent call last): File "", line 1, in NameError: name '_hello' is not defined
Ahora bien, si vamos a llamar _hello manualmente.
#test2.py from test import _hello , hello print hello() print _hello()
salida ->
hello hello private
Por último: Python no tiene realmente un soporte de privacidad equivalente, aunque solo y dobles guiones iniciales hacen en cierta medida le dará dos niveles de privacidad
Esto podría funcionar:
import sys, functools
def private(member):
@functools.wraps(member)
def wrapper(*function_args):
myself = member.__name__
caller = sys._getframe(1).f_code.co_name
if (not caller in dir(function_args[0]) and not caller is myself):
raise Exception("%s called by %s is private"%(myself,caller))
return member(*function_args)
return wrapper
class test:
def public_method(self):
print('public method called')
@private
def private_method(self):
print('private method called')
t = test()
t.public_method()
t.private_method()
Esto es un poco la l-o-n-g respuesta, pero creo que va a la raíz del problema real aquí - alcance de visibilidad. Simplemente colgar en él, mientras que sudar tinta a través de esto!
Simplemente importar un módulo no necesita necesariamente para obtener el acceso a los desarrolladores de aplicaciones a todas sus clases o métodos; si no puedo ver realmente el código fuente del módulo cómo voy a saber lo que está disponible? Alguien (o algo) tiene que decirme lo que puedo hacer y explicar cómo utilizar estas características que se me permite utilizar, de lo contrario todo es inútil para mí.
Aquellos desarrollo abstracciones de alto nivel basado en clases y métodos a través de los módulos importados fundamentales son presentados con un documento de especificación - no el código fuente real.
La especificación módulo describe todas las características destinadas a ser visible para el desarrollador del cliente. Cuando se trata de grandes proyectos y equipos de proyectos de software, la implementación real de un módulo debe permanecer siempre oculta a personas que hagan uso - es una caja negra con una interfaz con el mundo exterior. Para los puristas OOD, creo que los términos son aficionados a la tecnología "desacoplamiento" y "coherencia". El usuario sólo tiene que saber módulo de los métodos de interfaz sin ser carga con los detalles de implementación.
Un módulo no se debe cambiar sin cambiar primero su documento de especificación subyacente, que puede requerir revisión / aprobación en algunas organizaciones antes de cambiar el código.
Como programador de manía (retirado ahora), que se inicia un nuevo módulo con el documento de especificaciones escritas en realidad como un bloque de comentario gigante en la parte superior del módulo, esta será la parte que el usuario realmente ve en la biblioteca de especificaciones. Ya que sólo yo, todavía tengo que configurar una biblioteca, pero sería bastante fácil de hacer.
Entonces comenzará la codificación escribiendo las diversas clases y métodos, pero sin cuerpos funcionales - sólo declaraciones de impresión nulos como "print ()" - lo suficiente para que el módulo para compilar sin errores de sintaxis. Cuando se completa este paso compilo el nulo finalización de los módulos - este es mi especificación. Si estuviera trabajando en un equipo de proyecto, me gustaría presentar esta especificación / interfaz para su revisión y comentarios antes de proceder a dar cuerpo a cuerpo.
I dar cuerpo a los cuerpos de cada método de uno a la vez y compilar en consecuencia, asegurando errores de sintaxis se fijaron inmediatamente sobre la marcha. Este es también un buen momento para comenzar a escribir una sección de ejecución temporal "principal" en la parte inferior para probar cada método a medida que codificarlo. Cuando la codificación / pruebas, poner todo el código de prueba esté comentada hasta que necesite volver a ser necesario actualizaciones.
En un equipo de desarrollo en el mundo real, el módulo de comentarios de especificaciones que también aparecerá en una biblioteca de control de documentos, pero eso es otra historia. El punto es:. Usted, como cliente de módulo, sólo se ve esta especificación y no el código fuente
PD: mucho antes del comienzo de los tiempos, trabajé en la comunidad de defensa aeroespacial e hicimos algunas cosas bastante fresco, pero cosas como algoritmos y sistemas sensibles lógica de control estaban fuertemente abovedado y cifrado en bibliotecas de software seguro de aúpa. Tuvimos acceso a las interfaces de módulos / paquete, pero no los cuerpos de implementación de la caja negra. Hubo una herramienta de gestión de documentos que maneja todos los diseños a nivel de sistema, especificaciones de software, código fuente y los registros de prueba - se sincroniza todos juntos. El gobierno tenía estrictos estándares de control de calidad de software requisitos. Alguien recuerda un lenguaje llamado "Ada"? Esa es la edad que tengo!
utilizo Python 2.7 y 3.5. Escribí este código:
class MyOBject(object):
def __init__(self):
self.__private_field = 10
my_object = MyOBject()
print(my_object.__private_field)
corrieron y tiene:
AttributeError: objeto 'myObject' no tiene atributo '__private_field'
Por favor, consulte: https://www.tutorialsteacher.com/python/ -y-acceso-modificadores protegidas privadas-en-pitón
Si desea realizar un métodos o miembros de datos privados en Python, utilizar __setattr __
class Number:
def __init__(self,value):
self.my_private = value
def __setattr__(self, my_private, value):
# the default behavior
# self.__dict__[my_private] = value
raise Exception("can't access private member-my_private")
def main():
n = Number(2)
print(n.my_private)
if __name__ == '__main__':
main()