Python Learning Diary Encapsulation and Several Decorator Functions

Keywords: Python Attribute

encapsulation

Generally speaking, encapsulation is actually an object-oriented idea, which can protect code; narrowly speaking, encapsulation is one of the three characteristics of object-oriented, which can hide attributes and methods from people's eyes.

Private Attributes

Private attributes are represented by adding two double underscores before an attribute name

class Fighter:
    def __init__(self,name,hp,atk,speed):
        self.name = name
        self.__hp = hp                      #Private Attributes  Deformation into self._Fighter__hp
        self.__atk = atk                    #Private Attributes  Deformation to self._Fighter__atk
        self.__speed = speed                #Private Attributes  Deformation to self._Fighter__speed
f1 = Fighter('AKK-18',1500,200,300)
print(f1.__dict__)                          #{'name': 'AKK-18', '_Fighter__hp': 1500, '_Fighter__atk': 200, '_Fighter__speed': 300}

python's private attributes only add a layer of privacy to the code level, and you are not allowed to access these private attributes directly, like if you print a private attribute whose result is an error, or if you want to try to modify a private attribute, the result can't be changed successfully.

f1.__hp = 1000
print(f1.__dict__)                          #{'name': 'AKK-18', '_Fighter__hp': 1500, '_Fighter__atk': 200, '_Fighter__speed': 300, '__hp': 1000}

Because the above private attributes have been transformed into the format of class name attribute name, we write this as adding a new'key name'hp directly to self, so calling double underscores outside the class is not feasible.

How do we access our private attributes? We can see that the above private attributes have been transformed into the form of class name attribute name, so we can access:

print(f1._Fighter__hp)                      #1500
print(f1._Fighter__atk)                     #200
print(f1._Fighter__speed)                   #300

But such a shortcut is not perfect. We can add a get_value function inside the class to get those private attributes.

class Fighter:
    def __init__(self,name,hp,atk,speed):
        self.name = name
        self.__hp = hp                      #Private Attributes
        self.__atk = atk                    #Private Attributes
        self.__speed = speed                #Private Attributes
    def get_value(self):
        return self.__hp,self.__atk,self.__speed        #As long as private attributes are used within the class, they are automatically brought along'_Class name'
f1 = Fighter('AKK-18',1500,200,300)
print(f1.__dict__)                          #{'name': 'AKK-18', '_Fighter__hp': 1500, '_Fighter__atk': 200, '_Fighter__speed': 300}
print(f1.get_value())                       #(1500, 200, 300)
for i in f1.get_value():
    print(i)                                #1500
                                            #200
                                            #300

In get_value, return is actually a way of getting private attributes after deformations.

def get_value(self):
    return self._Fighter__hp,self._Fighter__atk,self._Fighter__speed

Private static properties

class Fighter:
    __id = 1234445                          #Private static properties
    def __init__(self,name,hp,atk,speed):
        self.name = name
        self.__hp = hp                      #Private Attributes
        self.__atk = atk                    #Private Attributes
        self.__speed = speed                #Private Attributes
    def get_value(self):                    #Getting Internal Private Attributes Method
        return self.__hp,self.__atk,self.__speed
    def get_id(self):
        return self.__id
f1 = Fighter('AKK-18',1500,200,300)
print(f1._Fighter__id)                      #1234445
print(f1.get_id())                          #1234445

Private methods

class Fighter:
    __id = 1234445                          #Private static properties
    def __init__(self,name,hp,atk,speed):
        self.name = name
        self.__hp = hp                      #Private Attributes
        self.__atk = atk                    #Private Attributes
        self.__speed = speed                #Private Attributes
    def get_value(self):                    #Getting Internal Private Attributes Method
        return self.__hp,self.__atk,self.__speed
    def get_id(self):                       #Getting static attributes id Method
        return self.__id
    def __shoot(self):                      #Private methods
        print('Shooting!')
    def get_shoot(self):                    #Access to private methods shoot
        self.__shoot()                      
        #self._Fighter__shoot()
f1 = Fighter('AKK-18',1500,200,300)
f1.get_shoot()                              #Shooting!

Modifying private attributes

class Room:
    def __init__(self,name,length,width):
        self.__name = name
        self.__length = length
        self.__width = width
    def Area(self):
        return self.__width*self.__length
    def get_name(self):         #How to get this private name
        return self.__name
    def set_name(self,new_name):#Reset the room number
        if type(new_name) is str and new_name.isdigit() == True:
            self.__name = new_name
        else:
            print('Incorrect naming!')
