面向对象之封装

封装的两个层面
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

 

posted @ 2017-04-23 09:38  柳姑娘  阅读(175)  评论(0)    收藏  举报