Estoy tratando de encontrar el equivalente en python de los métodos const de C++. Es decir, métodos que tienen prohibido cambiar cualquier dato miembro de su clase.
from typing import Final age: Final = 2 age += 3 # <----- warn about this -- works! class Person: def __init__(self, age: int) -> None: self.age = age def happy_birthday(self: Final[Person]) -> None: self.age += 1 # <----- warn about this -- how? Nunca he visto sugerencias de tipo utilizadas con self , por lo que se ve un poco raro (y no funciona)
main.py:4: error: Cannot assign to final name "age" main.py: note: In member "happy_birthday" of class "Person": main.py:9: error: Final can be only used as an outermost qualifier in a variable annotation [misc] def happy_birthday(self: Final[Person]) -> None: ^¿Hay alguna otra manera de lograr esto? Tenga en cuenta que los atributos aún deben permitir la modificación en otros métodos.
No existe tal cosa.
En C++, const está ahí por razones históricas y de optimización del compilador que no son relevantes en Python. Esta noción no parece encajar bien en el modelo de programación orientada a objetos de Python, en el que los métodos y las estructuras de datos forman unidades cohesivas: el objeto.
Si no tiene que ser una solución de sugerencia de tipo, puede hacer lo que sugirió PIG208 en los comentarios. es decir, puede crear un decorador que sobrescriba el método __setattr__ para generar una excepción al modificar cualquier atributo dentro del método.
Esto también es adecuado para adjuntar por método:
def const_method(func): def wrapper(instance): class unsettable_class(instance.__class__): def __init__(self): super().__setattr__("__dict__", instance.__dict__) def __setattr__(self, attr, value): if hasattr(self, attr): raise AttributeError(f"Trying to set value: {value} on the read-only attribute: {instance.__class__.__name__}.{attr}") super().__setattr__(attr, value) return func(unsettable_class()) return wrapperLuego puede usarlo como cualquier otro decorador:
class Person: def __init__(self, age: int) -> None: self.age = age @const_method def happy_birthday(self: "Person") -> None: self.age += 1 # throws an error since we are using the custom decorator def rebirth(self: "Person") -> None: self.age = 0 # will not throw an error since there is no decoratorDesafortunadamente, la desventaja es que este método no le dará resaltado de sintaxis en su IDE, como lo hará la sugerencia de tipo.