r1 = Room('1101',15,20)
print(r1.Area())                #300
print(r1.get_name())            #1101
r1.set_name('asd')
print(r1.__dict__)              #{'_Room__name': '1103', '_Room__length': 15, '_Room__width': 20}
print(r1.get_name())            #1103

 

Several ornaments

1.@property

We often regard the circumference and area of a circle as a method when we write it in object-oriented way. However, we know that the method is an action of acquisition, not an attribute noun, so in order to deal with this kind of disguising a method as an attribute, we need to use @property, which makes it look like a method. It's an attribute.

from math import pi as P
class Circle:
    def __init__(self,r):
        self.r = r
    def Perimeter(self):
        return 2*P*self.r
    def Area(self):
        return P*self.r**2
c = Circle(5)
print(c.Area())                     #78.53981633974483
print(c.Perimeter())                #31.41592653589793

Improvement:

from math import pi as P
class Circle:
    def __init__(self,r):
        self.r = r
    @property
    def Perimeter(self):        #Here it is. self No parameters can be passed back.
        return 2*P*self.r
    @property
    def Area(self):             #Here it is. self No parameters can be passed back.
        return P*self.r**2
c = Circle(5)
print(c.Perimeter)              #31.41592653589793
print(c.Area)                   #78.53981633974483

BMI problem: BMI index (BMI) = body weight (kg), height ^ 2(m)

Adult BMI values:

Too light: below 18.5

Normal: 18.5-23.9

Overweight: 24-27

Very obese: > 32

class BMI:
    def __init__(self,height,weight):
        self.__height = height
        self.__weight = weight
    @property
    def __bmi(self):                        #Computation bmi Method masquerades as an attribute
        return self.__weight/self.__height**2

    def get_bmi(self):                      #BMI judge
        if self.__bmi > 32:
            print('Very obese!')
        elif 24 <= self.__bmi <= 27:
            print('overweight!')
        elif 18.5 <= self.__bmi <= 23.9:
            print('normal!')
        else:
            print('Over light!')

b = BMI(1.75,72)
b.get_bmi()                                 #normal!
Modify attributes with @setter on the premise of @property
class Person:
    def __init__(self,name,):
        self.__name = name
    @property
    def name(self):
        return self.__name + ' hello!'
    @name.setter
    def name(self,new_name):
        self.__name = new_name
p1 = Person('Jogn')
print(p1.name)                               #Jogn hello!
#p1._Person__name = 'Maria'                  #Maria hello!
print(p1.name)                               #Maria hello!
Delete attributes with @deleter on the premise of @property
class Person:
    def __init__(self,name,):
        self.__name = name
    @property
    def name(self):
        return self.__name + ' hello!'
    @name.deleter
    def name(self):                     
        del self.name                       
p1 = Person('Jogn')
print(p1.name)                               #Jogn hello!
del p1.name                                  #del p1.name Its role here is to point to deleter Here's how,Do the function of this method again
print(p1.name)                               #I can't find the name.

Let's take a look at the del keyword here and what it does.

class Person:
    def __init__(self,name,):
        self.__name = name
    @property
    def name(self):
        return self.__name + ' hello!'
    @name.deleter
    def name(self):
        print('This method is implemented.!')
p1 = Person('Jogn')
print(p1.name)                               #Jogn hello!
del p1.name                                  #del p1.name Its role here is to point to deleter Here's how,Do the function of this method again
print(p1.name)                               #Jogn hello!

Because there is no operation to modify the name in the second name, the original name can be printed in the last p1.name.

2.@classmethod

When this method involves only static attributes, it should be decorated with classmethod

class Goods:
    __discount = 0.8                                    #Discount?
    def __init__(self,name,price):
        self.name = name
        self.__price = price
    @property
    def price(self):
        return self.__price * self.__discount
    @classmethod
    def change_discount(cls,new_discount):              #cls For class names
        cls.__discount = new_discount                   #Modify discount
apple = Goods('Apple',4)
print(apple.price)                                      #3.2
Goods.change_discount(0.5)
print(apple.price)                                      #2.0

3.@staticmethod

In a fully object-oriented program, if a function has nothing to do with an object, then use static method to turn the function into a static method.

class Login:
    def __init__(self,name,password):
        self.name = name
        self.password = password
    @staticmethod
    def get_n_psw():                            #Without default parameters, it's like a function.
        username = input('enter one user name:')
        psw = input('Please input a password:')
        Login(username,psw)                     #enter one user name:asdd                                               
        return username,psw                     #Please input a password:4564648
print(Login.get_n_psw())                        #('asdd', '4564648')

Posted by Rose.S on Sun, 08 Sep 2019 03:42:01 -0700