
class CoordinateValue:
    def __init__(self, name):
        self.storage_name = '_' + name

    def __set__(self, instance, value):
        setattr(instance, self.storage_name, int(value))

    def __get__(self, instance, owner_class):
        '''
        if instance is None:
            print('__get__ called from class')
        else:
            print(f'__get__ called, instance={instance}, owner_class={owner_class}')
        '''
        if instance is None:
            return self
        return getattr(instance, self.storage_name, None)



class Point:
    x = CoordinateValue('x')
    y = CoordinateValue('y')
    
def test_point():
    p1 = Point()
    p1.x = 100
    p1.y = 5
    print(p1.x, p1.y)
    print(p1.__dict__)

    p2 = Point()
    p2.x = 2
    p2.y = 3
    print(p2.x, p2.y)
    print(p2.__dict__)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# __set_name__
# Метод срабатывает в процессе создания класса и все!


class StringValidation:
    def __init__(self, min_length):
        self.min_length = min_length

    def __set_name__(self, owner, name):
        print(f'__set_name__ called: owner={owner}, attr_name={name}')
        self.attribute_name = name

    def __get__(self, instance, owner_class):
        if instance is None:
            return self
        else:
            print(f'calling __get__ for {self.attribute_name}')
            return instance.__dict__.get(self.attribute_name, None)
            # key = '_' + self.attribute_name
            # return getattr(instance, key, None)


    def __set__(self, instance, value):
        if not isinstance(value, str):
            raise ValueError(f'В атрибут {self.attribute_name} можно \
                             сохранять только строки.')
        if len(value) < self.min_length:
            raise ValueError(f'Длина атрибута {self.attribute_name} должна \
                             быть не меньше {self.min_length} символов')
        key = '_' + self.attribute_name
        # setattr(instance, key, value)
        instance.__dict__[self.attribute_name] = value



class Person:
    name = StringValidation(5)
    last_name = StringValidation(7)


def main():
    p = Person()
    p.name = 'Michail'
    p.last_name = 'Lermontov'
    print(p.name, p.last_name)
    try:
        p.name = 'M.'
    except ValueError as ex:
        print(ex)
    print(p.name, p.last_name)

if __name__ == '__main__':
    main()