zoukankan      html  css  js  c++  java
  • 封装、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
  • 相关阅读:
    http://the-automator.com/set-excel-font/
    ds finder 唤醒
    gateone8271
    todo
    VS调试运行出错,某些类库项目中引用的命名空间提示不存在
    很有意思的问题
    关于textedit 某些电脑下 输入 显示不全的问题
    SQL Server把一台服务器上的数据库转移到另外一台服务器上。而转移完成后,需要给一个"登录"关联一个"用户"时,发生错误:“错误15023:当前数据库中已存在用户或角色”或“用户、组或角色 在当前数据库中已存在”
    构造简单好用的年份、年月选择器
    大数据下的grid显示
  • 原文地址:https://www.cnblogs.com/Smart1san/p/9304650.html
Copyright © 2011-2022 走看看