day23-类的封装
1、封装
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
所以,在使用面向对象的封装特性时,需要:
1)将内容封装到某处
2)从某处调用被封装的内容
第一步:将内容封装到某处
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age #根据Foo类构造obj1对象,自动执行Foo类的__init__方法
#将Tom和20分别封装到self也就是obj1的name和age属性中
obj1 = Foo('Tom',20) #根据Foo类构造obj2对象,自动执行Foo类的__init__方法
#将Mike和25分别封装到self也就是obj2的name和age属性中
obj2 = Foo('Mike',25)
self 是一个形式参数,当执行 obj1 = Foo('Tom', 20)时,self等于obj1
当执行 obj2 = Foo('Mike', 25)时,self等于obj2
所以,内容其实被封装到了对象obj1和obj2中,每个对象中都有name和age属性,在内存里类似于下图来保存。

第二步:从某处调用被封装的内容
调用被封装的内容时,有两种情况:
1)通过对象直接调用
2)通过self间接调用
1、通过对象直接调用被封装的内容
上图展示了对象 obj1 和 obj2 在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age obj1 = Foo('Tom', 20)
print(obj1.name) # 直接调用obj1对象的name属性
print(obj1.age) # 直接调用obj1对象的age属性 obj2 = Foo('Mike', 25)
print(obj2.name) # 直接调用obj2对象的name属性
print(obj2.age) # 直接调用obj2对象的age属性
2、通过self间接调用被封装的内容
执行类中的方法时,需要通过self间接调用被封装的内容
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age def detail(self):
print(self.name)
print(self.age) obj1 = Foo('Tom', 20)
obj1.detail() # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的self = obj1,即:self.name是Tom,self.age是20 obj2 = Foo('Mike', 25
obj2.detail() # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的self = obj2,即:self.name是Mike, self.age是25
综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过对象直接或者self间接获取被封装的内容。
2、封装与扩展性
封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。
#类的设计者
class Room:
def __init__(self,name,owner,width,length,high):
self.name=name
self.owner=owner
self.__width=width
self.__length=length
self.__high=high
def tell_area(self): #对外提供的接口,隐藏了内部的实现细节,此时我们想求的是面积
return self.__width * self.__length #使用者
>>> r1=Room('卧室','egon',20,20,20)
>>> r1.tell_area() #使用者调用接口tell_area #类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码
class Room:
def __init__(self,name,owner,width,length,high):
self.name=name
self.owner=owner
self.__width=width
self.__length=length
self.__high=high
def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了
return self.__width * self.__length * self.__high #对于仍然在使用tell_area接口的人来说,根本无需改动自己的代码,就可以用上新功能
>>> r1.tell_area()
例子1:
class Parent:
def func(self):
print('in Parent func') def __init__(self):
self.func() class Son(Parent):
def func(self):
print('in Son func') son1 = Son()
结果是打印了in Son func
在实例化Son类时的流程:
1、在内存中创建了一个空间存储实例化对象son1
2、将实例化对象son1的内存指针指向Son类
3、自动执行Son类中的__init__方法,并将实例化对象son1传给self
4、由于Son类中没有__init__方法,所以就从父类Parent中寻找__init__方法并执行
5、执行父类中的__init__方法,调用了self.func()函数,而此时self是实例化对象son1,所以执行的是son1的func方法
6、son1的func方法打印in Son func
例子2:
class A:
a = 0
b = 1
def __init__(self):
c = 222
d = A()
d.a = 1
d.b = 2
d.c = {'':1}
e = A()
print(e.a)
print(e.b)
print(e.c)
结果:0 1 报错'A' object has no attribute 'c'
1、创建A类时,在A类中定义了静态属性a和b,创建了特殊方法__init__,c=222并不是创建了静态属性,也没有返回c,所以c在内存中并不存在
2、实例化对象d=A(),在d的空间内创建了静态属性a,b,c,但并不会修改A类中的属性
3、实例化对象e=A(),e可以调用A类中的静态属性a和b,但是A类中并不存在静态属性c,所以e.c会报错
day23-类的封装的更多相关文章
- iOS开发--QQ音乐练习,旋转动画的实现,音乐工具类的封装,定时器的使用技巧,SliderBar的事件处理
一.旋转动画的实现 二.音乐工具类的封装 -- 返回所有歌曲,返回当前播放歌曲,设置当前播放歌曲,返回下一首歌曲,返回上一首歌曲方法的实现 头文件 .m文件 #import "ChaosMu ...
- Java—类的封装、继承与多态
一.类和对象 1.类 类是数据以及对数据的一组操作的封装体. 类声明的格式: 类声明 { 成员变量的声明: 成员方法的声明及实现: } 1.1 声明类 [修饰符] class 类<泛型> ...
- 第三篇 :微信公众平台开发实战Java版之请求消息,响应消息以及事件消息类的封装
微信服务器和第三方服务器之间究竟是通过什么方式进行对话的? 下面,我们先看下图: 其实我们可以简单的理解: (1)首先,用户向微信服务器发送消息: (2)微信服务器接收到用户的消息处理之后,通过开发者 ...
- 025医疗项目-模块二:药品目录的导入导出-HSSF导入类的封装
上一篇文章提过,HSSF的用户模式会导致读取海量数据时很慢,所以我们采用的是事件驱动模式.这个模式类似于xml的sax解析.需要实现一个接口,HSSFListener接口. 原理:根据excel底层存 ...
- 022医疗项目-模块二:药品目录的导入导出-对XSSF导出excel类进行封装
资源全部来源于传智播客. 好的架构师写的程序,就算给刚入门的新手看,新手一看就知道怎么去用.所以我们要对XSSF导出excel类进行封装.这是架构师的工作,但我们也要知道. 我们写一个封装类: 这个类 ...
- 黑马程序员——JAVA基础之简述 类的封装
------- android培训.java培训.期待与您交流! ---------- 类的封装(Encapsulation) 封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式. 封装优 ...
- 【面试题001-补充】C++ MyString类的封装
[面试题001-补充]C++ MyString类的封装 一,C++ MyString类的封装 String.h: 123456789101112131415161718192021222324252 ...
- java中关于类的封装与继承,this、super关键字的使用
原创作品,可以转载,但是请标注出处地址http://www.cnblogs.com/V1haoge/p/5454849.html. this关键字: this代表当前对象,它有以下几种用途: 1.本类 ...
- Java---对象与类的封装
一.类和对象: package cn.hncu.Myclasslearn; /** * * @author hncu_chx * * Mylove amin */ /**类是一种数据类型,声明一个类就 ...
- php函数、类和对象以及类的封装、继承、类的静态方法、静态属性
1.函数 php内置函数可以直接使用,如果没有安装php扩展即可 自定义函数 //函数function 函数名 function dump($var = null){ //支出默认参数 ...
随机推荐
- appium 启动了2个端口,但是只有一台机器在跑的 问题解决 (还没试,记录在此)
appium启动了2个,端口分别设置为了4723 4725, 在测试类中也分别指定了设备和端口,用device来指定.然而每次都是运行一个设备. 后来添加了udid这个来指定才发现可以.deviceN ...
- python-selenium 并发执行用例的问题
看了虫师的多进程执行测试用例一直都执行错误,最后解决了 解决方法如下: 使用threading模块 import threading 使用threading.Thread的方法 ,执行用例成功
- hasClass() removeClass() addClass()
//检查第元素是否包含 "intro" 类 $("button").click(function(){ alert($("p:first") ...
- NodeJs使用async让代码按顺序串行执行
描述 由于nodejs中的函数调用都是异步执行的,而笔者在工程开发中函数A需要四五个参数,而这四五个参数值都是通过函数调用获得,因此按顺序写代码时,执行到函数A时,往往函数A需要的参数值因为参数的异步 ...
- maven的包冲突
maven的间接引用会引入其他未声明的包,maven自身的冲突解决方案,最终引用的包可能不是希望的版本. 直接声明期望的版本号,就没有间接引用的问题. 子模块很多时,可以使用dependencyMan ...
- 给VMware下的Linux扩容磁盘空间到根分区(以centos7.0为例)
一.扩展VMWare硬盘空间 关闭Vmware 的 Linux系统,这样,才能在VMWare菜单中设置: VM -> Settings... -> Hardware -> Hard ...
- GVRP
一.GARP和GVRP GARP全称是通用属性注册协议(Generic Attribute Registration Protocol),它为处于同一个交换网内的交换成员之间提供了分发.传播.注册某种 ...
- C#列的一些操作
//变更列名 DataTableA.Columns["原来的列名"].ColumnName="新的列名";
- 在VMware安装Centos7
1.新建虚拟机==>典型==>稍后安装操作系统==>选择linux==>centos 64位 2.填写虚拟机名字以及安装位置. 3.磁盘容量采用默认即可. 4. 自定义硬件: ...
- delphi版本对应
delphi 7 delphi 8delphi 2005 ----- 9delphi 2006 ----- 10 delphi 2007 ----- 11delphi 2009 ----- 12 de ...