day20-面向对象编程、继承
一、面向对象编程
1、简介
面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。
而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。
在Python中,所有数据类型都可以视为对象,当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类(Class)的概念。
2、类的构成
类Class由3部分构成
类的名称:类名
类的属性:一组数据
类的方法:允许对类进行操作的方法(行为)
类里面的变量可以叫做静态属性、静态变量、静态字段
类里面的函数一般叫做方法
3、定义类
定义一个类,格式如下:
class 类名:
静态属性
动态方法
4、举例:
class Person: #定义一个人类
role = 'person' #人的角色属性都是人
def walk(self): #人都可以走路,也就是有一个走路方法
print("person is walking...") print(Person.role) #查看人的role属性
print(Person.walk) #引用人的走路方法,注意,这里不是在调用
5、__init__方法
由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__方法,在创建实例的时候,就把name,score等属性绑上去:
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
注意:特殊方法“init”前后有两个下划线!!!
注意到__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去。
6、实例化对象
类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征
实例化对象的过程:
1)在内存中创建了一个内存空间,存储类
2)在这个类内存空间中创建静态变量和特殊方法__init__的内存地址,和动态方法的内存地址
3)在内存中创建了一个内存空间,存储这个变量
一般情况下:
类中的静态属性通过类名去调用或修改
类中的动态方法通过对象去调用执行
class 类名:
def __init__(self,参数1,参数2):
self.对象的属性1 = 参数1
self.对象的属性2 = 参数2 def 方法名(self):pass
def 方法名2(self):pass
对象名 = 类名(1,2) #对象就是实例,代表一个具体的东西
#类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法
#括号里传参数,参数不需要传self,其他与init中的形参一一对应
#结果返回一个对象
对象名.对象的属性1#查看对象的属性,直接用 对象名.属性名 即可
对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可
例子:
class Person: #定义一个人类
role = 'person' #人的角色属性都是人
def __init__(self,name):
self.name = name # 每一个角色都有自己的昵称; def walk(self): #人都可以走路,也就是有一个走路方法
print("person is walking...") p1 = Person('Mike') #实例化人p1
print(p1.role) #查看人的role属性
print(p1.name) #查看人的name属性
p1.walk() #引用人的走路方法
实例化的过程就是类——>对象的过程
7、self
self:在实例化时自动将对象/实例本身传给__init__的第一个参数,你也可以给他起个别的名字,但是约定俗成都这么写。
8、类属性的补充
8.1、我们定义的类的属性到底存到哪里了?有两种方式查看
dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值
print(dir(Person))
#['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
# '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
# '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'role', 'walk'] print(Person.__dict__)
#{'__module__': '__main__', 'role': 'person', '__init__': <function Person.__init__ at 0x0054FA98>,
# 'walk': <function Person.walk at 0x0054FA50>, '__dict__': <attribute '__dict__' of 'Person' objects>,
# '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
8.2、特殊的类属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)
9、类名称空间与对象的名称空间
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性
而类有两种属性:静态属性和动态属性
静态属性就是直接在类中定义的变量
动态属性就是定义在类中的方法
其中类的数据属性也叫静态属性是共享给所有对象的,通过id可以看出在内存中的地址是一样的
print(id(Person.role))
#
print(id(p1.role))
#
而类的动态属性是绑定到所有对象的,通过引用类的动态方法可以看出方法在内存中的地址是不一样的
print(Person('Tom').walk)
#<bound method Person.walk of <__main__.Person object at 0x01E83050>>
print(p1.walk)
#<bound method Person.walk of <__main__.Person object at 0x01E72F70>>
创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常
二、面向对象的三大特性:继承,多态,封装
2.1继承
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
python中类的继承分为:单继承和多继承
2.2、单继承
比如,我们已经编写了一个名为Animal的class,有一个run()方法可以直接打印:
class Animal:
def run(self):
print('Animal is running...')
当我们需要编写Dog和Cat类时,就可以直接从Animal类继承:
class Dog(Animal):
pass
class Cat(Animal):
pass
对于Dog来说,Animal就是它的父类,对于Animal来说,Dog就是它的子类。Cat和Dog类似。
继承有什么好处?最大的好处是子类获得了父类的全部功能。
由于Animial实现了run()方法,因此,Dog和Cat作为它的子类,什么事也没干,就自动拥有了run()方法:
dog = Dog()
dog.run() cat = Cat()
cat.run() 运行结果如下:
Animal is running...
Animal is running...
继承的第二个好处需要我们对代码做一点改进。你看到了,无论是Dog还是Cat,它们run()的时候,显示的都是Animal is running...,符合逻辑的做法是分别显示Dog is running...和Cat is running...,因此,对Dog和Cat类改进如下:
class Dog(Animal):
def run(self):
print('Dog is running...') class Cat(Animal):
def run(self):
print('Cat is running...') 再次运行,结果如下:
Dog is running...
Cat is running...
在单继承中,如果只想执行父类的属性或方法,那么子类的属性名或方法不能与父类中的属性名或方法名重复,否则只会执行子类中的属性或方法,相当于重写
如果既想执行子类的方法,又想执行父类中的方法,有2种方法:
方法1、使用super
class A:
def func(self):
print('in A') class B(A):
def func(self):
super().func()
print('in B') b1 = B()
b1.func()
结果:
in A
in B
方法2、方法内调用
class A:
def func(self):
print('in A') class B(A):
def func(self):
A.func(self)
print('in B') b1 = B()
b1.func()
结果:
in A
in B
2.3、多继承
继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object,这些继承关系看上去就像一颗倒着的树。比如如下的继承树:
class Base:
def test(self):
print('---Base---') class A(Base):
def test(self):
print('---A---')
def testA(self):
print('---A---') class B(Base):
def test(self):
print('---A---')
def testB(self):
print('---B---') class C(A, B):
pass c = C()
c.test()
类A和类B都继承类Base,类C继承类A和B
调用类C的test方法时,依次查看的顺序是类A,类B,类Base
如果定义类C时写成class C(B, A):,则先查看B,再查看A
print(C.__mro__) #在Python3中可以查看C类的对象搜索方法时的先后顺序。
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>)
2.3、查看继承
>>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
(<class '__main__.ParentClass1'>,)
>>> SubClass2.__bases__
(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
>>> ParentClass1.__bases__
(<class 'object'>,)
>>> ParentClass2.__bases__
(<class 'object'>,)
当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run()。这样,我们就获得了继承的另一个好处:多态。
继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。
2.4、重写
就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法
class Cat:
def sayHello(self):
print("halou...")
class Bosi(Cat):
def sayhello(self):
#调用父类的方法sayHello,在python2和3中都可以用,在参数中需要加self
Cat.sayHello(self)
#调用父类的方法sayHello,在python3中可以用,参数不需要加self,2种方法都可以
#super().sayHello()
print("hello...")
bosi = Bosi()
bosi.sayhello() halou...
hello...
2.5、私有属性不会被继承,公有属性会被继承
私有属性和私有方法只有在同一个类内部才能够继承,在外部不能继承
class 类1:
def 方法1(self):
self.属性1
self.__属性2
def __方法2(self):
self.方法1() #在相同类中的不同方法中,属性1可以继承,属性2也可以继承
def 方法3(self):
self.方法1() #因为是在同一个类中,所以方法1可以继承,包括公有方法1中的公有属性1和私有属性2
self.__方法2() #因为是在同一个类中,方法2可以继承 class 类2(类1): #继承类1
def 方法1(self):
self.属性1 #在不同类中公有属性1可以继承
self.__属性2 #在不同类中私有属性2不能继承
def 方法3(self):
self.方法1() #在不同类中公有方法1可以继承,包括公有方法1中的公有属性1和私有属性2
self.__方法2() #在不同类中私有方法2不能继承 aa = 类1()
bb = 类2()
类1中
方法1是公有方法
属性1是公有属性,在不同的方法和不同的类中都可以继承
属性2是私有属性,在不同的类中不可以继承,在同一个类中不同方法中可以继承
__方法2是私有方法,在同一个类中可以继承,在不同的类中不可以继承
day20-面向对象编程、继承的更多相关文章
- C++ Primer 学习笔记_69_面向对象编程 --继承情况下的类作用域
面向对象编程 --继承情况下的类作用域 引言: 在继承情况下,派生类的作用域嵌套在基类作用域中:假设不能在派生类作用域中确定名字,就在外围基类作用域中查找该名字的定义. 正是这样的类作用域的层次嵌套使 ...
- Python 面向对象编程 继承 和多态
Python 面向对象编程 继承 和多态 一:多继承性 对于java我们熟悉的是一个类只能继承一个父类:但是对于C++ 一个子类可以有多个父亲,同样对于 Python一个类也可以有多个父亲 格式: c ...
- Python面向对象编程——继承与派生
Python面向对象编程--继承与派生 一.初始继承 1.什么是继承 继承指的是类与类之间的关系,是一种什么"是"什么的关系,继承的功能之一就是用来解决代码重用问题. 继承是一种创 ...
- Javascript 面向对象编程—继承和封装
前 言 Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类) ...
- Javascript 进阶 面向对象编程 继承的一个样例
Javascript的难点就是面向对象编程,上一篇介绍了Javascript的两种继承方式:Javascript 进阶 继承.这篇使用一个样例来展示js怎样面向对象编程.以及怎样基于类实现继承. 1. ...
- Javascript 进阶 面向对象编程 继承的一个例子
Javascript的难点就是面向对象编程,上一篇介绍了Javascript的两种继承方式:Javascript 进阶 继承,这篇使用一个例子来展示js如何面向对象编程,以及如何基于类实现继承. 1. ...
- python面向对象编程 继承 组合 接口和抽象类
1.类是用来描述某一类的事物,类的对象就是这一类事物中的一个个体.是事物就要有属性,属性分为 1:数据属性:就是变量 2:函数属性:就是函数,在面向对象里通常称为方法 注意:类和对象均用点来访问自己的 ...
- Py修行路 python基础 (十五)面向对象编程 继承 组合 接口和抽象类
一.前提回忆: 1.类是用来描述某一类的事物,类的对象就是这一类事物中的一个个体.是事物就要有属性,属性分为 1:数据属性:就是变量 2:函数属性:就是函数,在面向对象里通常称为方法 注意:类和对象均 ...
- 【前端学习】javascript面向对象编程(继承和复用)
前言 继承,代码复用的一种模式.和其它高级程序语言相比,javascript有点点不一样,它是一门纯面向对象的语言,在JS中,没有类的概念,但也可以通过原型(prototype)来模拟对象 ...
- CSIC_716_20191126【面向对象编程--继承】
继承 什么是继承:继承是新建类的一种方式,通过此方式生成的类称为子类.或者 派生类,被继承的类称为父类.基类或超类.在python中,一个子类可以继承多个父类. 继承的作用:减少代码的冗余,提高开发效 ...
随机推荐
- SSM的配置文件
Mybatis: SqlMapConfig.xml,配置了数据源,连接池,事务,加载sql映射文件(pojo),sqlsessionFactory对象,配置到spring容器中,mapeer代理对象或 ...
- Python——字符串2.0(实验)(python programming)
直接打s,是程序员看到的:打print(),是用户看到的 列表 ] #列表索引,与数组唯一不同:等号左端可修改 转载自:https://www.cnblogs.com/wwwwwei/p/104816 ...
- 理解 neutron(15):Neutron Linux Bridge + VLAN/VXLAN 虚拟网络
学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...
- Zabbix 告警内容配置
#配置媒介告警类型 #----------------------------------------------------------------------------------------- ...
- MySQL学习----多版本并发mvcc
MySQL中的大多数事务性存储引擎实现的都不是简单的行级锁.基于提升并发性能的考虑,他们一般实现了多版本并发控制(mvcc).不仅是mysql,包括oracle,postgresql等其他数据库也实现 ...
- Find the peace with yourself
The purpose of being mature is to find the real calm and peace with yourself. Or you can say the tur ...
- 第11章 拾遗5:IPv6和IPv4共存技术(2)_ISATAP隧道技术
6.3 ISATAP隧道技术 (1)基本概念 ①在一个IPv4网络中主机与路由器之间创建一条ISATAP隧道,以便让该主机可以访问IPv6网络中的资源. ②条件:IPv4中的PC主机需要支持IPv4和 ...
- 升级Android Studio到1.0.2的问题解决
当前从光网下载到的Android Studio的版本是1.0.1,升级到1.0.2大概是3M的升级包.升级很简单,点击Help--Check For Update... 可是我碰到的情况是提示:Con ...
- 百度翻译API(C#)
百度翻译开放平台:点击打开链接 1. 定义类用于保存解析json得到的结果 public class Translation { public string Src { get; set; } pub ...
- 外网访问内网的FTP服务器-原理解析
1. 背景简介 最近研究如何在内网搭架FTP服务器,同时要保证外网(公网)能访问的到.终成正果,但走了一些弯路,在此记下,以飨后人. 2. 基础知识 FTP 使用 2 个端口,一个数据端口和一个命令端 ...