Python knowledge -- encapsulation, property

Posted by Ryyo on Sat, 15 Jan 2022 14:13:52 +0100

Reference: Object oriented encapsulation

encapsulation

The core of the three object-oriented features

Encapsulation < - > consolidation

Hide encapsulated attributes

How to hide attributes: add before the attribute name__ Prefix, you will achieve an external hidden attribute effect

class Foo:
    __x = 1

    def __f1(self):
        print('hello world')

'''
    print(Foo.__x)
AttributeError: type object 'Foo' has no attribute '__x'
'''

In fact, this is only a deformation operation, and deformation occurs only at the class definition stage. Take a look:

print(Foo.__dict__)

'''
'_Foo__x': 1, '_Foo__f1': <function Foo.__f1 at 0x0000013977EC9430>
'''

It can be found that all double underlined names in the class, such as__ x will automatically change when the class is defined:_ Class name__ Form of x
The deformed attribute format can still be accessed

print(Foo._Foo__x)
print(Foo._Foo__f1)

'''
1
<function Foo.__f1 at 0x0000019647CB9430>
'''

And this deformation is external and internal, which can be accessed directly within the class
Why? Class will perform syntax detection at the definition stage. Once _isfound_ The first attribute will be directly deformed to_ Foo__, When outside the class, the deformation of the class has been completed, so it cannot be accessed outside the class

class Foo:
    __x = 1

    def __f1(self):
        print('hello world')

    def f2(self):
        print(self.__x)
        print(self.__f1)


obj = Foo()
obj.f2()

'''
1
<bound method Foo.__f1 of <__main__.Foo object at 0x0000016660539AF0>>
'''

Why hide attributes?

The essence of encapsulation is to clearly distinguish between inside and outside. Encapsulated attributes can be directly used internally, but not externally. However, the purpose of defining attributes is to use them after all. If external attributes want to be hidden by classes, we need to open interfaces for them so that external attributes can be used indirectly. What is the significance of doing so???

  1. Hide data properties

Hiding data is not an end in itself. Hide it, and then provide an interface for operating the data. Then we can attach restrictions on the data operation to the interface, so as to complete the strict control of data attribute operation.

If you do not hide data: external users can directly modify the name attribute of the object, which will directly bypass the character format time limit.

class Teacher:
    def __init__(self, name, age):
        if not isinstance(name, str):
            raise TypeError('Name must be a string type')
        if not isinstance(age, int):
            raise TypeError('Age must be integer')
        self.name = name
        self.age = age

    def tell_info(self):
        print('full name:%s,Age:%s' % (self.name, self.age))


t = Teacher('egon', 18)
t.tell_info()

t.name = 18
t.age = 'egon'
t.tell_info()

'''
full name:egon,Age:18
 full name:18,Age:egon
'''

If hidden data: t.name cannot be used directly Name, you must use set to modify the name_ Info, it will be limited by the character type

class Teacher:
    def __init__(self, name, age):

        # self.name = name
        # self.age = age
        self.set_info(name, age)

    def tell_info(self):
        print('full name:%s,Age:%s' % (self.__name, self.__age))

    def set_info(self, name, age):
        if not isinstance(name, str):
            raise TypeError('Name must be a string type')
        if not isinstance(age, int):
            raise TypeError('Age must be integer')
        self.__name = name
        self.__age = age


t = Teacher('egon',18)
t.tell_info()

#t.name cannot be used directly Name, you must use set to modify the name_ Info, it will be limited by the character type
  1. Hide function / method properties

The purpose is to isolate the complexity. Some methods only need to be used inside the class, which reduces the operation difficulty of the operator. The operator only needs to use some large functions. Small functions have been completed at the time of design and are not seen by the operator.

example:
Withdrawal is a function, which consists of many functions: card insertion, password authentication, entering amount, printing bill and withdrawing money
For users, we only need to know the function of withdrawal, and we can hide the other functions. Obviously, we do so
It isolates complexity and improves security.

#Withdrawal is a function, which consists of many functions: card insertion, password authentication, entering amount, printing bill and withdrawing money
#For users, we only need to know the function of withdrawal, and we can hide the other functions. Obviously, we do so
#It isolates complexity and improves security

class ATM:
    def __card(self):
        print('Card insertion')
    def __auth(self):
        print('User authentication')
    def __input(self):
        print('Enter withdrawal amount')
    def __print_bill(self):
        print('Print bill')
    def __take_money(self):
        print('withdraw money')

    def withdraw(self):
        self.__card()
        self.__auth()
        self.__input()
        self.__print_bill()
        self.__take_money()

a=ATM()
a.withdraw()

property

property is a decorator. What is it used for?

The first way to use property

example:
BMI index (BMI is calculated, but obviously it sounds like an attribute rather than a method. It's easier to understand if we make it an attribute)

BMI values for adults:
Too light: less than 18.5
Normal: 18.5-23.9
Overweight: 24-27
Obesity: 28-32
Very obese, above 32
Body mass index (BMI) = weight (kg) ÷ height ^ 2 (m)

class People:
    def __init__(self, name, weight, height):
        self.name = name
        self.height = height
        self.weight = weight

    def bmi(self):
        return self.weight / (self.height ** 2)


obj1 = People('egon', 66, 1.5)
print(obj1.bmi())

Why bmi is defined as a function:

  1. From the formula of bmi, bmi should be calculated by trigger function
  2. bmi changes dynamically with the change of height and weight. It is not a fixed value, that is, it needs to be calculated every time

So you need () when you use it, but bmi sounds more like a data than a function
This will cause users to lack () when using bmi, so it is necessary to reduce misunderstanding. The property decorator is introduced so that users can not use ()

 @property
    def bmi(self):
        return self.weight / (self.height ** 2)


obj1 = People('egon', 66, 1.5)
print(obj1.bmi)
'''
29.333333333333332
'''

The second way to use property

example:
After learning through encapsulation, you will learn that developers will hide some attributes and restrict users from viewing and modifying data. However, this restriction also has a disadvantage, that is, it increases the complexity of the operator's data operation. If the operator modifies the data, he must call the functions set by the developer, and the function names set by each developer may be different, which will lead to unnecessary trouble.

class People:
    def __init__(self, name):
        self.__name = name

    def get_name(self):
        return self.__name

    def set_info(self, name, age):
        if not isinstance(name, str):
            raise TypeError('Name must be a string type')
        self.__name = name

    def del_name(self):
        print('Don't let delete')
        pass


#Generate object
t = People('egon')
#Modify object
t.set_info('haha')
#View object
print(t.get_name())

Is there a unified method that allows users to modify data in the previous logical way without first understanding the developer's function name, as shown in the following examples:

#View object
print(t.name)
#Modify object
t.name = 'haha'
#delete object
del t.name

Using the property decorator

class People:
    def __init__(self, name):
        self.__name = name

    @property   # name=propert(name)
    def name(self):
        return self.__name

    @name.setter
    def name(self, name):
        if not isinstance(name, str):
            raise TypeError('Name must be a string type')
        self.__name = name

    @name.deleter
    def name(self):
        print('Don't let delete')
        pass
	# name = p()

t = People('egon')

t.name = 'haha'
print(t.name)
del t.name

'''
haha
 Don't let delete
'''

Topics: Python encapsulation