博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
面向对象编程(封装、封装的意义、封装与扩展性、@property)
阅读量:7111 次
发布时间:2019-06-28

本文共 5128 字,大约阅读时间需要 17 分钟。

1.封装之如何实现属性的隐藏

 

 

封装: __x=1 # 把数据属性隐藏 (如何实现隐藏) 类定义阶段 __开头发生了变形 __x --> _A__x

特点:
  1.在类外部无法直接:obj.__AttrName
  2.在类内部是可以直接使用:obj.__AttrName # 为什么会这样?python 如何实现的 !类定义阶段已经变形 #__x --> _A__x #self._A_foo()
  3.子类无法覆盖父类__开头的属性 它两根本不是一个名字 #_Foo__func #_Bar__func
总结:
这种变形需要注意的问题:
  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

# class A:#     __x=1  # 把数据属性隐藏    _A__x##     def __init__(self,name):#         self.__name=name    # _A__name##     def __foo(self):  # 把函数属性隐藏   def _A__foo(self)#         print('run foo')##     def bar(self):#         self.__foo()  #self._A_foo()  定义阶段已经变了#         print('from bar')# print(A.__dict__)# {
'__module__': '__main__', '_A__x': 1, '__init__':
, '_A__foo':
, '__dict__':
, '__weakref__':
, '__doc__': None}# 类定义阶段 __开头发生了变形 __x --> _A__x# print(A.__x)# print(A._A__x)# print(A.__foo)# print(A._A__foo)# a=A('alice')# print(a.__dict__)# {
'_A__name': 'alice'}# print(a.__name)# print(a._A__name)# a.bar()# ---------------------------------------------# class Foo:# def __func(self): #_Foo__func# print('from foo')## class Bar(Foo):# def __func(self): #_Bar__func# print('from bar')# b=Bar()# b.func() # 子类把父类 重名的给覆盖掉了# ---------------------------------------------# class B:# __x=1## def __init__(self,name):# self.__name=name# # print(B._B__x) # 一般不要这么做!py不让你这么干了# B.__y=2 # 类定义完之后不会发生变形# # print(B.__dict__)# # {
'__module__': '__main__', '_B__x': 1, '__init__':
, '__dict__':
, '__weakref__':
, '__doc__': None, '__y': 2}## b=B('alice')# print(b.__dict__) # { '_B__name': 'alice'}## b.__age=18# print(b.__dict__) #{ '_B__name': 'alice', '__age': 18}# ---------------------------------------------# class A:# def foo(self):# print('A.foo')## def bar(self):# print('A.bar')# self.foo() #b.foo## class B(A):# def foo(self):# print('B.foo')## b=B()# b.bar()# ---------------------------------------------class A: def __foo(self): #_A__foo print('A.foo') def bar(self): print('A.bar') self.__foo() #self._A__foo() # 只调自己类的方法 定义时就已经确定好的!class B(A): def __foo(self): #_B__foo print('B.foo')b=B()b.bar()

2.封装的意义

 

封装数据属性目的: (封装不是单纯意义上的隐藏)
明确的区分内外,控制外部对隐藏的属性的操作行为
封装方法属性目的:
隔离复杂度 # a=ATM() a.withdraw(

在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改:

# class People:#     def __init__(self,name,age):#         self.__name=name#         self.__age=age##     def tell_info(self):           # 接口 设定规则#         print('Name:<%s>  Age:<%s>'%(self.__name,self.__age))##     def set_info(self,name,age):   # 接口 间接的修改 设定规则#         if not isinstance(name,str):#             print('名字必须是字符串类型')#             return#         if not isinstance(age,int):#             print('年龄必须是数字类型')#             return#         self.__name=name#         self.__age=age## p=People('alice','18')# p.tell_info()# p.set_info('alex',38)# p.tell_info()# p.set_info('alex','38')# p.tell_info()# -------------------------------------------------------class ATM:    def __card(self):   # 复杂的流程 给隐藏起来了  外部没必要关心        print('插卡')    def __auth(self):        print('用户认证')    def __input(self):        print('输入取款金额')    def __print_bill(self):        print('打印账单')    def __take_money(self):        print('取款')    def withdraw(self):  # 只有这个是用户 关心的        self.__card()        self.__auth()        self.__input()        self.__print_bill()        self.__take_money()a=ATM()a.withdraw()

3.封装与扩展性

面向对象:可扩展性高面向对象三大特性:继承 多态 封装封装的扩展性: def tell_area(self): # 对使用者来说 不用改变 方式 开发者在类里面修改

class Room:    def __init__(self,name,owner,weight,length,height):        self.name=name        self.owner=owner        self.__weight=weight        self.__length=length        self.__height=height    def tell_area(self):  # 对使用者来说 不用改变 方式        return self.__weight * self.__length * self.__heightr=Room('卫生间','alex',10,10,10)print(r.tell_area())

 

4.property的使用

 

Python内置的@property装饰器就是负责把一个方法变成属性调用的:

@property的实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作:

 

注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。

还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:

 

小结

@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。

property :    @property    def bmi(self): 必须有个返回值    print(p.bmi)   可以使 函数属性 伪装成 数据属性  bmi 是名词    p.bmi=23  # 不能赋值 can't set attribute  bmi 实质是个方法 总结:通过计算得来的方法 可以通过@property 伪装成数据属性       @property      查看  必须有返回值       @name.setter   修改       @name.deleter  删除

练习

请利用@property给一个Screen对象加上widthheight属性,以及一个只读属性resolution

class Screen(object):    @property    def resolution(self):        return self.width * self.height# 测试:s = Screen()s.width = 1024s.height = 768print('resolution =', s.resolution)if s.resolution == 786432:    print('测试通过!')else:    print('测试失败!')#输出resolution = 786432测试通过!

 

转载于:https://www.cnblogs.com/mjiu/p/8969115.html

你可能感兴趣的文章
HTTP解析
查看>>
MemCache超详细解读
查看>>
python numpy 教程
查看>>
手机web如何实现多平台分享
查看>>
策略模式和观察者模式
查看>>
详解CALayer 和 UIView的区别和联系
查看>>
eclipse中报错:java.lang.OutOfMemoryError: Java heap space
查看>>
Ubuntu 16.04 grub rescue 模式下修复 grub
查看>>
【Spring】24、<load-on-startup>0</load-on-startup>配置
查看>>
L0 Regularization
查看>>
使用JDBC向Kudu表插入中文数据乱码(转载)
查看>>
spf13-vim安装与使用
查看>>
字体颜色代码表
查看>>
hdu 2156 分数矩阵
查看>>
android SQLite数据库应用于草稿箱
查看>>
Android 无缝换肤深入了解与使用
查看>>
Cordova快速开始(安卓篇)
查看>>
Android 源码分析之旅2 1 IPC以及Service的启动过程
查看>>
Mobx 源码解析 一(observable)
查看>>
ActiveMQ
查看>>