Python - 面对对象(基础)
Python - 面对对象(基础)
一. 概述
面向过程:根据业务逻辑从上到下写垒代码
函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
面向对象:对函数进行分类和封装,让开发“更快更好更强...”
面向过程编程(Object Oriented Programming,OOP,面向对象程序设计) 最易被初学者接受,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,即:将之前实现的代码块复制到现需功能处。
二. 创建类和对象
面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用。
类就是一个模板,模板里可以包含多个函数,函数里实现一些功能
对象则是根据模板创建的实例,通过实例对象可以执行类中的函数

class是关键字,表示类
创建对象,类名称后加括号即可
类中的函数第一个参数必须是self(详细见:类的三大特性之封装)
类中定义的函数叫做 “方法”
# 创建类
class Foo:
def Bar(self):
print 'Bar'
def Hello(self, name):
print 'i am %s' %name
# 根据类Foo创建对象obj
obj = Foo()
obj.Bar() #执行Bar方法
obj.Hello('wupeiqi') #执行Hello方法
三. 面向对象三大特征
封装
第一步: 将内容封装到某处

self 是一个形式参数,
当执行 obj1 = Foo('wupeiqi', 18 ) 时,self 等于 obj1
当执行 obj2 = Foo('alex', 78 ) 时,self 等于 obj2
所以,内容其实被封装到了对象 obj1 和 obj2 中,每个对象中都有 name 和 age 属性,在内存里类似于下图来保存。
第二步: 从某处调用被封装的内容
调用被封装的内容时, 有两种情况:
- 通过对象直接调用
- 通过self间接调用
1、通过对象直接调用被封装的内容
上图展示了对象 obj1 和 obj2 在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
obj1 = Foo('wupeiqi', 18)
print obj1.name # 直接调用obj1对象的name属性
print obj1.age # 直接调用obj1对象的age属性
obj2 = Foo('alex', 73)
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('wupeiqi', 18)
obj1.detail() # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18
obj2 = Foo('alex', 73)
obj2.detail() # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 alex ; self.age 是 78
综上所述,对于面对对象的封装来说,其实就是使用构造方法将内容封装到对象中, 然后通过对象直接或self间接获取被封装的内容.
练习:游戏人生程序
1、创建三个游戏人物,分别是:
苍井井,女,18,初始战斗力1000
东尼木木,男,20,初始战斗力1800
波多多,女,19,初始战斗力2500
2、游戏场景,分别:
草丛战斗,消耗200战斗力
自我修炼,增长100战斗力
多人游戏,消耗500战斗力
# -*- coding:utf-8 -*-
# ##################### 定义实现功能的类 #####################
class Person:
def __init__(self, na, gen, age, fig):
self.name = na
self.gender = gen
self.age = age
self.fight =fig
def grassland(self):
"""注释:草丛战斗,消耗200战斗力"""
self.fight = self.fight - 200
def practice(self):
"""注释:自我修炼,增长100战斗力"""
self.fight = self.fight + 200
def incest(self):
"""注释:多人游戏,消耗500战斗力"""
self.fight = self.fight - 500
def detail(self):
"""注释:当前对象的详细情况"""
temp = "姓名:%s ; 性别:%s ; 年龄:%s ; 战斗力:%s" % (self.name, self.gender, self.age, self.fight)
print temp
# ##################### 开始游戏 #####################
cang = Person('苍井井', '女', 18, 1000) # 创建苍井井角色
dong = Person('东尼木木', '男', 20, 1800) # 创建东尼木木角色
bo = Person('波多多', '女', 19, 2500) # 创建波多多角色
cang.incest() #苍井空参加一次多人游戏
dong.practice()#东尼木木自我修炼了一次
bo.grassland() #波多多参加一次草丛战斗
#输出当前所有人的详细情况
cang.detail()
dong.detail()
bo.detail()
cang.incest() #苍井空又参加一次多人游戏
dong.incest() #东尼木木也参加了一个多人游戏
bo.practice() #波多多自我修炼了一次
#输出当前所有人的详细情况
cang.detail()
dong.detail()
bo.detail()
继承
继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。
例如:
猫可以:喵喵叫、吃、喝、拉、撒
狗可以:汪汪叫、吃、喝、拉、撒
如果我们要分别为猫和狗创建一个类,那么就需要为 猫 和 狗 实现他们所有的功能,如下所示:
伪代码
class 动物:
def 吃(self):
# do something
def 喝(self):
# do something
def 拉(self):
# do something
def 撒(self):
# do something
# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类
class 猫(动物):
def 喵喵叫(self):
print '喵喵叫'
# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类
class 狗(动物):
def 汪汪叫(self):
print '喵喵叫'
上述代码不难看出,吃、喝、拉、撒是猫和狗都具有的功能,而我们却分别的猫和狗的类中编写了两次。如果使用 继承 的思想,如下实现:
动物:吃、喝、拉、撒
猫:喵喵叫(猫继承动物的功能)
狗:汪汪叫(狗继承动物的功能)
代码实例
class Animal:
def eat(self):
print "%s 吃 " %self.name
def drink(self):
print "%s 喝 " %self.name
def shit(self):
print "%s 拉 " %self.name
def pee(self):
print "%s 撒 " %self.name
class Cat(Animal):
def __init__(self, name):
self.name = name
self.breed = '猫'
def cry(self):
print '喵喵叫'
class Dog(Animal):
def __init__(self, name):
self.name = name
self.breed = '狗'
def cry(self):
print '汪汪叫'
# ######### 执行 #########
class Animal:
def eat(self):
print "%s 吃 " %self.name
def drink(self):
print "%s 喝 " %self.name
def shit(self):
print "%s 拉 " %self.name
def pee(self):
print "%s 撒 " %self.name
class Cat(Animal):
def __init__(self, name):
self.name = name
self.breed = '猫'
def cry(self):
print '喵喵叫'
class Dog(Animal):
def __init__(self, name):
self.name = name
self.breed = '狗'
def cry(self):
print '汪汪叫'
# ######### 执行 #########
c1 = Cat('小白家的小黑猫')
c1.eat()
c2 = Cat('小黑的小白猫')
c2.drink()
d1 = Dog('胖子家的小瘦狗')
d1.eat()
所以,对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。
注:除了子类和父类的称谓,你可能看到过 派生类 和 基类 ,他们与子类和父类只是叫法不同而已。

