30 · Encapsulación: propiedades y nombres protegidos
@property convierte un método en atributo — perfecto para valores calculados y escrituras validadas. Python confía en ti con convención sobre imposición.
Python no tiene **control de acceso impuesto** — `_subrayado_simple` es una convención que significa "interno, por favor no toques", y `__doble_subrayado` activa el name-mangling para evitar colisiones en subclases. `@property` te permite exponer un método como atributo de solo lectura (o escritura validada) — los callers usan la sintaxis `obj.valor` mientras la clase controla lo que realmente ocurre.
Sin esto:
Sin `@property`, los valores calculados (Fahrenheit desde Celsius) requieren una llamada explícita al método — `temp.to_fahrenheit()`. Con `@property`, la API se lee como `temp.fahrenheit` — más natural y compatible con código que espera atributos simples.
Los desarrolladores de Java a menudo recurren a campos privados y métodos getter/setter por reflejo. La filosofía de Python es distinta: empieza con un atributo público simple. Si más tarde necesitas validación o un valor calculado, puedes reemplazar el atributo con un @property sin cambiar el código del caller — porque obj.x y obj.x = v se ven exactamente igual tanto si x es un atributo simple como una propiedad.
@property define un getter que se llama cuando lees obj.attr. @attr.setter define un setter llamado cuando escribes obj.attr = valor. @attr.deleter es raro — se llama cuando haces del obj.attr.
Convenciones de nombres:
_nombre— subrayado simple inicial. Señala "interno, tratar como privado por convención". Nada impide el acceso desde fuera — Python simplemente confía en ti.__nombre— doble subrayado inicial. Python lo reescribe como_NombreClase__nombreen tiempo de análisis (name mangling). Esto evita que una subclase sombree accidentalmente un atributo con el mismo nombre — no es realmente privado.
La regla Pythónica: no escribas Java en Python. La mayoría de los atributos deberían ser simplemente públicos. Añade @property solo cuando genuinamente necesites validación, un valor calculado o inicialización perezosa.
Python (in browser)
Desde la perspectiva del caller, `t.fahrenheit` parece exactamente un atributo simple — sin `()`, la sintaxis de asignación funciona. La clase maneja la conversión de forma transparente. Si más tarde añades el setter a una clase que antes solo tenía getter, los callers existentes no necesitan cambios de código.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
Python no impide el acceso a `t._celsius` — el subrayado simple es un contrato social, no un candado. El autor de la clase señala "esto es fontanería interna" y confía en que los callers lo respeten. En la práctica, el 95 % del tiempo debes leer y escribir a través de la interfaz pública (`t.fahrenheit`, `t.celsius`).
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
El propósito principal del name mangling es **evitar colisiones en subclases**, no la privacidad real. `_Foo__secret` sigue siendo accesible con pleno conocimiento del esquema de mangling. Usa `__doble_subrayado` para atributos que no deben ser sobreescritos accidentalmente en subclases — no como medida de seguridad.
En términos simples, ¿qué hace `@property`?
- Python no tiene control de acceso impuesto. `_protegido` es una convención; `__mangled` previene colisiones de nombres en subclases mediante name mangling (no es privacidad real).
- `@property` expone un getter como `obj.attr`. `@attr.setter` añade una escritura validada. Los callers ven sintaxis de atributo simple en cualquier caso — la superficie de la API no cambia.
- Empieza con atributos públicos simples. Añade `@property` solo cuando necesites validación, un valor calculado o carga perezosa.
Los estimadores de sklearn exponen hiperparámetros como atributos públicos simples (`model.C`, `model.n_estimators`) pero usan `@property` para estadísticas calculadas establecidas después de `.fit()` — `n_features_in_`, `classes_`, `feature_importances_`. `nn.Module` de PyTorch expone `.training` como propiedad que controla el comportamiento de batch-norm y dropout; llamar a `.train()` o `.eval()` lo cambia. Los modelos de Pydantic usan magia de descriptor similar a `@property` para la validación de campos — el mismo principio de "la sintaxis de acceso a atributo oculta cómputo".
Si lo quitas: Sin `@property`, cada atributo calculado necesitaría ser una llamada a método — `model.get_feature_importances()` en lugar de `model.feature_importances_`. La convención de sklearn de acceso por atributo para los parámetros ajustados sería imposible de implementar limpiamente.