19. Setter, Getter, Deleter

19.1. Accessing class fields using setter and getter

Listing 347. Accessing class fields "Java way" -- don't do that in Python
class Astronaut:
    name = ''

    def set_name(self, name):
        print('Log, that value is being changed')
        self.name = name

    def get_name(self):
        return self.name

astro = Astronaut()
astro.set_name('Jan Twardowski')

print(astro.get_name())

19.1.1. Use case

Listing 348. Use case uzasadnionego użycia gettera w kodzie
from django.contrib import admin
from habitat._common.admin import HabitatAdmin
from habitat.sensors.models import ZWaveSensor


@admin.register(ZWaveSensor)
class ZWaveSensorAdmin(HabitatAdmin):
    change_list_template = 'sensors/change_list_charts.html'
    list_display = ['mission_date', 'mission_date', 'type', 'device', 'value', 'unit']
    list_filter = ['created', 'type', 'unit', 'device']
    search_fields = ['^date', 'device']
    ordering = ['-datetime']

    def get_list_display(self, request):
        list_display = self.list_display

        if request.user.is_superuser:
            list_display = ['earth_datetime'] + list_display

        return list_display

19.2. Accessing class fields using properties

Listing 349. Accessing class fields - "the Python way"
class Astronaut:
    def __init__(self, name=''):
        self.name = name

astro = Astronaut()              # either put ``name`` as an argument for ``__init__()``
astro.name = 'Jan Twardowski'     # or create dynamic field in runtime

print(astro.name)

19.3. Dynamically creating fields

Listing 350. Funkcja inicjalizującą, która automatycznie dodaje pola do naszej klasy w zależności od tego co zostanie podane przy tworzeniu obiektu
class Astronaut:
    def __init__(self, last_name, **kwargs):
        self.last_name = last_name

        for key, value in kwargs.items():
            setattr(self, key, value)


jan = Astronaut(last_name='Twardowski', addresses=())
ivan = Astronaut(first_name='Иван', last_name='Иванович', agency='Roscosmos')

print(jan.last_name)   # Twardowski
print(ivan.first_name)  # Иван

print(jan.__dict__)    # {'last_name': 'Twardowski', 'addresses': ()}
print(ivan.__dict__)    # {'last_name': 'Иванович', 'first_name': 'Иван', 'agency': 'Roscosmos'}

19.4. Getter

  • @property - for defining getters

  • Przykład użycia:

    • Blokowanie możliwości edycji pola klasy

    • Dodawanie logowania przy ustawianiu wartości

Listing 351. Using @property as a getter
class Temperature:
    def __init__(self, kelvin: float = 0.0):
        self.kelvin = kelvin

    @property
    def celsius(self):
        temp = self.kelvin - 273.15
        return round(temp, 2)


temp = Temperature(kelvin=309.75)

print(temp.celsius)
# 36.6

19.5. Setter

  • @x.setter - for defining setter for field x

  • Require field to be @property

Listing 352. @x.setter
class Temperature:
    def __init__(self, kelvin: float = 0.0):
        self.kelvin = kelvin

    @property
    def celsius(self):
        temp = self.kelvin - 273.15
        return round(temp, 2)

    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError('Temperature below -273.15 is not possible')
        else:
            self.kelvin = value + 273.15

temp = Temperature()

print(temp.kelvin)
# 0.0

temp.celsius = 36.60
print(temp.kelvin)
# 309.75

temp.celsius = -1000
# ValueError: Temperature below -273.15 is not possible

19.6. Deleter

  • @x.deleter - for defining deleter for field x

  • Require field to be @property

Listing 353. @x.deleter
class Temperature:
    def __init__(self, kelvin: float = 0.0):
        self.kelvin = kelvin

    @property
    def celsius(self):
        temp = self.kelvin - 273.15
        return round(temp, 2)

    @celsius.deleter
    def celsius(self):
        self.kelvin = 0.0

temp = Temperature(kelvin=100)

print(temp.celsius)
# -173.15

del temp.celsius

print(temp.celsius)
# -273.15

19.7. Accessors

19.7.1. __setattr__()

Listing 354. Example __setattr__()
class Kelvin:
    def __init__(self, initial_temperature):
        self.temperature = initial_temperature

    def __setattr__(self, name, new_value):
        if name == 'value' and new_value < 0.0:
            raise ValueError('Temperature cannot be negative')
        else:
            super().__setattr__(name, new_value)


temp = Kelvin(273)

temp.value = 20
print(temp.value)  # 20

temp.value = -10
print(temp.value)  # ValueError: Temperature cannot be negative

19.7.2. __getattribute__()

Listing 355. Example __getattribute__()
class Kelvin:
    def __init__(self, temperature):
        self.temperature = temperature

    def __getattribute__(self, name):
        if name == 'value':
            raise ValueError('Field is private, cannot display')
        else:
            super().__getattribute__(name)


temp = Kelvin(273)

temp.value = 20
print(temp.value)  # ValueError: Field is private, cannot display

19.7.3. __delattr__()

Listing 356. Example __delattr__()
class Point:
    x = 10
    y = -5
    z = 0

    def __delattr__(self, name):
        if name == 'z':
            raise ValueError('Cannot delete field')
        else:
            super().__delattr__(name)

p = Point()

del p.y

delattr(p, 'z')
# ValueError('Cannot delete field')