学习了继承的写法之后,我们用代码来是上述阿猫阿狗的功能:
class Animal:
def eat(self):
print "%s 吃 " %self.name
def drink(self):
print "%s 喝 " %self.name
def shit(self):
print "%s 拉 " %self.name
def pee(self):
print "%s 撒 " %self.name
class Cat(Animal):
def __init__(self, name):
self.name = name
self.breed = '猫'
def cry(self):
print '喵喵叫'
class Dog(Animal):
def __init__(self, name):
self.name = name
self.breed = '狗'
def cry(self):
print '汪汪叫'
# ######### 执行 #########
c1 = Cat('小白家的小黑猫')
c1.eat()
c2 = Cat('小黑的小白猫')
c2.drink()
d1 = Dog('胖子家的小瘦狗')
d1.eat()
那么问题又来了,多继承呢?
是否可以继承多个类
如果继承的多个类每个类中都定了相同的函数,那么那一个会被使用呢?
1、Python的类可以继承多个类,Java和C#中则只能继承一个类
2、Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先

- 当类是经典类时,多继承情况下,会按照深度优先方式查找
- 当类是新式类时,多继承情况下,会按照广度优先方式查找
经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果 当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。


经典类多继承
class D:
def bar(self):
print 'D.bar'
class C(D):
def bar(self):
print 'C.bar'
class B(D):
def bar(self):
print 'B.bar'
class A(B, C):
def bar(self):
print 'A.bar'
a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> D --> C
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()
新式类多继承
class D(object):
def bar(self):
print 'D.bar'
class C(D):
def bar(self):
print 'C.bar'
class B(D):
def bar(self):
print 'B.bar'
class A(B, C):
def bar(self):
print 'A.bar'
a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> C --> D
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()
经典类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
新式类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
注意:在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
多态
Pyhon不支持Java和C#这一类强类型语言中多态的写法,但是原生多态,其Python崇尚“鸭子类型”。
Python伪代码实现Jave或C#的多态
class F1:
pass
class S1(F1):
def show(self):
print 'S1.show'
class S2(F1):
def show(self):
print 'S2.show'
# 由于在Java或C#中定义函数参数时,必须指定参数的类型
# 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类
# 而实际传入的参数是:S1对象和S2对象
def Func(F1 obj):
"""Func函数需要接收一个F1类型或者F1子类的类型"""
print obj.show()
s1_obj = S1()
Func(s1_obj) # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show
s2_obj = S2()
Func(s2_obj) # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show
Python "鸭子类型"
class F1:
pass
class S1(F1):
def show(self):
print 'S1.show'
class S2(F1):
def show(self):
print 'S2.show'
def Func(obj):
print obj.show()
s1_obj = S1()
Func(s1_obj)
s2_obj = S2()
Func(s2_obj)
Python - 面对对象(基础)的更多相关文章
- python 面对对象基础
目录 面向对象基础 面向对象编程(抽象) 类与对象 给对象定制独有的特征 对象的属性查找顺序 类与对象的绑定方法 类与数据类型 对象的高度整合 面向对象基础 面向对象编程(抽象) 回顾一下 面向过程编 ...
- Python - 面对对象(进阶)
目录 Python - 面对对象(进阶) 类的成员 一. 字段 二. 方法 三. 属性 类的修饰符 类的特殊成员 Python - 面对对象(进阶) 类的成员 一. 字段 字段包括:普通字段和静态字段 ...
- 16、python面对对象之类和继承
前言:本文主要介绍python面对对象中的类和继承,包括类方法.静态方法.只读属性.继承等. 一.类方法 1.类方法定义 使用装饰器@classmethod装饰,且第一个参数必须是当前类对象,该参数名 ...
- Python - 面对对象(其他相关,异常处理,反射,单例模式,等..)
目录 Python - 面对对象(其他相关,异常处理,反射,等..) 一.isinstance(obj, cls) 二.issubclass(sub, super) 三.异常处理 1. 异常处理 2. ...
- 小学生绞尽脑汁也学不会的python(面对对象-----类与类之间的关系)
小学生绞尽脑汁也学不会的python(面对对象-----类与类之间的关系 1. 依赖关系. 最轻的一种关系 在方法中引入另一个类的对象 class Elephant: def __init__(sel ...
- 小学生绞尽脑汁也学不会的python(面对对象-----成员)
小学生绞尽脑汁也学不会的python(面对对象-----成员) 成员 class Person: def __init__(self, name, num, gender, birthday): # ...
- 15、python面对对象之类和对象
前言:本文主要介绍python面对对象中的类和对象,包括类和对象的概念.类的定义.类属性.实例属性及实例方法等. 一.类和对象的概念 问题:什么是类?什么是实例对象? 类:是一类事物的抽象概念,不是真 ...
- python面对对象编程----2:__init__
面对对象编程估计我们最早接触到的就是__init__了,也就是实例的初始化处理过程: 1:来看看最基础的__init__ class Card(object): #抽象类Card,并不用于实例化 de ...
- python面对对象编程------4:类基本的特殊方法__str__,__repr__,__hash__,__new__,__bool__,6大比较方法
一:string相关:__str__(),__repr__(),__format__() str方法更面向人类阅读,print()使用的就是str repr方法更面对python,目标是希望生成一个放 ...
随机推荐
- 直接使用FileSystem以标准输出格式显示hadoop文件系统中的文件
package com.yoyosys.cebbank.bdap.service.mr; import java.io.IOException; import java.io.InputStream; ...
- Django day28 频率组件,解析器
一:频率组件: 1.频率是什么? 节流,访问控制 2. (1)内置的访问频率控制类SimpleRateThrottle (2)写一个类,继承SimpleRateThrottle class MyThr ...
- Vue 柱状图
echarts.js作为国内的IT三巨头之一的百度的推出一款相对较为成功的开源项目,总体上来说有这样的一些优点 1.echarts.js容易使用 echarts.js的官方文档比较详细,而且官网中提供 ...
- SQL数据库还原的二种方式和区别
1.数据库还原 在SQL中,直接选择选择“还原数据库”:选中.bak 文件即可. 2.生成脚本 新建同样的DB名字,在SQL打开脚本,执行脚本语言.数据库里面就会自动填充内容.
- SQL Server之纵表与横表互转
1,纵表转横表 纵表结构 Table_A: 转换后的结构: 纵表转横表的SQL示例: SELECT Name , SUM(CASE WHEN Course = N'语文' THEN G ...
- 9.Hierarchy Editor
Hierarchy Editor(层次编辑器) 用于定义3D图层的结构,向Ventuz渲染引擎发出“命令”,并指定命令的发生顺序.通常,每个层次节点都会导致对GPU的一个或多个调用,例如设置材质或渲染 ...
- java DDD 基于maven开发的探讨
对于DDD我目前的理解是 1.除了数据的基本操作,也可以把一些公用的方法或者类迁移到Infrastructrue 2.对于domain层可以声明各个聚合根的操作接口:例:IXXXRepository ...
- Java引用jar的优化
一般java的类文件开头都是各种引用: 如 上图的引用可以写成
- body全屏css/网页全屏设置/全屏样式
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- fcc 响应式框架Bootstrap 练习2
text-primary 属性值使标题直接变成了红色,text-center使标题直接居中 <h2 class="text-primary text-center"> ...