Python20-Day07
面向对象之继承与派生
什么是继承?
继承是一种创建新类的方式,新建的类可以继承一个或者多个父类,父类又称为基类或者超类,新建的类称为派生类或者子类
子类会‘遗传’父类的特性,从而解决代码重用问题
python中分为单继承和多继承
class ParentClass1: #定义父类
pass class ParentClass2: #定义父类
pass class SubClass1(ParentClass1): #单继承,父类是ParentClass1,子类是SubClass
pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
pass
查看继承
#print(SubClass1.__bases__)
(<class '__main__.ParentClass1'>,) #print(SubClass2.__bases__)
(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
经典类与新式类
1、只有python2中才分为经典类和新式类,python3中都是新式类
2、在python2中没有标明继承object类的类,以及该类的子类,都称为经典类
3、在python2中标明继承object类的类,以及该类的子类,称为新式类
4、python3中,无论是否继承object类,默认都继承object类,即python3中都为新式类
继承与抽象
继承描述的是子类与父类之间的关系,是什么是什么的关系,要找出这种关系,必须先抽象再继承
属性查找
class Foo:
def f1(self):
print('Foo.f1') def f2(self):
print('Foo.f2')
self.f1() class Bar(Foo):
def f1(self):
print('Foo.f1') b=Bar()
b.f2() #得到的结果为:
Foo.f2
Foo.f1
派生
子类也可以添加自己新的属性或者自己重新定义属性。一旦重新定义了自己的属性且与父类重名,调用新增的属性时,就以自己的为准了。
class ParentClass:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def tell_info(self):
print('%s is in old_class!' %self.name)
class SubClass(ParentClass):
def __init__(self,name,age,sex):
ParentClass.__init__(self,name,age,sex)
# def tell_info(self):
# print('%s is in subclass!' %self.name) stu1 = SubClass('zly',25,'female')
stu1.tell_info() #此时调用结果为:
zly is in old_class! #如果在SubClass子类中也定义tell_info属性,此时调用结果为:
zly is in subclass!
组合与重用性
软件重用的重要方式除了继承之外还有另外一种:组合
组合指的是:在一个类中以另外一个类的对象作为数据属性,称为类的组合
继承:
通过继承建立了派生类与基类之间的关系,是一种什么是什么的关系。
当类之间有很多相同的功能,提取这些共同的功能做成父类。用继承比较好
组合:
用组合的方式建立了类与组合的类之间的关系,是一种有的关系。
class People:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex class Course:
def __init__(self,name,period,price):
self.name=name
self.period=period
self.price=price
def tell_info(self):
print('<%s %s %s>' %(self.name,self.period,self.price)) class Teacher(People):
def __init__(self,name,age,sex,job_title):
People.__init__(self,name,age,sex)
self.job_title=job_title
self.course=[]
self.students=[] class Student(People):
def __init__(self,name,age,sex):
People.__init__(self,name,age,sex)
self.course=[] egon=Teacher('egon',18,'male','沙河霸道金牌讲师')
s1=Student('牛榴弹',18,'female') python=Course('python','3mons',3000.0)
linux=Course('python','3mons',3000.0) #为老师egon和学生s1添加课程
egon.course.append(python)
egon.course.append(linux)
s1.course.append(python) #为老师egon添加学生s1
egon.students.append(s1) #使用
for obj in egon.course:
obj.tell_info()
抽象类
抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
从设计的角度看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象来的。
抽象类中只有抽象方法,没有实现功能,该类不能被实例化,只能被继承,且子类必须实现抽象方法。
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
#一切皆文件
import abc #利用abc模块实现抽象类 class All_file(metaclass=abc.ABCMeta):
all_type='file'
@abc.abstractmethod #定义抽象方法,无需实现功能
def read(self):
'子类必须定义读功能'
pass @abc.abstractmethod #定义抽象方法,无需实现功能
def write(self):
'子类必须定义写功能'
pass # class Txt(All_file):
# pass
#
# t1=Txt() #报错,子类没有定义抽象方法 class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('文本数据的读取方法') def write(self):
print('文本数据的读取方法') class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('硬盘数据的读取方法') def write(self):
print('硬盘数据的读取方法') class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('进程数据的读取方法') def write(self):
print('进程数据的读取方法') wenbenwenjian=Txt() yingpanwenjian=Sata() jinchengwenjian=Process() #这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read() print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)
继承实现的原理
1、继承顺序
如果继承关系为非菱形结果,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支,
如果继承关系为菱形结构,属性查找:深度优先和广度优先。
2、继承原理
定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表。
所有父类的MRO列表遵循以下3条原则:
1、子类会先与父类被检查
2、多个父类会根据他们在列表中的顺序被检查
3、如果对下一个类存在两个合法的选择,选择第一个父类
面向对象之封装
如何隐藏?
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
#其实这仅仅这是一种变形操作且仅仅只在类定义阶段发生变形
#类中所有双下划线开头的名称如__x都会在类定义时自动变形成:_类名__x的形式: class A:
__N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
def __init__(self):
self.__X=10 #变形为self._A__X
def __foo(self): #变形为_A__foo
print('from A')
def bar(self):
self.__foo() #只有在类内部才可以通过__foo的形式访问到. #A._A__N是可以访问到的,
#这种,在外部是无法通过__x这个名字访问到。
变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形
在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有。
#正常情况
>>> class A:
... def fa(self):
... print('from A')
... def test(self):
... self.fa()
...
>>> class B(A):
... def fa(self):
... print('from B')
...
>>> b=B()
>>> b.test()
from B #把fa定义成私有的,即__fa
>>> class A:
... def __fa(self): #在定义时就变形为_A__fa
... print('from A')
... def test(self):
... self.__fa() #只会与自己所在的类为准,即调用_A__fa
...
>>> class B(A):
... def __fa(self):
... print('from B')
...
>>> b=B()
>>> b.test()
from A
封装数据:
将数据隐藏起来,然后对外提供操作该数据的接口,然后可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格限制。
class Teacher:
def __init__(self,name,age):
# self.__name=name
# self.__age=age
self.set_info(name,age) def tell_info(self):
print('姓名:%s,年龄:%s' %(self.__name,self.__age))
def set_info(self,name,age):
if not isinstance(name,str):
raise TypeError('姓名必须是字符串类型')
if not isinstance(age,int):
raise TypeError('年龄必须是整型')
self.__name=name
self.__age=age t=Teacher('egon',18)
t.tell_info() t.set_info('egon',19)
t.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()
特性(property)
什么是特性property?
property是一种特殊的属性,访问它时会执行一段功能,然后返回值。
class People:
def __init__(self,name,weight,height):
self.name=name
self.weight=weight
self.height=height
@property
def bmi(self):
return self.weight / (self.height**2) p1=People('egon',75,1.85)
print(p1.bmi)
为什么要用property?
将一个类的函数定义成特性后,对象再去使用的时候obj.name,根本无法察觉自己的nameshi执行了一个函数后计算出来的。这种特性的使用方式遵循了统一访问的原则
面向对象之绑定方法与非绑定方法
类中定义的函数分成两大类
1、绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入)
1、绑定到类的方法:用classmethod装饰器装饰的方法
为类量身定制
2、绑定到对象的方法:没有被任何装饰器装饰的方法
为对象量身定制
属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值一说。
2、非绑定方法:用staicmethod装饰器装饰的方法
1、不与类或对象绑定,类和对象都可以调用。但是没有自动传值一说,就是一个普通工具。
绑定方法:
绑定给类的方法(classmethod)
classmethod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数,python内置了函数classmethod来吧类中的函数定义成类方法
#settings.py
HOST='127.0.0.1'
PORT=3306
DB_PATH=r'C:\Users\Administrator\PycharmProjects\test\面向对象编程\test1\db'
import settings
class MySQL:
def __init__(self,host,port):
self.host=host
self.port=port @classmethod
def from_conf(cls):
print(cls)
return cls(settings.HOST,settings.PORT) print(MySQL.from_conf) #<bound method MySQL.from_conf of <class '__main__.MySQL'>>
conn=MySQL.from_conf() conn.from_conf() #对象也可以调用,但是默认传的第一个参数仍然是类
非绑定方法
在类内部用staicmethod装饰的函数即非绑定方法,就是普通函数
staicmethod不与类或对象绑定,谁都可以调用,没有自动传值效果
import hashlib
import time
class MySQL:
def __init__(self,host,port):
self.id=self.create_id()
self.host=host
self.port=port
@staticmethod
def create_id(): #就是一个普通工具
m=hashlib.md5(str(time.time()).encode('utf-8'))
return m.hexdigest() print(MySQL.create_id) #<function MySQL.create_id at 0x0000000001E6B9D8> #查看结果为普通函数
conn=MySQL('127.0.0.1',3306)
print(conn.create_id) #<function MySQL.create_id at 0x00000000026FB9D8> #查看结果为普通函数
classmethod与staicmethod区别
import settings
class MySQL:
def __init__(self,host,port):
self.host=host
self.port=port @staticmethod
def from_conf():
return MySQL(settings.HOST,settings.PORT) # @classmethod #哪个类来调用,就将哪个类当做第一个参数传入
# def from_conf(cls):
# return cls(settings.HOST,settings.PORT) def __str__(self):
return '就不告诉你' class Mariadb(MySQL):
def __str__(self):
return '<%s:%s>' %(self.host,self.port) m=Mariadb.from_conf()
print(m) #我们的意图是想触发Mariadb.__str__,但是结果触发了MySQL.__str__的执行,打印就不告诉你:
Python20-Day07的更多相关文章
- day07 Cookie 和 Session(非常重要)
day07 Cookie 和 Session 1. 会话技术 2. cookie 的方法和 cookie 案例-显示用户上次访问网站的时间 3. cookie 的细节 - 删除 cookie 4. S ...
- python day07笔记总结
2019.4.4 S21 day07笔记总结 一.深浅拷贝 1.copy.copy() 浅拷贝 deep.copy() 深拷贝 2.一般情况 1.str/int/bool 是不可变类型 ...
- Python面向对象-day07
写在前面 上课第七天,打卡: 时间的高效利用: 前言: 今天egon老师补充了下 is 和 == 的区别,整理如下:Python中变量的属性以及判断方法 一.面向过程和面向对象 - 1.面向过程 核心 ...
- 逆袭之旅.DAY07东软实训..封装~继承~抽象~final
2018年7月3日.逆袭之旅DAY07 package day0703.exam1; /** * 狗狗类 使用权限修饰符private和public进行封装 * @author Administrat ...
- C++Primer笔记-----day07
==========================================================================day07===================== ...
- Day07 jdk5.0新特性&Junit&反射
day07总结 今日内容 MyEclipse安装与使用 JUnit使用 泛型 1.5新特性 自动装箱拆箱 增强for 静态导入 可变参数方法 枚举 反射 MyEclipse安装与使用(yes) 安装M ...
- python开发学习-day07(面向对象之多态、类的方法、反射、新式类and旧式类、socket编程)
s12-20160227-day07 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...
- 2017-2018-1 JAVA实验站 冲刺 day07
2017-2018-1 JAVA实验站 冲刺 day07 各个成员今日完成的任务 小组成员 今日工作 完成进度 张韵琪 写博客.进行工作总结 100% 齐力锋 部分按钮图片.对按钮图片进行ps 100 ...
- dup、文件锁、库函数、函数调用(day07)
一.lseek()重新定位文件的读写位置. #include <sys/types.h> #include <unistd.h> off_t lseek(int fd, off ...
- 记录我的 python 学习历程-Day07 基础数据类型进阶 / 数据类型之间的转换 / 基础数据类型总结 / 编码的进阶
基础数据类型 str(字符串) str:补充方法练习一遍就行 s.capitalize() 首字母大写,其余变小写 s = 'dyLAn' print(s.capitalize()) # Dylan ...
随机推荐
- 添加打印功能 iOS
app直接调取系统的打印功能 https://blog.csdn.net/wsyx768/article/details/79098885
- CS231N assignment1
# Visualize some examples from the dataset. # We show a few examples of training images from each cl ...
- 使用iometer测试
对国产机进行测试 1.win7上安装测试 下载: 点击打开链接 双击安装即可. 2.ubuntu下配置: OS: Ubuntu 12.04LTS x86_64Kernel: 3.5.0-26-gene ...
- Xamarin 编写混合APP趟坑记录(二)
前言 公司要开发一个App,为了便于维护和更新,而不用每次去苹果审核,采用的是混合开发方式:用WebVie+WebApp的方式. 因为本人不会Java和ObjectC,公司又不想花钱招这两个岗位的人, ...
- 【转载】WCF 客户端识别认证之UserName认证
原文地址: http://blog.csdn.net/zxz414644665/article/details/9308055 过程:用户调用service,服务端验证用户传来的用户名和密码(传输过程 ...
- 2017-2018-1 20155305 《信息安全系统设计基础》第四周学习总结(课堂提交作业未来得及提交码云链接myod补充博客)
2017-2018-1 20155305 <信息安全系统设计基础>第四周学习总结(课堂提交作业未来得及提交码云链接myod补充博客) 课堂提交题目要求 编写MyOD.java 用java ...
- JavaWeb总结(十三)
Web开发模式的变迁 了解了Servlet和JSP,知道利用Servlet就可以开发一个Web应用程序,但是Servlet的缺陷使Web应用程序开发变得非常繁琐且不利于分工协作.使用JSP(表达式.声 ...
- Tarjan/2-SAT学习笔记
Tarjan/2-SAT Tags:图论 作业部落 评论地址 Tarjan 用来求割边或者割点,求点双联通分量或者边双联通分量 点双联通分量:两个点之间有两条点不相交的路径 边双联通分量:两个点之间有 ...
- [Qt扒手2] PyQt5 路径绘画例子
[说明] 此例扒自 Qt 官网,原例是 C++ 代码,我把它改写成了 Python + PyQt5 版本. 有了前一个例子的成功,这个例子改写的非常之快.记得第一个例子花了我几天的时间,而这个例子只花 ...
- js 日期,时间函数 及相关运算大全
一.在js中如何比较两个时间字符串的大小 方法一: function CompareDate(d1,d2){ return ((new Date(d1.replace(/-/g,"/ ...