面向对象编程介绍
面向对象
1. 概述
如今主流的软件开发思想有两种:一个是面向过程,另一个是面向对象。面向过程出现得较早,典型代表为C语言,开发中小型项目的效率很高,但是很难适用于如今主流的大中型项目开发场景。面向对象则出现得更晚一些,典型代表为Java或C++等语言,更加适合用于大型开发场景。两种开发思想各有长短。
对于面向过程的思想: 需要实现一个功能的时候,看重的是开发的步骤和过程,每一个步骤都需要自己亲力亲为,需要自己编写代码(自己来做)
对于面向对象的思想:当需要实现一个功能的时候,看重的并不是过程和步骤,而是关心谁帮我做这件事(偷懒,找人帮我做)
面向对象的三大特征有:封装性、继承性、多态性。
2. 生活举例
-
洗衣服
l 面向过程(手洗):脱衣服、找一个盆、加水、加洗衣粉、浸泡30分钟、搓洗、拧衣服、倒掉水、再加水、漂洗、拧衣服、倒掉水、晾衣服。
l 面向对象(机洗):脱衣服、放入洗衣机、按下开关、拿出衣服晾晒。
-
买电脑
l 面向过程(自己买):需要电脑、查询参数信息、横向比较机型、了解打折信息、与店家讨价还价、下单、收快递、开机验货、确认收货。
l 面向对象(找人买):需要电脑、找秘书帮我买、收电脑。
-
吃饭
l 面向过程(自己做):我饿了、买菜、洗菜择菜、切菜、起火、炒菜、盛菜、吃饭、刷碗。
面向对象(出去买):我饿了、买饭、吃饭。
类和对象
面向对象编程的2个非常重要的概念:类和对象
对象是面向对象编程的核心,在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,提出了另外一个新的概念——类
1. 类
我们学习编程语言,就是为了模拟现实世界中的事物,实现信息化来提高工作效率。例如银行的业务系统、超市的结账系统等,都是如此。
面向对象的语言当中,“类”就是用来模拟现实事物的。
那么模拟现实世界的事物通常从两方面模拟:
- 属性:事物的特征描述信息,用于描述某个特征“是什么”。 静
- 行为:事物的能力行动方案,用于说明事物“能做什么”。
类中也有属性、行为两个组成部分,而“对象”是类的具体实例。例如:
- 类:抽象的,是一张“手机设计图”。
- 对象:具体的,是一个“真正的手机实例”。
类就相当于制造飞机时的图纸,用它来进行创建的飞机就相当于对象
人以类聚 物以群分。
具有相似内部状态和运动规律的实体的集合(或统称为抽象)。
具有相同属性和行为事物的统称
类是抽象的,在使用的时候通常会找到这个类的一个具体的存在,使用这个具体的存在。一个类可以找到多个对象
2. 对象
某一个具体事物的存在 ,在现实世界中可以是看得见摸得着的。
可以是直接使用的
3. 类和对象之间的关系
小总结:类就是创建对象的模板
4. 练习:区分类和对象
奔驰汽车 类
奔驰smart 类
张三的那辆奔驰smart 对象
狗 类
大黄狗 类
李四家那只大黄狗 对象
水果 类
苹果 类
红苹果 类 红富士苹果 类
我嘴里吃了一半的苹果 对象
5. 类的构成
类(Class) 由3个部分构成
- 类的名称:类名
- 类的属性:一组数据
- 类的方法:允许对进行操作的方法 (行为)
<1> 举例:
1)人类设计,只关心3样东西:
- 事物名称(类名):人(Person)
- 属性:身高(height)、年龄(age)
- 方法(行为/功能):跑(run)、打架(fight)
2)狗类的设计
- 类名:狗(Dog)
- 属性:品种 、毛色、性别、名字、 腿儿的数量
- 方法(行为/功能):叫 、跑、咬人、吃、摇尾巴
6. 类的抽象
如何把日常生活中的事物抽象成程序中的类?
拥有相同(或者类似)属性和行为的对象都可以抽像出一个类
方法:一般名词都是类(名词提炼法)
<1> 坦克发射3颗炮弹轰掉了2架飞机
- 坦克–》可以抽象成 类
- 炮弹–》可以抽象成类
- 飞机-》可以抽象成类
<2> 小明在公车上牵着一条叼着热狗的狗
- 小明–》 人类
- 公车–》 交通工具类
- 热狗–》 食物类
- 狗–》 狗类
<3>【想一想】如下图中,有哪些类呢?
说明:
- 人
- 枪
- 子弹
- 手榴弹
- 刀子
- 箱子
<4>【想一想】如下图中,有哪些类呢?
说明:
- 向日葵
- 类名: xrk
- 属性:
- 行为: 放阳光
- 豌豆
- 类名: wd
- 属性: 颜色 、发型,血量
- 行为:发炮, 摇头
- 坚果:
- 类名:jg
- 属性:血量 类型
- 行为:阻挡;
- 僵尸:
- 类名:js
- 属性:颜色、血量、 类型、速度
- 行为:走 跑跳 吃 死
定义类
定义一个类,格式如下:
class 类名:
方法列表
demo:定义一个Hero类
# class Hero: # 经典类(旧式类)定义形式
# class Hero():
class Hero(object): # 新式类定义形式
def info(self):
print("英雄各有见,何必问出处。")
说明:
-
定义类时有2种形式:新式类和经典类,上面代码中的Hero为新式类,前两行注释部分则为经典类;
-
object 是Python 里所有类的最顶级父类;
-
类名 的命名规则按照"大驼峰命名法";
-
info 是一个实例方法,第一个参数一般是self,表示实例对象本身,当然了可以将self换为其它的名字,其作用是一个变量 这个变量指向了实例对象
self
使用self替换方法中的对象名
class Cat:
# 方法
def eat(self):
print("猫在吃鱼....")
def drink(self):
print("猫在喝可乐...")
def introduce(self):
# print("名字是:%s, 年龄是:%d" % (汤姆的名字, 汤姆的年龄))
# print("名字是:%s, 年龄是:%d" % (tom.name, tom.age))
print("名字是:%s, 年龄是:%d" % (self.name, self.age))
# 创建了一个对象
tom = Cat()
tom.name = "汤姆"
tom.age = 30
tom.eat()
tom.drink()
print(tom.name)
print(tom.age)
print("-"*30)
tom.introduce()
print("="*30)
# 创建了另外一个对象
lan_mao = Cat()
lan_mao.name = "蓝猫"
lan_mao.age = 20
lan_mao.introduce() # 相当于lan_mao.introduce(lan_mao)
一个较为完整的程序
class Cat:
# 方法
def eat(self):
print("%s在吃鱼...." % self.name) # 这里换成self
def drink(self):
print("%s在喝可乐..." % self.name) # 这里换成self
def introduce(self):
# print("名字是:%s, 年龄是:%d" % (汤姆的名字, 汤姆的年龄))
# print("名字是:%s, 年龄是:%d" % (tom.name, tom.age))
print("名字是:%s, 年龄是:%d" % (self.name, self.age))
# 创建了一个对象
tom = Cat()
tom.name = "汤姆"
tom.age = 30
tom.eat()
tom.drink()
print(tom.name)
print(tom.age)
print("-"*30)
tom.introduce()
print("="*30)
# 创建了另外一个对象
lan_mao = Cat()
lan_mao.name = "蓝猫"
lan_mao.age = 20
lan_mao.introduce() # 相当于lan_mao.introduce(lan_mao)
lan_mao.eat()
lan_mao.drink()
总结
- 所谓的self,可以理解为自己
- 可以把self当做C++中类里面的this指针一样理解,就是对象自身的意思
- 某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发者只需要传递后面的参数即可
- self仅仅是一个变量名,也可将self换为其他任意的名字,但是为了能够让其他开发人员能明白这变量的意思,因此一般都会self当做名字
属性
在类中我们可以定义一些属性,比如:
class people:
name = 'Tom'
age = 12
p = people()
print("name=%s, age=%d"%(p.name,p.age))
定义了一个people类,里面定义了name和age属性,默认值分别为’Tom’和12。
在定义了类之后,就可以用来产生实例化对象了,这句p = people( )实例化了一个对象p,然后就可以通过p来读取属性了。这里的name和age都是公有
的,可以直接在类外通过对象名访问,如果想定义成私有
的,则需在前面加2个下划线 即’__’
class people:
__name = 'Tom'
__age = 12
p = people()
print("name=%s, age=%d"%(p.__name,p.__age))
这段程序运行会报错:
注意点:
提示找不到该属性,因为私有属性是不能够在类外通过对象名来进行访问的。在Python中没有像C++中public和private这些关键字来区别公有属性和私有属性,它是以属性命名方式来区分,如果在属性名前面加了2个下划线’__’,则表明该属性是私有属性,否则为公有属性(方法也是一样,方法名前面加了2个下划线的话表示该方法是私有的,否则为公有的)。
定义学生类
## 类和对象
# 面向对象 vs 面向过程
# 定义类
'''
class 类名():
## 属性
## 方法
pass
# 使用类 实例化
对象名 = 类名()
对象名.属性名
对象名.方法名
'''
class Student():
"""魔法方法(具有特殊含义的方法)__init__当类被实例化的时候回自动调用"""
def __init__(self):
print("__init__被自动调用")
self.name = None
self.age = None
self.score = None
def study(self):
print(f"{self.name}在疯狂的学习中....")
def show(self):
print(f'姓名: {self.name} , 年龄: {self.age}, 成绩: {self.score}')
s1 = Student()
s1.name = "张三"
s1.age = 19
s1.score = 99
print(s1.name)
s1.study()
s1.show()
class Student():
def __init__(self, name, age=0, score=0):
self.name = name
self.age = age
self.score = score
def study(self):
print(f"{self.name}在疯狂的学习中....")
def show(self):
print(f'姓名: {self.name} , 年龄: {self.age}, 成绩: {self.score}')
s1 = Student("李四", 20, 100)
s1.show()
s1.study()
s2 = Student("王五")
s2.show()
s3 = Student("赵六", 67)
s3.show()
s4 = Student("田七", score=67)
s4.show()
self的作用
from math import pi
class Student():
def __init__(self, name, age=0, score=0):
self.name = name
self.age = age
self.score = score
def study(v):
print(f"{v.name}在疯狂的学习中....")
def show(self):
print(f'姓名: {self.name} , 年龄: {self.age}, 成绩: {self.score}')
print(f'self 的地址是 {id(self)}')
s1 = Student("李四", 20, 100)
print(id(s1))
s1.show()
s2 = Student("王五")
print(id(s2))
s2.show()
s3 = Student("赵六", 67)
s3.show()
s4 = Student("田七", score=67)
s4.show()
import math
class Circle():
def __init__(self, radius=1):
self.radius = radius
def getPerimeter(self):
return 2*self.radius*math.pi
def getArea(self):
return math.pi*(self.radius**2)
c1 = Circle()
print(c1.radius)
c1.getPerimeter()
print(c1.getArea())
c1 = Circle(2)
c1.radius = 10
print(c1.radius)
print(c1.getArea())
面向对象三大特性
封装/继承/多态
import math
class Circle():
def __init__(self, radius=1):
## 将属性私有化, 只能在类内部使用
self.__radius = radius
def getPerimeter(self):
return 2*self.__radius*math.pi
def getArea(self):
return math.pi*(self.__radius**2)
# 如果说想访问私有 可以提供 getxx方法和setxxx方法
def getRadius(self):
return self.__radius
def setRadius(self, r):
self.__radius = r
c1 = Circle(2)
# print(c1.radius)
print(c1.getRadius())
c1.setRadius(10)
print(c1.getArea())
print(c1.getPerimeter())
实现我们自己的向量类
v1 = [1, 2, 3 ]
v2= [1, 2, 3 ]
v1 + v2 数学中和程序的结果是不一样的
class Vector():
def __init__(self, lst):
self.__value = lst[:]
def __str__(self):
return "({})".format(", ".join(str(e) for e in self.__value))
if __name__ == '__main__':
v1 = Vector([1, 2, 3, 5])
v2 = Vector([1, 2, 3, 5])