面向对象
简单介绍
首先先来介绍一下面向对象
如今主流的软件开发思想有两种:
一个是面向过程,另一个是面向对象。 面向过程出现得较早,典型代表为C语言,开发中小型项目的效率很高,但是很难适用于如今主流的大中型项目开发场景。面向对象则出现得更晚一些,典型代表为Java或C++等语言,更加适合用于大型开发场景。两种开发思想各有长短。
对于面向过程的思想: 需要实现一个功能的时候,看重的是开发的步骤和过程,每一个步骤都需要自己亲力亲为,需要自己编写代码(自己来做)
对于面向对象的思想:当需要实现一个功能的时候,看重的并不是过程和步骤,而是关心谁帮我做这件事(偷懒,找人帮我做)
面向对象的三大特征有:封装性、继承性、多态性。
类和对象
面向对象的初衷是让开发者可以自己定义数据类型。
其中有两个核心概念:一个是类型(简称类),另一个是对象(又称实例)。
对象是面向对象编程的核心,在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,提出了另外一个新的概念——类
面向对象的语言当中,“类”就是用来模拟现实事物的。
举个简单的例子:
一部手机的设计图纸就可以看做一个类。
一个具体的,真正的手机就可以看做对象。
小结: 类是抽象的,在使用的时候通常会找到这个类的一个具体的存在,使用这个具体的存在。一个类可以找到多个对象。
类是一类事物,对象就是这类事物的具体实现。
类也有属性、行为两个部分组成,对象是类的具体实例。
属性:事物的特征描述信息,用于描述某个特征“是什么”。
行为:事物的能力行动方案,用于说明事物“能做什么”。
定义类和创建对象
语法:
class 类名:
注意: 类的命名使用大驼峰命名法
1.每个单词的首字母大写
2.单词与单词之间没有下划线
举例:
定义一个猫类
class Cat:
def eat(self):
print('%s 爱吃鱼' %(self.name))
def drink(self):
print('猫要喝水')
hellokitty = Cat()
hellokitty.name = 'HK'
print(hellokitty.name)
print(hellokitty)
hellokitty.eat()
hellokitty.drink()
tom = Cat()
tom.eat()
hellokitty是一个对象,也就是代码中的hellokitty.name和self.name是相同的
"""
self:
哪一个对象调用的方法,self就是哪一个对象的引用(指向对象的内存地址空间)
在调用方法的时候,程序员不需要传递self参数(定义的时候 第一个参数必须是self)
对象属性获取
添加和获取对象的属性
class Hero(object):
"""定义了一个英雄类,可以移动和攻击"""
def move(self):
"""实例方法"""
print("正在前往事发地点...")
def attack(self):
"""实例方法"""
print("发出了一招强力的普通攻击...")
实例化了一个英雄对象 泰达米尔
taidamier = Hero()
给对象添加属性,以及对应的属性值
taidamier.name = "泰达米尔" # 姓名
taidamier.hp = 2600 # 生命值
taidamier.atk = 450 # 攻击力
taidamier.armor = 200 # 护甲值
通过.成员选择运算符,获取对象的属性值
print("英雄 %s 的生命值 :%d" % (taidamier.name, taidamier.hp))
print("英雄 %s 的攻击力 :%d" % (taidamier.name, taidamier.atk))
print("英雄 %s 的护甲值 :%d" % (taidamier.name, taidamier.armor))
通过.成员选择运算符,获取对象的实例方法
taidamier.move()
taidamier.attack()
英雄 泰达米尔 的生命值 :2600
英雄 泰达米尔 的攻击力 :450
英雄 泰达米尔 的护甲值 :200
正在前往事发地点...
发出了一招强力的普通攻击...
对象创建并添加属性后,能否在类的实例方法里获取这些属性呢?如果可以的话,应该通过什么方式?
在方法内通过self获取对象属性
class Hero(object):
"""定义了一个英雄类,可以移动和攻击"""
def move(self):
"""实例方法"""
print("正在前往事发地点...")
def attack(self):
"""实例方法"""
print("发出了一招强力的普通攻击...")
def info(self):
"""在类的实例方法中,通过self获取该对象的属性"""
print("英雄 %s 的生命值 :%d" % (self.name, self.hp))
print("英雄 %s 的攻击力 :%d" % (self.name, self.atk))
print("英雄 %s 的护甲值 :%d" % (self.name, self.armor))
实例化了一个英雄对象 泰达米尔
taidamier = Hero()
给对象添加属性,以及对应的属性值
taidamier.name = "泰达米尔" # 姓名
taidamier.hp = 2600 # 生命值
taidamier.atk = 450 # 攻击力
taidamier.armor = 200 # 护甲值
通过.成员选择运算符,获取对象的实例方法
taidamier.info() # 只需要调用实例方法info(),即可获取英雄的属性
taidamier.move()
taidamier.attack()
英雄 泰达米尔 的生命值 :2600
英雄 泰达米尔 的攻击力 :450
英雄 泰达米尔 的护甲值 :200
正在前往事发地点...
发出了一招强力的普通攻击...
魔法方法
__init__函数,它可以在实例化对象的时候修改属性的值。
class Hero(object):
"""定义了一个英雄类,可以移动和攻击"""
# Python 的类里提供的,两个下划线开始,两个下划线结束的方法,就是魔法方法,__init__()就是一个魔法方法,通常用来做属性初始化 或 赋值 操作。
# 如果类面没有写__init__方法,Python会自动创建,但是不执行任何操作,
# 如果为了能够在完成自己想要的功能,可以自己定义__init__方法,
# 所以一个类里无论自己是否编写__init__方法 一定有__init__方法。
def __init__(self):
""" 方法,用来做变量初始化 或 赋值 操作,在类实例化对象的时候,会被自动调用"""
self.name = "泰达米尔" # 姓名
self.hp = 2600 # 生命值
self.atk = 450 # 攻击力
self.armor = 200 # 护甲值
def info(self):
"""在类的实例方法中,通过self获取该对象的属性"""
print("英雄 %s 的生命值 :%d" % (self.name, self.hp))
print("英雄 %s 的攻击力 :%d" % (self.name, self.atk))
print("英雄 %s 的护甲值 :%d" % (self.name, self.armor))
def move(self):
"""实例方法"""
print("正在前往事发地点...")
def attack(self):
"""实例方法"""
print("发出了一招强力的普通攻击...")
实例化了一个英雄对象,并自动调用__init__()方法
taidamier = Hero()
通过.成员选择运算符,获取对象的实例方法
taidamier.info() # 只需要调用实例方法info(),即可获取英雄的属性
taidamier.move()
taidamier.attack()
有参数的__init__()方法
class Hero(object):
"""定义了一个英雄类,可以移动和攻击"""
def __init__(self, name, skill, hp, atk, armor):
""" __init__() 方法,用来做变量初始化 或 赋值 操作"""
# 英雄名
self.name = name
# 技能
self.skill = skill
# 生命值:
self.hp = hp
# 攻击力
self.atk = atk
# 护甲值
self.armor = armor
def move(self):
"""实例方法"""
print("%s 正在前往事发地点..." % self.name)
def attack(self):
"""实例方法"""
print("发出了一招强力的%s..." % self.skill)
def info(self):
print("英雄 %s 的生命值 :%d" % (self.name, self.hp))
print("英雄 %s 的攻击力 :%d" % (self.name, self.atk))
print("英雄 %s 的护甲值 :%d" % (self.name, self.armor))
实例化英雄对象时,参数会传递到对象的__init__()方法里
taidamier = Hero("泰达米尔", "旋风斩", 2600, 450, 200)
gailun = Hero("盖伦", "大宝剑", 4200, 260, 400)
直接输出对象即为地址
print(gailun)
<__main__.Hero object at 0x0318B100>
print(taidamier)
<__main__.Hero object at 0x0318B0D0>
不同对象的属性值的单独保存
print(id(taidamier.name))
print(id(gailun.name))
同一个类的不同对象,实例方法共享
print(id(taidamier.move()))
泰达米尔 正在前往事发地点...
2045877480
print(id(gailun.move()))
盖伦 正在前往事发地点...
2045877480
输出结果:
<__main__.Hero object at 0x0318B100>
<__main__.Hero object at 0x0318B0D0>
51928864
51928912
泰达米尔 正在前往事发地点...
2045877480
盖伦 正在前往事发地点...
2045877480
如果是属性则直接输出其地址值,如果是方法则先执行方法在输出地址值
通过一个类,可以创建多个对象,就好比通过一个模具创建多个实体一样
init(self)中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那么__init__(self)中出了self作为第一个形参外还需要2个形参,例如__init__(self,x,y)
注意:
①在类内部获取 属性 和 实例方法,通过self获取;
②在类外部获取 属性 和 实例方法,通过对象名获取。
③如果一个类有多个对象,每个对象的属性是各自保存的,都有各自独立的地址;
④但是实例方法是所有对象共享的,只占用一份内存空间。类会通过self来判断是哪个对象调用了实例方法。
__str__函数
__str__函数,该函数要求返回一个字符串,这个字符串的信息要能够把对象的信息组织起来,当我们使用print函数打印对象的时候,实际上打印的就是__str__函数返回的字符串。
class Hero(object):
"""定义了一个英雄类,可以移动和攻击"""
def __init__(self, name, skill, hp, atk, armor):
""" __init__() 方法,用来做变量初始化 或 赋值 操作"""
# 英雄名
self.name = name # 实例变量
# 技能
self.skill = skill
# 生命值:
self.hp = hp # 实例变量
# 攻击力
self.atk = atk
# 护甲值
self.armor = armor
def move(self):
"""实例方法"""
print("%s 正在前往事发地点..." % self.name)
def attack(self):
"""实例方法"""
print("发出了一招强力的%s..." % self.skill)
# def info(self):
# print("英雄 %s 的生命值 :%d" % (self.name, self.hp))
# print("英雄 %s 的攻击力 :%d" % (self.name, self.atk))
# print("英雄 %s 的护甲值 :%d" % (self.name, self.armor))
def __str__(self):
"""
这个方法是一个魔法方法 (Magic Method) ,用来显示信息
该方法需要 return 一个数据,并且只有self一个参数,当在类的外部 print(对象) 则打印这个数据
"""
return "英雄 <%s> 数据: 生命值 %d, 攻击力 %d, 护甲值 %d" % (self.name, self.hp, self.atk, self.armor)
taidamier = Hero("泰达米尔", "旋风斩", 2600, 450, 200)
gailun = Hero("盖伦", "大宝剑", 4200, 260, 400)
如果没有__str__ 则默认打印 对象在内存的地址。
当类的实例化对象 拥有 str 方法后,那么打印对象则打印 str 的返回值。
print(taidamier)
print(gailun)
查看类的文档说明,也就是类的注释
print(Hero.__doc__)
封装
公有成员是可以公开使用的,即可以在类的内部进行访问,也可以在外部程序中使用。Python中类的成员函数、成员变量默认都是公开的。
私有成员在类的外部不能直接访问,一般在类的内部进行访问和操作,或者在类的外部通过调用对象的公有成员方法来访问,这是类的封装特性的重要体现。
__xxx:以两个下划线开头,表示类的私有成员,一般只有类对象自己能访问,子类对象也不能直接访问该成员,但可以通过“对象名._类名__xxx”这样的特殊方式来访问。
class Point:
x = 10
__y = 20
z = 30
def get_x(self):
returnself.x
def get_y(self):
returnself.__y
def __get_z(self):
returnself.z
继承
单继承
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。继承用于指定一个类将从其父类获取其大部分或全部功能。它是面向对象编程的一个特征。这是一个非常强大的功能,方便用户对现有类进行几个或多个修改来创建一个新的类。新类称为子类或派生类,从其继承属性的主类称为基类或父类。
简单来说举个例:
子类B继承了父类A,同时也得到了父类中的方法,所以 子类B创建出来的对象b就能到用A中吃的方法
class A(object):
def eat(self):
print(“我要吃泡面”)
class B(A):
pass
b=B()
b.eat()
多重继承
Python子类可以继承一个基类,也可以继承多个基类,这就是多重继承。
还是举个简单的例子
子类B继承了父类A,子类C又继承了父类B,这样的多重继承,最后的子类对象会沿着父类继承的那条路去找所属父类的方法
class A(object):
def eat(self):
print(“我要吃泡面”)
class B(A):
pass
class C(B):
pass
c=C()
c.eat()
注:不建议使用多继承,因为如果 父类A和父类B中方法有一样的,会存在覆盖或存在加载顺序的问题。
多态
多态是指基类的同一方法在不同派生类对象中具有不同的变现和行为。不同的派生类对象调用相同的基类方法,产生了不同的执行结果,这样可以增加代码的外部调用灵活度,多态以继承和重写父类方法为前提条件,多态只是调用方法的技巧,不会影响到类的内部设计。
理解表述:比如:Dog 和哮天犬同时介绍自己 哮天犬 有自己的介绍 Dog有属于自己的介绍
class Amile():
def print_self(self):
pass
class Dog(Amile):
def print_self(self):
print(“我是大黄”)
class xiaotq(Amile):
def print_self(self):
print(“我是哮天犬”)
def jieshao(temp):
temp.print_self()
dog=Dog()
jieshao(dog)
dog2=xiaotq()
jieshao(dog2)