• 面向对象之封装


    封装的两个层面
    1类和对象的名称空间,本质就是一种封装 类名. 和 实例名. 就是访问隐藏属性的接口
    2. 类中把某些属性和方法隐藏起来,只在内部使用,外部无法访问,或留下少量接口(函数)供外部访问
    只有在类定义时自动变形: __x =======> _类名__x
    定义后的赋值操作不会变形,不会隐藏
    类的里面可以直接访问变形的属性名
    对于这一层面的封装,我们需要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,然后在外部就可以使用了

    这种机制并没有真正意义上限制我们访问隐藏的属性,只要知道类名和变量名就可以访问
    #封装
    
    class A:
        __x = 1     #_A__x = 1
        def __test(self):    #_A__test(self)
            print('from A')
    
    
    print(A._A__x)
    A._A__test(11111)
    
    print(A.__dict__)
    
    a = A()
    print(a._A__x)
    a._A__test()
    
    print(a.__dict__)
    
    #__名字,这种语法,只在定义的时候才会有变形的效果,如果类或对象已经产生,就不会有变形效果
    class B:
        pass
    B.__x = 1
    print(B.__dict__)
    
    b = B()
    b.__x = 1
    print(b.__dict__)
    
    class A:
        def __init__(self):
            self.__x = 1
        def tell(self):
            print(self.__x)   #在类内部可以直接使用__名字在访问变形的属性名
    
    a = A()
    print(a.__dict__)
    #print(a.__x)    #报错
    a.tell()
    
    #在定义的阶段就会变形
    class A:
        def __fa(self):     #_A__fa()
            print('from A')
        def test(self):                  #类内部定义一个函数作为接口,外部可以访问类的私有属性
            self.__fa()      #_A__fa()
    
    class B(A):
        def __fa(self):      #_B__fa()
            print('from B')
    
    b = B()
    b.test()
    View Code
    # 将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,
    # 这种特性的使用方式遵循了统一访问的原则
    #@property的第一个用法:把函数属性伪装成数据属性,方便使用者调用
    import math
    class Circle:
        def __init__(self,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(7)
    print(c.radius)
    c.radius = 10
    print(c.area)
    print(c.perimeter)
    
    class Room:
        def __init__(self,length,weith,height):
            self.length = length
            self.weith = weith
            self.height = height
        @property
        def area(self):
            return self.length*self.weith
        @property
        def volume(self):
            return self.length*self.weith*self.height
    
    r = Room(1,3,5)
    print(r.length)
    print(r.area)
    print(r.volume)
    View Code
    #被property装饰的属性会优先于对象的属性被使用
    #被property装饰的属性,如下面的sex,分成3种:
    # 1 property 查看
    # 2 sex.setter 修改
    # 3 sex.deleter 删除
    #@property的第二个用法:自定义对象对于所属类的属性的访问
    class People:
        def __init__(self,name,SEX):
            self.name = name
            self.sex = SEX
    
        @property           #使用装饰器将之变为数据属性
        def sex(self):             #定义接口函数,使外部可以访问私有变量
            print('-----------')
            return self.__sex
        @sex.setter
        def sex(self,value):
            if not isinstance(value,str):
                raise TypeError('性别必须是字符串')
            self.__sex = value
        @sex.deleter
        def sex(self):
            del self.__sex
    
    
    
    
    p = People('egon','male')
    print(p.sex)
    p.sex = 'famale'
    print(p.sex)
    
    del p.sex
    print(p.sex)
    View Code
    #静态方法与类方法     都是为类量身定制的,一个是类的另一种实例化对象的方法,一个是他的子类的另一种实例化对象的方法

    staticmethod # 解除绑定: 类的另一种创建对象的方法
    # 应用场景:编写类时需要采用很多不同的方式来创建实例,而我们只有一个__init__函数,此时静态方法就派上用场了
    class Foo:
        @staticmethod
        def spam(self):
            print('-------->',self)
    Foo.spam(22222)
    f = Foo()
    f.spam(222)
    
    
    import time
    class Date:
        def __init__(self,year,month,day):
            self.year = year
            self.month = month
            self.day = day
        @staticmethod        #解除绑定
        def now():
            t = time.localtime()
            obj = Date(t.tm_year,t.tm_mon,t.tm_mday)     #新建实例并返回
            return obj
        @staticmethod
        def tomorrow():
            t = time.localtime(time.time()+86400)
            obj = Date(t.tm_year,t.tm_mon,t.tm_mday)
            return obj
    
    # 但凡是定义在类的内部,并且被staticmethod装饰器修饰过的方法,都是解除绑定的方法,实际上就是函数,没有自动传值功能
    d1 = Date(2017,5,6)
    d2 = Date(2017,6,9)
    date_now = Date.now()        #类可以调用自己的函数       进行实例化对象
    print(date_now)
    print(d1.now)
    d_n1=d1.now()              #对象也可以调用类的函数      进行实例化对象,但仍然是类实例化出来的,尽量不要用
    
    
    # 但凡是定义在类的内部,并且没有被任何装饰器修饰过的方法,都是绑定方法,有自动传值功能
    
    d_n1 = Date.now()
    print(d_n1.year)
    d_n1.now()    #绑定方法会自动传值,但是类的函数并不需要参数
    View Code
    classmethod  #给类绑定方法  :类和它的子类的另一种实例化对象的方法
    class Foo:
        def bar(self):
            pass
        @classmethod   #把一个方法绑定给类:类.方法 会把类本身当做第一个参数自动传给绑定方法
        def test(cls,x):
            print(cls,x)
            cls()   #拿到一个类的内存地址后,就可以实例化或者应用类的属性了
    
    
    print(Foo.bar)     #函数
    print(Foo.test)    #Foo 的绑定方法
    
    Foo.test(1)
    f = Foo()
    
    print(f.test)
    f.test(4)
    View Code
    # __str__定义在类内部,必须返回一个字符串类型
    # 什么时候会触发它的执行:打印由这个类产生的对象时,会触发执行
    class People:
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def __str__(self):        #自定义类的str函数
                return '<name:%s,age:%s>'%(self.name,self.age)
    
    p1 = People('egon',18)
    print(p1)
    print(str(p1))
    View Code
    #应用场景
    import time
    class Date:
        def __init__(self,year,month,day):
            self.year = year
            self.month = month
            self.day = day
        @classmethod      #类的绑定方法
        def now(cls):
    
            t = time.localtime()
            obj = cls(t.tm_year,t.tm_mon,t.tm_mday)
            return obj
    
    
    class EuroDate(Date):
        def __str__(self):      #打印它的对象时触发
            return '年:%s,月:%s,日:%s'%(self.year,self.month,self.day)
    
    # e = EuroDate(1,1,1)
    # print(e)
    e1 = EuroDate.now()
    print(e1)
    View Code
  • 相关阅读:
    安装MySQL(简便)
    许愿墙的搭建(基于Apache+php+mysql)
    httpd服务的安装、配置和关于php留言本网站的搭建
    Linux系统的初化始配置(包括配置网络,修改主机名,关闭firewalld与selinux的生效)
    Linux系统root用户忘记密码的重置方法
    Linux下面CentOS 7桌面的安装
    通过挂载系统光盘搭建本地yum仓库的方法
    时间同步ntp服务的安装与配置(作为客户端的配置)
    larbin
    Larbin的安装与配置
  • 原文地址:https://www.cnblogs.com/liuguniang/p/6748899.html
Copyright © 2020-2023  润新知