面向对象编程(封装、封装的意义、封装与扩展性、@property)
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__': <function A.__init__ at 0x0000017AC92B0B70>, '_A__foo': <function A.__foo at 0x0000017AC92B0BF8>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__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__': <function B.__init__ at 0x00000180405A0B70>, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__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.__height r=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对象加上width和height属性,以及一个只读属性resolution:
class Screen(object):
@property
def resolution(self):
return self.width * self.height # 测试:
s = Screen()
s.width = 1024
s.height = 768
print('resolution =', s.resolution)
if s.resolution == 786432:
print('测试通过!')
else:
print('测试失败!') #输出
resolution = 786432
测试通过!
面向对象编程(封装、封装的意义、封装与扩展性、@property)的更多相关文章
- 【转】Javascript 面向对象编程(一):封装
原文链接:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html Javascript ...
- Javascript 面向对象编程(一):封装 by 阮一峰
<Javascript高级程序设计(第二版)>(Professional JavaScript for Web Developers, 2nd Edition) 它们都是非常优秀的Java ...
- Javascript 面向对象编程(一):封装 作者:yuan一峰
学习Javascript,最难的地方是什么? 我觉得,Object(对象)最难.因为Javascript的Object模型很独特,和其他语言都不一样,初学者不容易掌握. 下面就是我的学习笔记,希望对大 ...
- Javascript 面向对象编程(一):封装
Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类). 那么,如果 ...
- Javascript 面向对象编程初探(一)--- 封装
Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类). 那么,如果 ...
- 老生常谈: Javascript 面向对象编程初探(一)--- 封装
Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类). 那么,如果 ...
- (转)Javascript 面向对象编程(一):封装(作者:阮一峰)
Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类). 那么,如果 ...
- Javascript面向对象编程(一):封装
Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类). 那么,如果 ...
- Javascript 面向对象编程(一):封装(转载)
Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类). 那么,如果 ...
- Javascript 面向对象编程(补充):封装
Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类). 那么,如果 ...
随机推荐
- mapboxgl实现带箭头轨迹线
最近在使用mapboxgl实现轨迹展示时,想实现类似高德地图导航轨迹效果,然而并未在网上找到类似示例.经一番研究与尝试,最终解决,效果如下. 添加箭头核心代码如下,只需在配置layout中添加symb ...
- 如何利用Typora编写博客,快速发布到多平台?
在不同的平台发布同样的文章,最让人头疼的就是图片问题,如果要手动一个个去重新上传,耗时耗力,还容易搞错.下面分享的方法,可以将Typora编写的文章快速发布到CSDN.微信公众号.博客园.简书等平台. ...
- linq to entity不识别方法"System.String ToString()"
将班级id以字符串形式输入如:"1111,1112,1113".数据库里的id为int型,在数据路里找到匹配的相应班级转换成列表.在这里爆出问题:不识别方法"System ...
- wdcp的一个安全漏洞 2015 9 月
wdcp的一个安全漏洞,非常严重,请大家及时升级和检查 在九月份的时候,wdcp出了一个很严重的安全漏洞,当时也出了补丁更新,具体可看http://www.wdlinux.cn/bbs/thread- ...
- #2020征文-开发板# 用鸿蒙开发AI应用(一)硬件篇
目录: 前言 开发板简介 产品特色及功能 产品参数 各个主板功能简介 Hi3516DV300 芯片手册 前言鸿蒙2.0的系统刚开源出来,华为志在打造1+8+N万物互联的全场景智慧生活,不仅是国产操作系 ...
- go mod 拉取私有仓库
前言 如果代码中依赖了本地的包, 这个包是托管在内网 Gitlab 中, 而且不是 HTTPS 服务,那么应该怎样使用 go mod 拉取代码呢? 本文会给你我的答案 正文 首先我们要知道, 如果本地 ...
- 【剑指 Offer】10-II.青蛙跳台阶问题
题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶.求该青蛙跳上一个 n 级的台阶总共有多少种跳法. 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008, ...
- 【Linux】快速创建文件的命令方法
[root@centos7 dir1]# ll total 0 -rw-r--r-- 1 root root 0 Aug 15 02:39 file1 -rw-r--r-- 1 root root 0 ...
- 【Oracle】归档日志的删除操作
[root@sha3 oracle]# rman target / Recovery Manager: Release 10.2.0.4.0 - Production on Tue Jan 20 01 ...
- kubernets之pod的标签
一 如何查看pod 的日志 1 通过执行命令查看日志信息 kubectl logs pod_name 二 创建带有标签的pod,一个范例的pod创建yaml文件如下所示 2.1 创建带有 ...