面向对象 - 封装: 封装:在类定义阶段,以__开头的属性名发生了变形 eg: __x --> _A__x / __foo --> _A__foo 1.特点: 1.在类外部无法直接访问 __x 是 _A__x 2.在类内部可以直接使用 self.__foo() == self._A__foo() 3.子类无法覆盖父类以__开头的属性 因为根本不是一个名字 __x _A__x 2.总结: 这种变形需要注意的问题: 1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了, 如a._A__N eg:print(A._A__x) 但一般不这样做! 2.变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形 eg: b.__age=18 {'_B__name': 'alice', '__age': 18} 3.在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的 eg: def __foo(self): #_A__foo 3.意义: 1.封装数据属性的目的:(封装不是单纯意义上的隐藏) 明确的区分内外,控制外部对隐藏属性的操作行为 对接口 设定规则 2.封装方法属性的目的: 隔离复杂度 a=ATM() a.withdraw() 对接口 设定规则 4.扩展性: def tell_area(self) 对使用者来说不用改变方式 开发者在类里面扩展 面向对象的三大特征:继承 多态 封装 面向对象的优点:可扩展性高
1 class A: 2 __x=1 3 def __init__(self,name): 4 self.name=name 5 6 def __foo(self): 7 print('run foo') 8 9 def bar(self): 10 self.__foo() 11 print('run bar') 12 13 a=A('alice') 14 # print(a.__dict__) 15 # print(a.name) 16 # a.bar() 17 # # a.foo() 18 # a._A__foo() 19 # # print(a.__x) 20 # print(a._A__x) 21 # print(A.__dict__) 22 23 # a.bar() 24 # a.__foo() 25 26 # a.__x=1 27 # print(a.__dict__) 28 # print(a.__x) 29 # print(A.__dict__) 30 31 # A.__x=2 32 # print(A.__x) 33 # print(A.__dict__) 34 35 class Foo: 36 def __func(self): 37 print('from foo') 38 39 class Bar(Foo): 40 def __init__(self,name): 41 self.__name=name 42 43 def __func(self): 44 print('from bar') 45 46 # b=Bar() 47 # # b.func() 48 # print(Foo.__dict__) 49 # print(Bar.__dict__) 50 51 b=Bar('alice') 52 # print(b.__dict__) 53 # print(b.name) 54 # print(b._Bar__name) 55 56 class A: 57 def __foo(self): #_A__foo 58 print('A.foo') 59 60 def bar(self): 61 print('A.bar') 62 self.__foo() #self._A__foo() # 只调自己类的方法 定义时就已经确定好的! 63 64 class B(A): 65 def __foo(self): # _B_fooo 66 print('B.foo') 67 68 # b=B() 69 # b.bar() 70 71 # print(A.__dict__) 72 # print(B.__dict__) 73 74 class People: 75 def __init__(self,name,age): 76 self.__name=name 77 self.__age=age 78 79 def tell_info(self): #对接口 设定规则 80 print('name:<%s> age:<%s>'%(self.__name,self.__age)) 81 82 def set_info(self,name,age): 83 if not isinstance(name,str): 84 print('名字必须是字符串类型') 85 return 86 if not isinstance(age,int): 87 print('年龄必须是数字类型') 88 return 89 self.__name=name 90 self.__age=age 91 92 p1=People('alice',12) 93 # print(p1.name,p1.age) 94 # print(p1.__dict__) 95 # p1.tell_info() 96 # p1.set_info('alex',18) 97 # p1.tell_info() 98 99 class ATM:100 def __card(self):101 print('插卡')102 103 def __auth(self):104 print('用户认证')105 106 def __input(self):107 print('输入取款金额')108 109 def __print_bill(self):110 print('打印账单')111 112 def __take_money(self):113 print('取款')114 115 def withdraw(self):116 self.__card()117 self.__auth()118 self.__input()119 self.__print_bill()120 self.__take_money()121 122 # a=ATM()123 # a.withdraw()124 125 class Room:126 def __init__(self,name,owner,weight,length,height):127 self.name=name128 self.owner=owner129 self.__weight=weight130 self.__length=length131 self.__height=height132 133 def tell_area(self):134 return self.__weight * self.__length * self.__height135 136 r=Room('客厅','alice',100,100,100)137 # print(r.tell_area())
面向对象 - property: property: 1.@property 将函数属性 伪装成 数据属性 2.必须要有返回值 return '' 3.@property 查看 必须要有返回值 print(p.name) name 是函数属性 不是数据属性 伪装成 数据属性 @name.setter 修改 p.name='alex' @name.deleter 删除 del p.name 总结:通过计算得来的方法 可以通过@property 伪装成数据属性
1 class People: 2 def __init__(self,name,weight,height): 3 self.name=name 4 self.weight=weight 5 self.height=height 6 7 @property 8 def bmi(self): 9 return self.weight / (self.height ** 2)10 11 p = People('alice',60,1.65)12 # print(p.bmi())13 # print(p.bmi)14 # p.bmi=1215 16 class People:17 def __init__(self,name):18 self.__name=name19 20 @property21 def name(self):22 return self.__name23 24 @name.setter25 def name(self,val):26 if not isinstance(val,str):27 print('名字必须是str')28 return29 self.__name=val30 31 @name.deleter32 def name(self):33 print('不允许删除')34 35 36 p=People('alice')37 print(p.name)38 p.name='alex'39 print(p.name)40 del p.name