package

1. Introduction

From the meaning of packaging itself, packaging is like taking a sack, putting kittens, dogs, little bastards, and alex into the sack, and then sealing the sack. According to this logic, encapsulation = 'hidden', this understanding is quite one-sided

2. First see how to hide

Hide attributes by starting with double underscores in python (set them to private)

#其实这仅仅这是一种变形操作
#类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:

class A:
    __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__X=10 #变形为self._A__X
    def __foo(self): #变形为_A__foo
        print('from A')
    def bar(self):
        self.__foo() #只有在类内部才可以通过__foo的形式访问到.

#A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形

2.1 Features of this automatic deformation:

  1. The __x defined in the class can only be used internally, such as self.__x, which refers to the result of the deformation.
  2. This deformation is actually for the external deformation, which cannot be accessed from the outside by the name __x.
  3. The __x defined in the subclass will not override the __x defined in the parent class, because the subclass is transformed into: _subclass name__x, and the parent class is transformed into: _parent class name__x, that is, double When the properties at the beginning of the underscore are inherited to subclasses, subclasses cannot override them.

2.2 The problems that need to be paid attention to in this deformation are:

  1. This mechanism does not really restrict us from directly accessing attributes from the outside. Knowing the class name and attribute name can spell out the name: _class name__ attribute, and then you can access it, such as a._A__N
  2. The deformation process occurs only once in the definition of the class, and the assignment operation after the definition will not be deformed
  3. In inheritance, if the parent class does not want the subclass to override its own method, it can define the method as private
#正常情况
>>> class A:
...     def fa(self):
...         print('from A')
...     def test(self):
...         self.fa()
... 
>>> class B(A):
...     def fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from B


#把fa定义成私有的,即__fa
>>> class A:
...     def __fa(self): #在定义时就变形为_A__fa
...         print('from A')
...     def test(self):
...         self.__fa() #只会与自己所在的类为准,即调用_A__fa
... 
>>> class B(A):
...     def __fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from A

3. Encapsulation is not simply hiding

3.1 Package data

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

class Teacher:
    def __init__(self,name,age):
        self.__name=name
        self.__age=age

    def tell_info(self):
        print('姓名:%s,年龄:%s' %(self.__name,self.__age))
    def set_info(self,name,age):
        if not isinstance(name,str):
            raise TypeError('姓名必须是字符串类型')
        if not isinstance(age,int):
            raise TypeError('年龄必须是整型')
        self.__name=name
        self.__age=age

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

t.set_info('egon',19)
t.tell_info()

3.2 Encapsulation method: the purpose is to isolate the complexity

#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
#对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
#隔离了复杂度,同时也提升了安全性

class ATM:
    def __card(self):
        print('插卡')
    def __auth(self):
        print('用户认证')
    def __input(self):
        print('输入取款金额')
    def __print_bill(self):
        print('打印账单')
    def __take_money(self):
        print('取款')

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

a=ATM()
a.withdraw()

Other examples of encapsulation methods:

  1. There is no part of your body that does not reflect the concept of encapsulation: your body hides the functions of urine such as the bladder and urethra, and then provides you with a urine interface (the interface is yours...,) , you can't hang your bladder outside your body and show it off to others when you go to the toilet: hi, man, look at my bladder and see how I pee.
  2. The TV itself is a black box that hides all the details, but it will definitely provide a bunch of buttons to the outside world. These buttons are also the concept of the interface, so the packaging is not a simple meaning of hiding! ! !
  3. The shutter is what point-and-shoot cameras provide for point-and-shoots, hiding the complex camera functions inside.

Tip: In a programming language, an interface provided externally (an interface can be understood as an entry) can be a function, called an interface function, which is different from the concept of an interface. An interface represents a collection of interface functions.

4. Properties

4.1 What is a feature property

A property is a special property that, when accessed, executes a piece of functionality (function) and returns a value

Example 1: BMI index (bmi is calculated, but obviously it sounds like an attribute rather than a method, it is easier to understand if we make it an attribute)

BMI values ​​for adults:

Too light: below 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)

EX:70kg÷(1.75×1.75)=22.86

class People:
    def __init__(self,name,weight,height):
        self.name=name
        self.weight=weight
        self.height=height
    @property
    def bmi(self):
        return self.weight / (self.height**2)

p1=People('egon',75,1.85)
print(p1.bmi)

Example 2: The perimeter and area of ​​a circle

import math
class Circle:
    def __init__(self,radius): #圆的半径radius
        self.radius=radius

    @property
    def area(self):
        return math.pi * self.radius**2 #计算面积

    @property
    def perimeter(self):
        return 2*math.pi*self.radius #计算周长

c=Circle(10)
print(c.radius)
print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
print(c.perimeter) #同上
'''
输出结果:
314.1592653589793
62.83185307179586
'''

Note: The properties area and perimeter cannot be assigned at this time

c.area=3 #为特性area赋值
'''
抛出异常:
AttributeError: can't set attribute
'''

4.2 Why use property

After defining the function of a class as a feature, when the object uses obj.name again, it is impossible to notice that its name is calculated by executing a function. The use of this feature follows the principle of unified access.

Besides, see

ps:面向对象的封装有三种方式:
【public】
这种其实就是不封装,是对外公开的
【protected】
这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开
【private】
这种封装对谁都不公开

Python does not syntactically build the three of them into its own class mechanism. In C++, all data is generally set as private, and then set and get methods (interfaces) are provided to set and obtain, This can be achieved by the property method in python

class Foo:
    def __init__(self,val):
        self.__NAME=val #将所有的数据属性都隐藏起来

    @property
    def name(self):
        return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)

    @name.setter
    def name(self,value):
        if not isinstance(value,str):  #在设定值之前进行类型检查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME

    @name.deleter
    def name(self):
        raise TypeError('Can not delete')

f=Foo('egon')
print(f.name)
# f.name=10 #抛出异常'TypeError: 10 must be str'
del f.name #抛出异常'TypeError: Can not delete'

5. Encapsulation and Extensibility

Encapsulation is to clearly distinguish between inside and outside, so that the implementer of the class can modify the contents of the encapsulation without affecting the code of the external caller; while the external user only knows one interface (function), as long as the interface (function) name and parameters remain unchanged, use The author's code never needs to be changed. This provides a good basis for cooperation - or, as long as the basic convention of the interface remains the same, code changes are not a concern.

#类的设计者
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏了内部的实现细节,此时我们想求的是面积
        return self.__width * self.__length


#使用者
>>> r1=Room('卧室','egon',20,20,20)
>>> r1.tell_area() #使用者调用接口tell_area


#类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了
        return self.__width * self.__length * self.__high


#对于仍然在使用tell_area接口的人来说,根本无需改动自己的代码,就可以用上新功能
>>> r1.tell_area()

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325325996&siteId=291194637