封装、property和绑定方法

一、封装

1.定义

  封:指的是该属性对外是隐藏的,但是对内部是开放的

  装:申请一个名称空间,往里边丢名字和属性

2.为什么要有封装

  2.1 封装数据属性的目的:

  首先定义数据属性的目的就是为了给类外部使用的,隐藏之后就是为了不让外部直接使用,需要通过调用类内部开通的接口来使用;然后类外部需要用到这个功能的时候,可以通过这个接口来间接的调用并操作这个隐藏属性。

  精髓:我们可以在该接口上附加上任何我们想要的逻辑与功能,从而达到严格控制使用者对属性的操作。

  2.2 封装函数属性的目的:

  定义函数属性的目的就是为了给类外部使用的,隐藏函数属性的目的就是为了不让外部直接使用,须在类的内部开辟一个专门的接口;外部需要使用是,也是需通过这个接口来间接的调用并操作这个隐藏的函数属性。

  精髓:隔离了复杂的程度

3.如何做到封装

  可以在需要隐藏的属性前面加上__开头

  解释:

  3.1 这种隐藏仅仅是一种语法上的变形操作。

  3.2 变形操作只在类的定义阶段发生一次,因为类体代码仅仅只在定义阶段检测一次。

  3.3 这种隐藏是对外不对外的,即在类的内部可以直接访问而在外部不能直接访问;究其根本原因是在类的定义阶段,类体的代码发生了一次统一的变形。

  3.4 如果不想让子类的方法覆盖父类的,可以直接在子类的方法名前加上__开头,隐藏其属性。

 1 class People():
 2     def __init__(self,name,age):
 3         self.__name=name
 4         self.__age=age
 5     def tell_info(self):
 6         print('%s - %s'%(self.__name,self.__age))
 7     def reset_info(self,name,age):
 8         self.__name = name
 9         self.__age = age
10         if type(name) is not str:   # 在接口上可以添加我们想要的逻辑
11             raise NameError('name must be string')
12         if type(age) is not int:
13             raise TypeError('age must be integer')
14 
15 p1=People('大仙',999)
16 # print(p1.name)   # 外部已经访问不到该属性了
17 p1.tell_info()
18 p1.reset_info('瓶盖',9)  # 通过类内部定义的特定接口来更改数据
19 p1.tell_info()
封装的简单例子

二、property

  property 将被装饰的方法伪装成一个数据属性,这样在使用时就可以不用加括号而直接引用。

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

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


p=People('黄山',1.7,75)
print(p.BMI) # 可以不用加括号而直接调用
property
 1 class People:
 2     def __init__(self,name):
 3         self.__name=name
 4 
 5     # 将name函数伪装成一个普通的数据属性
 6     @property    # 查看obj.name
 7     def name(self):
 8         return 'your name is %s' %self.__name
 9 
10     @name.setter    # 修改obj.name的值
11     def name(self,name):
12         if type(name) is not str:
13             raise NameError('your name must be str ')
14         self.__name=name
15         # 相当于在类的内部提供了一个专门修改名字的接口
16 
17     @name.deleter  # 删除obj.name
18     def name(self):
19         raise PermissionError('Deleting the name is not permission')
20         # del self.__name  # 若要删除obj.name这个属性,可以注释掉上面的raise error,
21                            # 相当于在类的内部提供了一个专门删除obj.name的接口
22 
23 p=People('大佬')
24 print(p.name)  # 可以不直接加括号而直接引用
25 
26 # p.name=123
27 # print(p.name)  #NameError: your name must be str
28 
29 del p.name  #NameError: your name must be str

三、绑定方法和非绑定方法

1.定义

1.1 绑定方法

绑定方法分成两类:

  1.1.1 绑定给对象

    在类内部定义的函数且没有被任何函数装饰器修饰的,这种就是默认绑定给对象的

  1.1.2 绑定给类

    在类内部定义的函数如果被装饰器@classmethod 装饰的,这个函数就是绑定给类的,就应该由类来调用,类来调用就会将类当作第一个参数自动传入。

  1.1.3 绑定方法的特性:

    绑定给谁就应该由谁来调用,谁来调用就会将谁当成第一个参数自动传入<其精髓就在于:自动传值>

1.2 非绑定方法

  类中定义的函数如果被装饰器@staticmethod 装饰,那么该函数就变成非绑定方法。

  函数如果没有被绑定,则意味着类和对象皆可调用,但无论谁来调用,都没有自动传值的效果,就是一个普通的函数,这种情况则应该传入相应的参数。

2. 如何使用

  如果函数体代码需要使用外部传入的类,则应该将函数定义成绑定成给类的方法

  如果函数体代码需要使用外部传入的对象,则应该将函数定义成绑定给对象的方法

  如果函数体代码既不需要使用外部传入的类,也不需要使用外部传入的对象,那么应该将函数定义成非绑定方法/普通函数。

 1 import settings
 2 import uuid
 3 
 4 class Mysql():
 5     def __init__(self,ip,port):
 6         self.uuid=self.create_uuid()
 7         self.ip=ip
 8         self.port=port
 9 
10     def get_info(self):
11         print('%s - %s'%(self.ip,self.port))
12 
13     @classmethod
14     def from_settings(cls):
15         return cls(settings.ip,settings.port)
16 
17     @staticmethod
18     def create_uuid():  # 非绑定方法,所以不需要参数
19         return uuid.uuid4()
20 
21 # 默认的实例化方式
22 obj=Mysql('192.168.0.0',3306)
23 obj.get_info()  # 这种情况下函数是已经执行了,
24             # 所以不必在用print(obj.get_info())了,
25             # 否则在输出结果的同时,会收到一个函数的默认返回值
26 
27 # 一种新的实例化方式,从配置文件中读取出配置完成实例化
28 obj=Mysql.from_settings()
29 obj.get_info()
30 
31 # 若函数是非绑定方法,则类和对象皆可调用
32 obj.create_uuid()
33 Mysql.create_uuid()
小实例
ip='192.168.0.0'
port=3306
settings
原文地址:https://www.cnblogs.com/Smart1san/p/9304650.html