Saltar al contenido

Propiedad de solo lectura de Python

Solución:

Generalmente, los programas de Python deben escribirse asumiendo que todos los usuarios son adultos que consienten y, por lo tanto, son responsables de usar las cosas correctamente ellos mismos. Sin embargo, en el raro caso en el que simplemente no tiene sentido que un atributo sea configurable (como un valor derivado o un valor leído de alguna fuente de datos estática), la propiedad de solo captador es generalmente el patrón preferido.

Solo mis dos centavos, Silas Ray está en el camino correcto, sin embargo, tuve ganas de agregar un ejemplo. 😉

Python es un lenguaje de tipo inseguro y, por lo tanto, siempre tendrá que confiar en los usuarios de su código para usar el código como una persona razonable (sensata).

Por PEP 8:

Utilice un guión bajo inicial solo para métodos no públicos y variables de instancia.

Para tener una propiedad de ‘solo lectura’ en una clase, puede hacer uso de la @property decoración, necesitarás heredar de object cuando lo haga para hacer uso de las clases de estilo nuevo.

Ejemplo:

>>> class A(object):
...     def __init__(self, a):
...         self._a = a
...
...     @property
...     def a(self):
...         return self._a
... 
>>> a = A('test')
>>> a.a
'test'
>>> a.a="pleh"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

Aquí hay una forma de evitar la suposición de que

todos los usuarios son adultos que consienten y, por lo tanto, son responsables de usar las cosas correctamente por sí mismos.

por favor mira mi actualización a continuación

Utilizando @property, es muy detallado, por ejemplo:

   class AClassWithManyAttributes:
        '''refactored to properties'''
        def __init__(a, b, c, d, e ...)
             self._a = a
             self._b = b
             self._c = c
             self.d = d
             self.e = e

        @property
        def a(self):
            return self._a
        @property
        def b(self):
            return self._b
        @property
        def c(self):
            return self._c
        # you get this ... it's long

Utilizando

Sin subrayado: es una variable pública.
Un subrayado: es una variable protegida.
Dos guiones bajos: es una variable privada.

Excepto el último, es una convención. Aún puede, si realmente se esfuerza, acceder a las variables con doble subrayado.

¿Asi que que hacemos? ¿Renunciamos a tener propiedades de solo lectura en Python?

¡Mirad! read_only_properties decorador al rescate!

@read_only_properties('readonly', 'forbidden')
class MyClass(object):
    def __init__(self, a, b, c):
        self.readonly = a
        self.forbidden = b
        self.ok = c

m = MyClass(1, 2, 3)
m.ok = 4
# we can re-assign a value to m.ok
# read only access to m.readonly is OK 
print(m.ok, m.readonly) 
print("This worked...")
# this will explode, and raise AttributeError
m.forbidden = 4

Usted pregunta:

Dónde está read_only_properties ¿procedente de?

Me alegro de que lo hayas preguntado, aquí está la fuente de read_only_properties:

def read_only_properties(*attrs):

    def class_rebuilder(cls):
        "The class decorator"

        class NewClass(cls):
            "This is the overwritten class"
            def __setattr__(self, name, value):
                if name not in attrs:
                    pass
                elif name not in self.__dict__:
                    pass
                else:
                    raise AttributeError("Can't modify {}".format(name))

                super().__setattr__(name, value)
        return NewClass
    return class_rebuilder

actualizar

Nunca esperé que esta respuesta recibiera tanta atención. Sorprendentemente lo hace. Esto me animó a crear un paquete que puedas usar.

$ pip install read-only-properties

en tu caparazón de Python:

In [1]: from rop import read_only_properties

In [2]: @read_only_properties('a')
   ...: class Foo:
   ...:     def __init__(self, a, b):
   ...:         self.a = a
   ...:         self.b = b
   ...:         

In [3]: f=Foo('explodes', 'ok-to-overwrite')

In [4]: f.b = 5

In [5]: f.a="boom"
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-5-a5226072b3b4> in <module>()
----> 1 f.a="boom"

/home/oznt/.virtualenvs/tracker/lib/python3.5/site-packages/rop.py in __setattr__(self, name, value)
    116                     pass
    117                 else:
--> 118                     raise AttributeError("Can't touch {}".format(name))
    119 
    120                 super().__setattr__(name, value)

AttributeError: Can't touch a
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *