subclases - python poo tutorial
Miembros privados en Python (8)
Las variables de instancia "privadas" a las que no se puede acceder, excepto desde dentro de un objeto, no existen en Python. Sin embargo, hay una convención que es seguida por la mayoría del código de Python: un nombre prefijado con un guión bajo (por ejemplo, _spam) debe tratarse como una parte no pública de la API (ya sea una función, un método o un miembro de datos) . Se debe considerar un detalle de implementación y está sujeto a cambios sin previo aviso.
Como existe un caso de uso válido para los miembros privados de la clase (es decir, para evitar los conflictos de nombres de nombres con nombres definidos por subclases), existe un apoyo limitado para dicho mecanismo, llamado mangling. Cualquier identificador de la forma __spam (al menos dos guiones bajos principales, como máximo un guión bajo final) se reemplaza textualmente por
_classname__spam
, donde classname es el nombre de la clase actual con guiones bajos destacados. Este cambio se realiza sin tener en cuenta la posición sintáctica del identificador, siempre que ocurra dentro de la definición de una clase.
Entonces, por ejemplo ,
class Test:
def __private_symbol(self):
pass
def normal_symbol(self):
pass
print dir(Test)
dará salida:
[''_Test__private_symbol'',
''__doc__'',
''__module__'',
''normal_symbol'']
__private_symbol
debe considerar como un método privado, pero aún se podrá acceder a través de _Test__private_symbol
.
¿Cómo puedo hacer que los métodos y los datos sean privados en Python? ¿O Python no es compatible con los miembros privados?
Si el nombre de una función de Python, método de clase o atributo comienza con (pero no termina con) dos guiones bajos, es privado; todo lo demás es público. Python no tiene ningún concepto de métodos de clases protegidos (accesibles solo en su propia clase y clases descendientes). Los métodos de clase son privados (accesibles solo en su propia clase) o públicos (accesibles desde cualquier lugar).
Esta es una respuesta bastante larga, pero creo que llega a la raíz del problema real aquí: el alcance de la visibilidad. ¡Quédate ahí mientras sigo con esto!
La simple importación de un módulo no necesariamente le da al desarrollador de la aplicación acceso a todas sus clases o métodos; si realmente no puedo VER el código fuente del módulo, ¿cómo sabré qué hay disponible? Alguien (o algo) tiene que decirme qué puedo hacer y explicarme cómo usar esas características que tengo permitido usar, de lo contrario, todo es inútil para mí.
Aquellos que desarrollan abstracciones de alto nivel basadas en clases y métodos fundamentales a través de módulos importados se presentan con una especificación DOCUMENTO, NO el código fuente real.
La especificación del módulo describe todas las características destinadas a ser visibles 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 SIEMPRE debe permanecer oculta de quienes lo usan, es una blackbox con una interfaz para el mundo exterior. Para los puristas de OOD, creo que los términos tecnológicos son "desacoplamiento" y "coherencia". El usuario del módulo solo necesita conocer los métodos de interfaz sin agobiarse con los detalles de la implementación.
Un módulo NUNCA debe cambiarse sin antes cambiar 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 hobby (retirado ahora), comienzo un nuevo módulo con el doc de especificaciones realmente escrito 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 soy solo yo, aún tengo que configurar una biblioteca, pero sería bastante fácil de hacer.
Luego empiezo a codificar escribiendo las diversas clases y métodos pero sin cuerpos funcionales, solo declaraciones de impresión nula como "print ()", solo lo suficiente para permitir que el módulo se compile sin errores de sintaxis. Cuando este paso se completa, compilo el módulo nulo completado: esta es mi especificación. Si estuviera trabajando en un equipo de proyecto, presentaría esta especificación / interfaz para su revisión y comentarios antes de proceder a dar cuerpo al cuerpo.
Completo los cuerpos de cada método de uno en uno y los compilo en consecuencia, asegurándome de que los errores de sintaxis se solucionen inmediatamente sobre la marcha. Este es también un buen momento para comenzar a escribir una sección de ejecución "principal" temporal en la parte inferior para probar cada método a medida que lo codifica. Cuando se completa la codificación / prueba, todo el código de prueba se comenta hasta que lo necesite de nuevo en caso de que las actualizaciones sean necesarias.
En un equipo de desarrollo del mundo real, el bloque de comentarios de especificaciones también aparecería en una biblioteca de control de documentos, pero esa es otra historia. El punto es: usted, como cliente del módulo, solo ve esta especificación y NO el código fuente.
PD: mucho antes del comienzo de los tiempos, trabajé en la comunidad aeroespacial de defensa e hicimos algunas cosas geniales, pero cosas como algoritmos patentados y lógica de control de sistemas sensibles fueron estrechamente abovedados y encriptados en bibliotecas de software seguras super-duper. Tuvimos acceso a las interfaces de módulo / paquete pero NO a los cuerpos de implementación de Blackbox. Había una herramienta de gestión de documentos que manejaba todos los diseños a nivel de sistema, las especificaciones de software, el código fuente y los registros de prueba: todo estaba sincronizado. El gobierno tenía estrictos requisitos de estándares de garantía de calidad de software. Alguien recuerda un idioma llamado "Ada"? ¡Así de viejo soy!
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()
Las otras respuestas proporcionan los detalles técnicos. Me gustaría enfatizar la diferencia en filosofía entre Python, por un lado, y lenguajes como C ++ / Java (que supongo que está familiarizado con su pregunta).
La actitud general en Python (y Perl para el caso) es que la ''privacidad'' de un atributo es una solicitud al 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 a menudo se la conoce como "Todos aceptamos a adultos", ya que "supone" que el programador es lo suficientemente responsable como para no interferir con el interior. Los caracteres de subrayado iniciales sirven como un mensaje cortés que indica que el atributo es interno.
Por otro lado, si desea acceder a las partes internas de algunas aplicaciones (un ejemplo notable es generadores de documentación como pydoc), puede hacerlo. Le corresponde a usted como programador saber qué está haciendo y hacerlo correctamente en lugar de hacerlo en el idioma para obligarlo a hacer las cosas de la manera que sea.
No hay ningún otro mecanismo de protección de acceso private
en Python. Existe una convención documentada en la guía de estilo de Python para indicar a los usuarios de su clase que no deberían acceder a determinado atributo.
_single_leading_underscore: indicador de "uso interno" débil. Por ejemplo,
from M import *
no se importan objetos cuyo nombre comienza con un guión bajo.single_trailing_underscore_: utilizado por convención para evitar conflictos con la palabra clave Python, p. ej.
Tkinter.Toplevel(master, class_=''ClassName'')
__double_leading_underscore: cuando se nombra un atributo de clase, se invoca el mangle del nombre (dentro de la clase FooBar, __boo se convierte en _FooBar__boo; ver a continuación).
Python no es compatible con la privacidad directamente. El programador necesita saber cuándo es seguro modificar el atributo desde el exterior, pero de todos modos con Python puede lograr algo así como privacidad con pequeños trucos. Ahora veamos que una persona puede ponerle algo privado 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 ejecutaremos:
>>> 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
Entonces, ¿cómo alguien puede acceder a esa variable?
Puedes hacer como:
>>>p._Person__priva I am Private
Wow, en realidad, si python obtiene cualquier variable que comience con doble guión bajo se "traduce" al agregar un guion bajo y el nombre de la clase al principio:
Nota: Si no desea que cambie este nombre pero aún desea enviar una señal para que otros objetos permanezcan alejados, puede usar un único guion bajo inicial con un guion bajo inicial que no se importa con importaciones marcadas (desde la importación del módulo *)
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 si llamaremos a _hello manualmente.
#test2.py from test import _hello , hello print hello() print _hello()
salida ->
hello hello private
Finalmente: Python no tiene realmente un soporte de privacidad equivalente, aunque los guiones iniciales simples y dobles le otorgan en cierta medida dos niveles de privacidad
si desea que los métodos o los miembros de datos sean privados en Python, use __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()