2012-01-26 38 views
8

Sé que los atributos de la clase que se declaran con el subrayado doble __ prefijo pueden o no estar visibles fuera de la definición de la clase. Como todavía podemos acceder a esos atributos por object._className__attrName.Ocultamiento de datos en Python Clase

class A: 
    def __init__(self): 
     self.a = 1 
     self.b = 2 
     ---- 
     ---- 
     self.z = 26 
     self.catch = 100 

ahora para proteger a todos los atributos excepto para el catch, tengo que declarar con doble subrayado que es bastante desordenado. ¿Hay alguna manera de decir en la definición de mi clase que solo se puede acceder al self.catch fuera de la clase?

Disculpas si se responde en otro lugar o se menciona anteriormente.

+1

No. Sin embargo, a menos que sea realmente paranoico, el hecho de que alguien * pueda * acceder a un objeto usando 'object._className__attrName' no es un gran problema. Realmente solo quieres evitar que las personas accedan accidentalmente a las variables que no deberían cuando usas tu código. La ofuscación logra ese objetivo. – Chris

+2

posible duplicado de [¿Python tiene variables 'privadas' en las clases?] (Http://stackoverflow.com/questions/1641219/does-python-have-private-variables-in-classes) –

+0

@ BjörnPollex, esto no es así t lo que está pidiendo. Quiere la necesidad de un "operador" explícito "público", no lo contrario. –

Respuesta

16

Sí, es posible ocultar los datos privados en un cierre - al menos, si hay una manera de acceder a private desde fuera make_A, no he encontrado:

def make_A(): 
    private = { 
     'a' : 1, 
     'b' : 2, 
     'z' : 26, 
     } 
    class A: 
     def __init__(self): 
      self.catch = 100 
      private['a'] = 2 # you can modify the private data 
     def foo(self): 
      print(private['a']) # you can access the private data 
    return A 

A = make_A() 

a=A() 

a.foo() 
# 2 

en cuenta que private no está en dir(a)

print('private' in dir(a)) 
# False 

Aunque esto es posible, no creo que esta es la forma recomendable para programar en Python.


arriba, private es compartida por todas las instancias de A. Para utilizar los datos privados en una base por ejemplo, añadir self a la tecla dict:

def make_A(): 
    private = {} 
    class A: 
     def __init__(self): 
      self.catch = 100 
      private[self,'a'] = 1 # you can modify the private data 
      private[self,'b'] = 2  
      private[self,'z'] = 26  
     def foo(self): 
      print(private[self,'a']) # you can access the private data 
    return A 
+2

+1 para el ocultamiento de datos al estilo de cierre. – 9000

+0

Thumbs up for *** closures **. Esto puede ser de interés: [Secret Variables i Python] (http://www.jotflow.com/jot/Secret-Variables-In-Python/5). Compara el ocultamiento de datos funcionales en Python con variables privadas en Java. –

1

No, ya que es parte del nombre, no se puede hacer eso.

Bueno, en realidad puede hacerlo mediante hackers con los getters/setters, pero en general no debería hacerlo.

1

¿Por qué querría para proteger atributos?

Si desea proteger los atributos contra sobreescritura inadvertida, use doble guión bajo y, probablemente, propiedades listas para facilitar el acceso. Pero la mayoría de las veces, you aint't gonna need it. Solo hazte un favor y deja los atributos abiertos, esto hace que la depuración sea mucho más fácil.

Si usted quiere proteger su objeto de la manipulación por parte de terceros, se puede jugar con __getattr__ y __setattr__, pero probablemente no se debe pasar a un cliente que no se confía objetos con datos protegidos en absoluto, utilice el facade pattern lugar y ocultar sus objetos de valor más opacamente Es posible que desee replantearse su arquitectura, también.

+1

* ¿Por qué podría querer proteger los atributos? * Podría indicarle la entrada del wiki sobre encapsulación, pero le daré un ejemplo práctico. Digamos que tienes una aplicación python grande y compleja en la que tienes varias clases con el atributo 'nombre'. Se encuentra un error en el cual el nombre del administrador de la clase se anula incorrectamente. Si dejó abierto el atributo de nombre como sugiere, ¿cómo va a encontrar la línea ofensiva de código? Si ha ocultado el atributo y los descriptores de acceso utilizados, puede colocar un punto de interrupción en el captador y encontrar al culpable rápidamente. – dar512

+0

@ dar512: si su clase es parte de una interfaz pública, y los clientes pueden alterar los atributos, ¡crívelos por medio de los usuarios! Sin embargo, el número de clases públicas es bastante limitado en una aplicación típica. Además, usar datos inmutables tiene numerosas ventajas; A menudo uso subclases de 'namedtuple' para representar los datos de una manera a prueba de balas. – 9000

+0

Como programador, si elijo dispararme a mi propia pierna con una escopeta, que así sea. Estás limitando mi capacidad para corregir/alterar tu código ocultando cosas. Las palabras clave 'protegida' y 'privada' son solo antipatrones. Por favor, abandona la idea de que le estás haciendo un favor a alguien "ocultando" cosas de otros programadores. Si desea hacer algo como esto, use '_variable' y proporcione una propiedad getter' variable' y no setter. Todavía puedo modificar manualmente la '_variable' de esta manera si así lo deseo. Pero no use hacks de lenguaje para ofuscar su funcionamiento interno de otros programadores. – Rebs

3

Mientras que la respuesta aceptada por unutbu parece una buena idea para ocultar los datos, el diccionario private siendo accesible mediante __closure__ (este atributo no se puede quitar):

def make_A(): 
    private = {} 
    class A: 
     def __init__(self): 
      self.catch = 100 
      private[self,'a'] = 1 # you can modify the private data 
      private[self,'b'] = 2  
      private[self,'z'] = 26  
     def foo(self): 
      print(private[self,'a']) # you can access the private data 
    return A 


A = make_A() 
a = A() 
a.foo() # 1 
a.foo.__closure__[0].cell_contents[(a, 'a')] = 42 
a.foo() # 42 

o seguir el enlace proporcionado por Sumukh Barve en el comentarios:

def createBankAccount(): 
    private = {'balance': 0.0} 
    def incr(delta): 
     private['balance'] += delta; 
    account = { 
     'deposit': lambda amount: incr(amount), 
     'withdraw': lambda amount: incr(-amount), 
     'transferTo': lambda otherAccount, amount: (
      account['withdraw'](amount), 
      otherAccount['deposit'](amount) 
     ), 
     'transferFrom': lambda otherAccount, amount: (
      otherAccount['transferTo'](account, amount) 
     ), 
     'getBalance': lambda : private['balance'] 
    } 
    return account; 


account = createBankAccount() 

print(account['getBalance']()) 
account['getBalance'].__closure__[0].cell_contents['balance'] = 1000**1000 
print(account['getBalance']()) # I can buy a couple of nations 

I bevile la única manera de crear private atributos es escribir algunos k ind de CPython extensión.

+0

gracias por eso –