zoukankan      html  css  js  c++  java
  • 封装

    一、封装
    1.什么是封装
    封:属性对外是隐藏的,但对内是开放的
    装:申请一个名称空间,往里装如一系列名字/属性

    2.为什么要封装
    封装数据属性目的:
    首先定义属性的目的就是为了给类外部的使用者使用的,
    隐藏之后是为了不让外部使用者直接使用,需要类内部开辟一个接口
    然后让类外部的使用者通过接口来间接地操作隐藏属性。
    精髓在于:我们可以在接口上附加任意逻辑,从而严格控制使用者对属性的操作

    封装函数属性目的:
    首先定义属性的目的就是为了给类外部使用者使用的,
    隐藏函数属性是为了不让外部使用者直接使用,需要类内部开辟一个接口
    然后在接口内取调用隐藏功能
    精髓在于:隔离了复杂度

    3.如何封装
    如何隐藏:在属性前加上__开头
    1.这种隐藏仅仅是一种语法上的变形操作
    2.这种语法上的变形只在定义阶段发生一次,因为类体代码仅仅只在类定义阶段检测一次
    3.这种隐藏是对外不对内的,即在类的内部可以直接访问,而在类的外部则无法直接访问,原因是
    在类定义阶段,类体代码统一发生了一次变形
    4.如果不想让子类的方法覆盖父类,可以将改方法名前加一个__开头


    例子1:
    class Foo:
    def __f1(self): #_Foo__f1
    print('Foo.f1')

    def f2(self):
    print('Foo.f2')
    self. __f1() #self._Foo__f1

    class Bar(Foo):
    def _f1(self): #_Bae__f1
    print('Bar.f1')

    obj=Bar()
    obj.f2()

    结果为:Foo.f2
    Foo.f1


    例子2:
    class People:
    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 type(name) is not str:
    raise TypeError('用户名必须是str类型')
    # print('用户名必须为str类型')
    # return
    if type(age) is not int:
    raise TypeError('年龄必须是int类型')
    # print('年龄必须为int 类型')
    # return
    self.__name=name
    self.__age=age

    peo1=People('egon',18)
    # peo1.tell_info()
    peo1.set_info('EGON',19)
    peo1.tell_info()


    二、特性property
    property装饰器用于将被装饰的方法伪装成一个数据属性,在使用是可以不用加括号而直接引用

    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)

    peo1=People('小明',70,1.77)
    print(peo1.bmi)


    property用法一:

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

    @property #查看object.name
    def name(self):
    return '<名字是:%s>'%self.__name

    @name.setter #修改object.name=值
    def name(self,name):
    if type(name) is not str:
    raise TypeError('名字必须是str类型')
    self.__name=name

    @name.deleter #删除del object.name
    def name(self):
    raise PermissionError('不给删')
    # del self.__name

    peo1=People('egon')
    # print(peo1.name)
    peo1.name='EGON'
    # print(peo1.name)
    del peo1.name

    property用法二:
    class People:
    def __init__(self,name):
    self.__name=name

    def tell_name(self):
    return '<名字是:%s>'%self.__name

    def set_name(self,name):
    if type(name) is not str:
    raise TypeError('名字必须是str类型')
    self.__name=name

    def del_name(self):
    print('不给删')

    name=property(tell_name,set_name,del_name)

    peo1=People('egon')
    print(peo1.name)
    peo1.name='EGON'
    print(peo1.name)
    del peo1.name
    #用法和上面一样,推荐使用上面的方法


    三、绑定方法与非绑定方法
    1.绑定方法:
    特性:绑定给谁就应该由谁来调用,谁来调用就会当作第一个参数自动传入
    ============精髓在于自动传值===========

    绑定方法分两类:
    1.1 绑定给对象方法:
    在类内部定义的函数(没有被任何装饰器装饰的),默认就是绑定给对象用的

    1.2 绑定给类的方法:
    在类内部定义的函数如果被装饰器@classmethod装饰,
    那么则是绑定给类的,应该由类来调用,类来调用就自动将类当作第一参数自动传入

    2.非绑定方法:
    类中定义的函数如果被装饰器@staticmethod装饰,那么该函数就成非绑定方法
    既不与类绑定,又不与对象绑定,意味着类与对象都可以来调用
    但是无论谁来调用,都没有任何自动传值的效果,就是一个普通函数

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


    class Foo:
    @classmethod
    def f1(cls):
    print(cls)

    def f2(self):
    print(self)


    obj=Foo()
    print(obj.f2)
    print(Foo.f1)

    Foo.f1()
    print(Foo)


    1、f1绑定给类的
    了解:绑定给类的应该由类来调用,但对象其实也可以使用,只不过自动传入的仍然是类
    print(Foo.f1)
    print(obj.f1)
    Foo.f1()
    obj.f1()

    2、f2是绑定给对象的
    obj.f2()
    Foo.f2(obj)


    import settings
    import uuid

    class Mysql:
    def __init__(self,ip,port):
    self.uid=self.create_uid()
    self.ip=ip
    self.port=port

    def tell_info(self):
    print('%s:%s' %(self.ip,self.port))

    @classmethod
    def from_conf(cls):
    return cls(settings.IP, settings.PORT)

    @staticmethod
    def func(x,y):
    print('不与任何人绑定')

    @staticmethod
    def create_uid():
    return uuid.uuid1()

    默认的实例化方式:类名(..)
    obj=Mysql('10.10.0.9',3307)

    一种新的实例化方式:从配置文件中读取配置完成实例化
    obj1=Mysql.from_conf()
    obj1.tell_info()

    func 类与对象都可以访问
    obj.func(1,2)
    Mysql.func(3,4)

    print(obj.func)
    print(Mysql.func) 两者一样

    print(obj.uid)
  • 相关阅读:
    [2013腾讯马拉松 3月23日]HDU 4517 小小明系列故事——游戏的烦恼
    金山西山居初赛第三场 HDU 4551~HDU 4553
    Redis安装
    前端常用网址汇总
    Html5移动端页面布局通用模板暨移动端问题总结
    js数组去重,并统计最多项算法
    纯css实现下拉菜单
    js实现求平均数功能
    Html5+css3实现3D转动效果
    移动设备分辨率及响应式断点汇总
  • 原文地址:https://www.cnblogs.com/kingyanan/p/9239563.html
Copyright © 2011-2022 走看看