引子

假设我们要开发一个关于飞机大战的游戏,那么游戏的里面就会有两个角色,分别是属于玩家操控的战机和敌方的战机,并且两个战机都有不同的技能或攻击方式,现在我们用自己目前所学的去写出下面的这些代码:

def Fighter(name,atk,hp,speed):
fighter = {
'name' : name, #战机的名字
'atk' : atk, #战机的攻击力
'hp' : hp, #战机的血量
'speed' : speed #战机的速度
}
return fighter def EnemyFighter(name,atk,hp,speed,kind):
enemyfighter = {
'name' : name, #敌机的名字
'atk' : atk, #敌机的攻击力
'hp' : hp, #敌机的血量
'speed' : speed, #敌机的速度
'kind' : kind #敌机的种类
}
return enemyfighter

我们在写好了这些属性之后就可以生成敌方的战机和玩家的战机:

playerFighter1 = Fighter('Player1',200,1500,300)
playerFighter2 = Fighter('Player2',150,2000,280)
Boss1 = EnemyFighter('lazerBoss',1000,7000,50,'Boss')
Monster1 = EnemyFighter('Monster1',100,200,150,'Monster')
print(playerFighter1) #{'name': 'Player1', 'atk': 200, 'hp': 1500, 'speed': 300}
print(playerFighter2) #{'name': 'Player2', 'atk': 150, 'hp': 2000, 'speed': 280}
print(Boss1) #{'name': 'lazerBoss', 'atk': 1000, 'hp': 7000, 'speed': 50, 'kind': 'Boss'}
print(Monster1) #{'name': 'Monster1', 'atk': 100, 'hp': 200, 'speed': 150, 'kind': 'Monster'}

那么在生成好了这些对象之后,我们还缺的是它们不同的攻击方法,因此我们要在它们的方法中再添加一个方法再去调用

def Fighter(name,atk,hp,speed): #定义一个战机的属性
fighter = {
'name' : name, #战机的名字
'atk' : atk, #战机的攻击力
'hp' : hp, #战机的血量
'speed' : speed, #战机的速度
}
def playerAttack(enemyfighter): #玩家攻击函数
enemyfighter['hp'] -= fighter['atk']
print('{0}被{1}攻击了,损失了{2}HP!'.format(enemyfighter['name'],fighter['name'],fighter['atk']))
fighter['playerAttack'] = playerAttack
return fighter def EnemyFighter(name,atk,hp,speed,kind):
enemyfighter = {
'name' : name, #敌机的名字
'atk' : atk, #敌机的攻击力
'hp' : hp, #敌机的血量
'speed' : speed, #敌机的速度
'kind' : kind #敌机的种类
}
def enemyFighterAttack(fighter): #敌机攻击函数
fighter['hp'] -= enemyfighter['atk']
print('{0}被{1}攻击了,损失了{2}HP!'.format(fighter['name'],enemyfighter['name'],enemyfighter['atk']))
enemyfighter['enemyFighterAttack'] = enemyFighterAttack
return enemyfighter playerFighter1 = Fighter('Player1',200,1500,300)
playerFighter2 = Fighter('Player2',150,2000,280)
Boss1 = EnemyFighter('lazerBoss',1000,7000,50,'Boss')
Monster1 = EnemyFighter('Monster1',100,200,150,'Monster')
print(playerFighter1) #{'name': 'Player1', 'atk': 200, 'hp': 1500, 'speed': 300, 'playerAttack':
                  <function Fighter.<locals>.playerAttack at 0x0000000002138A60>}
print(playerFighter2) #{'name': 'Player2', 'atk': 150, 'hp': 2000, 'speed': 280, 'playerAttack':
                  <function Fighter.<locals>.playerAttack at 0x0000000002138D08>}
print(Boss1) #{'name': 'lazerBoss', 'atk': 1000, 'hp': 7000, 'speed': 50, 'kind': 'Boss', 'enemyFighterAttack':
                  <function EnemyFighter.<locals>.enemyFighterAttack at 0x0000000002138D90>}
print(Monster1) #{'name': 'Monster1', 'atk': 100, 'hp': 200, 'speed': 150, 'kind': 'Monster', 'enemyFighterAttack':
                  <function EnemyFighter.<locals>.enemyFighterAttack at 0x0000000002138E18>}

现在调用这两个功能代码:

print(playerFighter1)                         #{'name': 'Player1', 'atk': 200, 'hp': 1500, 'speed': 300, 'playerAttack': 
                              <function Fighter.<locals>.playerAttack at 0x0000000002138A60>}
Boss1['enemyFighterAttack'](playerFighter1) #Player1被lazerBoss攻击了,损失了1000HP!
print(playerFighter1) #{'name': 'Player1', 'atk': 200, 'hp': 500, 'speed': 300, 'playerAttack':
                              <function Fighter.<locals>.playerAttack at 0x00000000027A8A60>} print(Monster1) #{'name': 'Monster1', 'atk': 100, 'hp': 200, 'speed': 150, 'kind': 'Monster', 'enemyFighterAttack':
                              <function EnemyFighter.<locals>.enemyFighterAttack at 0x0000000002138E18>}
playerFighter2['playerAttack'](Monster1) #Monster1被Player2攻击了,损失了150HP!
print(Monster1) #{'name': 'Monster1', 'atk': 100, 'hp': 50, 'speed': 150, 'kind': 'Monster', 'enemyFighterAttack':
                              <function EnemyFighter.<locals>.enemyFighterAttack at 0x00000000027A8E18>}

像上面Fighter和EnemyFighter函数都是定义了一类事物,直到我们调用了函数,赋值了之后才真的有了一个实实在在的事物

面向对象、面向过程、面向函数

面向对象:把整个任务封装成一个大的类,在这个类里面详细地分解执行每个步骤,只需要执行类就可以完成任务。优点解决了程序的扩展性,对某一个对象单独修改,会立刻反映到整个体系中,比如对一个游戏中的一个人物参数的特征和技能修改都很容易。缺点可控性差无法像面向过程的程序设计流水线式,可以很精准得预测问题的处理流程和结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预知结果。因此经常我们可以看到一个新角色出现在遊戲時会出现影响游戏平衡和玩家游戏体验的场景。

面向过程:就是程序按照步骤一个一个地去执行。优点在于极大得降低了写程序的复杂难度,只要顺着要执行的步骤堆叠代码就好;

缺点是一套流水线或者流程就是解决一个问题,代码牵一发而动全身。

面向函数:就是将编程分成很多种情况,把每一种情况写成一种函数,然后要按步骤执行函数完成。

class Cat:
def __init__(self,*args):
self.name = args[0]
self.height = args[1]
self.weight = args[2]
self.type = args[3]

实例化一个对象再去查看它的内部属性(用法:对象名.属性名)

cat1 = Cat('jackey',20,45,'cat')            #实例化一个对象
print(cat1.name) #jackey
print(cat1.height) #
print(cat1.weight) #
print(cat1.type) #cat

也可以用实例化名.__dict__[属性名]的方法查看属性

print(cat1.__dict__['name'])                #jackey
print(cat1.__dict__['height']) #
print(cat1.__dict__['weight']) #
print(cat1.__dict__['type']) #cat

利用self.__dict__查看属性

class Cat:
def __init__(self,*args):
print(self.__dict__) #{} 当我们还没加入属性时,self没有内容
self.name = args[0]
self.height = args[1]
self.weight = args[2]
self.type = args[3]
print(self.__dict__) #{'name': 'jackey', 'height': 20, 'weight': 45, 'type': 'cat'} cat1 = Cat('jackey',20,45,'cat') #实例化一个对象
print(cat1.__dict__) #{'name': 'jackey', 'height': 20, 'weight': 45, 'type': 'cat'}

__init__()中的参数self可以理解为一个字典,即一个对象,它把后面的属性name、height、weight等都存在了这个self'字典'中,再把每一个属性和它对应的值都交给我们实例化的对象

class Cat:
def __init__(self,*args):
self.name = args[0]
self.height = args[1]
self.weight = args[2]
self.type = args[3]
print(self,id(self)) #<__main__.Cat object at 0x00000000025B1DD8> 39525848
cat1 = Cat('jackey',20,45,'cat') #实例化一个对象
print(cat1,id(cat1)) #<__main__.Cat object at 0x00000000025B1DD8> 39525848

可以从执行结果看出来它们共用的是同一个内存地址

查看一个类函数内部的静态属性(用法:类名.静态属性)和调用方法(用法:对象名.方法名()):

class Cat:
Rose = 'cat' #静态属性
def __init__(self,*args):
self.name = args[0]
self.height = args[1]
self.weight = args[2]
self.type = args[3]
def Eat(self):
print('吃点什么...')
cat1 = Cat('jackey',20,45,'cat') #实例化一个对象
print(Cat.Rose) #cat
cat1.Eat() #吃点什么...

类名.__dict__

实例化名.__dict__它存储的是self里面的属性

而类名.__dict__它存储的是这个类中的所有名字

print(Cat.__dict__)         #{'__module__': '__main__', '__init__': <function Cat.__init__ at 0x0000000002588950>, 'Eat': <function Cat.Eat at 0x0000000002588A60>, '__dict__': <attribute '__dict__' of 'Cat' objects>, '__weakref__': <attribute '__weakref__' of 'Cat' objects>, '__doc__': None}
print(cat1.__dict__) #'name': 'jackey', 'height': 20, 'weight': 45, 'type': 'cat'}

执行流程说明:

class Cat:
def __init__(self,*args):
self.name = args[0]
self.height = args[1]
self.weight = args[2]
self.type = args[3]
def Eat(self):
print('{}正在吃小鱼干...'.format(self.name)) cat1 = Cat('jackey',20,45,'cat') #实例化一个对象
#这两种函数调用方法都是可以的
#Cat.Eat(cat1) #jackey正在吃小鱼干...
cat1.Eat() #jackey正在吃小鱼干...

1.首先先定义了一个Cat类

2.Cat() 即调用类名加括号和内容相当于执行了__init__()函数

3.在Cat()中的所有参数都会被*args以元祖的形式接收,而self是函数内部自己创建的一个类似于字典对象的一个东西

4.之后再执行赋值过程self.name = args[0]...执导所有属性赋值完成

5.这个时候self参数会把这个所有属性都传值给外面我们实例化出的对象cat1,注意:如果self里面是没有值的话,外面的实例化对象是没有内容的

6.最后通过类.函数名(实例化对象名字)或实例化对象名字.函数名()来调用函数,执行Eat方法,再打印结果

修改属性

print(cat1.name)                 #jackey
cat1.name = 'Maria'
print(cat1.name)      #Maria
print(cat1.__dict__)      #{'name': 'Maria', 'height': 20, 'weight': 45, 'type': 'cat'}

也可以用__dict__来修改

print(cat1.name)                    #jackey
cat1.__dict__['name'] = 'Maria'
print(cat1.name) #Maria
print(cat1.__dict__) #{'name': 'Maria', 'height': 20, 'weight': 45, 'type': 'cat'}

增加一个新的属性

class Cat:
def __init__(self,*args):
self.name = args[0]
self.height = args[1]
self.weight = args[2]
self.type = args[3]
def Eat(self):
print('{}正在吃小鱼干...'.format(self.name)) cat1 = Cat('jackey',20,45,'cat') #实例化一个对象
print(cat1.__dict__) #{'name': 'jackey', 'height': 20, 'weight': 45, 'type': 'cat'}
cat1.age = 5
print(cat1.age) #
print(cat1.__dict__) #{'name': 'jackey', 'height': 20, 'weight': 45, 'type': 'cat', 'age': 5}

其他的类属性

类名.__name__  # 类的名字(字符串)
类名.__doc__   # 类的文档字符串
类名.__base__  # 类的第一个父类(在讲继承时会讲)
类名.__bases__  # 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__  # 类的字典属性
类名.__module__ # 类定义所在的模块
类名.__class__ # 实例对应的类(仅新式类中)

总结

什么是类? 具有相同特征的一类事物(人、狗、猫、飞机等)

什么是对象? 具体的某个事物(303房间的人、那支笔等)

什么是实例化? 类->对象的过程

python中一切皆为对象,类型的本质就是类

什么时候会用到面向对象呢?比如非常明显地处理一类事物,这类事物都具有相似的属性和功能;当有几个函数需要反复传入相同的参数时,就可以考虑面向对象;这些参数都是对象的属性

练习

用面向对象的方式表示一个圆的周长和面积,并求出它的周长和面积

from math import pi as P
class Circle:
def __init__(self,r):
self.r = r
def S(self):
return P*self.r**2
def L(self):
return 2*P*self.r c1 = Circle(1)
print(c1.S()) #3.141592653589793
print(c1.L()) #6.283185307179586

Python学习日记(二十二) 初识面向对象的更多相关文章

  1. Python学习日记(四十二) Mysql数据库篇 十

    前言 当我们自己去写SQL代码的时候有时候会因为不熟练会导致效率低,再之后要进行许多的优化,并且操作也较为繁琐.因此ORM框架就能够解决上面的问题,它能根据自身的一些规则来帮助开发者去生成SQL代码. ...

  2. Python学习日记(三十二) hmac检验客户端的合法性和socketsever模块

    Hmac模块 其实这个模块类似hashlib模块,它能将一些重要的信息通过算法加密成密文,让信息更具有安全性. 关于hmac加密算法的了解:它的全名是哈希运算消息认证码(Hash-based Mess ...

  3. Egret入门学习日记 --- 第十二篇(书中 5.1节 内容)

    第十二篇(书中 5.1节 内容) 昨天把 第4章完成了. 今天来看第5章. 接下来是 5.1节 的内容. 总结一下 5.1节 的重点: 1.如何制作一个公用按钮皮肤. 跟着做: 重点1:如何制作一个公 ...

  4. Python学习日记(一)——初识Python

    Python的优势 互联网公司广泛使用python来做的事一般有:自动化运维.自动化测试.大数据分析.爬虫.Web等. Python与其他语言 C和Python.Java.C#: C  语言:代码编译 ...

  5. Python学习日记(三十六) Mysql数据库篇 四

    MySQL作业分析 五张表的增删改查: 完成所有表的关系创建 创建教师表(tid为这张表教师ID,tname为这张表教师的姓名) create table teacherTable( tid int ...

  6. python学习笔记(二十)初识面向对象

    面向对象的编程的主要思想是把构成问题的各个事物分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述一个事物在解决问题的过程中经历的步骤和行为.对象作为程序的基本单位,将程序和数据封装其中, ...

  7. Python学习日记(三十四) Mysql数据库篇 二

    外键(Foreign Key) 如果今天有一张表上面有很多职务的信息 我们可以通过使用外键的方式去将两张表产生关联 这样的好处能够节省空间,比方说你今天的职务名称很长,在一张表中就要重复的去写这个职务 ...

  8. Python学习札记(三十二) 面向对象编程 Object Oriented Program 3

    参考:访问限制 NOTE 1.eg. #!/usr/bin/env python3 class Student(object): """docstring for Stu ...

  9. Python学习【第十二篇】模块(2)

    序列化 1.什么是python序列化? 把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling 序列化就是将python的数据类型转换成字符串 反序列化就是将字符串转换成 ...

  10. Python学习(四十二)—— Djago-model进阶

    一.QuerySet 可切片 使用Python 的切片语法来限制查询集记录的数目 .它等同于SQL 的LIMIT 和OFFSET 子句. Entry.objects.all()[:5] # (LIMI ...

随机推荐

  1. typescript - 1.环境搭建

    安装 1.安装node.js 安装typescript npm install -g typescript 3.编译 tsc helloworld.ts Typescript开发工具Vscode自动编 ...

  2. C#程序打包安装部署之添加注册表项(转)

    今天为大家整理了一些怎样去做程序安装包的具体文档,这些文档并不能确保每个人在做安装包的时候都能正确去生成和运行,但是这些文档的指导作用对于需要的朋友来说还是很有必要的,在实际产品的安装部署过程中可能有 ...

  3. node.js使用markdown-it批量转md内容为html

    代码如下: var fs = require('fs'); var MarkdownIt = require('markdown-it'), md = new MarkdownIt(); /* pag ...

  4. 【err】tensorflow.python.framework.errors_impl.OutOfRangeError: RandomShuffleQueue

    problem Traceback (most recent call last): File , in _do_call return fn(*args) File , in _run_fn opt ...

  5. [LeetCode] 556. Next Greater Element III 下一个较大的元素 III

    Given a positive 32-bit integer n, you need to find the smallest 32-bit integer which has exactly th ...

  6. VisualStudio开发UE4工程设置

    转自:http://wangjie.rocks/2016/06/24/ue4-vs-setup/ 推荐插件 Visual Assist X C++ 代码高亮 UnrealVS Extension UE ...

  7. SQL查询优化思维即SQL子查询

    一. 什么叫子查询 定义及分类 子查询又称内部查询,而包含子查询的语句称之外部查询(又称主查询).所有的子查询可以分为两类,即相关子查询和非相关子查询. 非相关子查询是独立于外部查询的子查询,子查询总 ...

  8. 问题一:使用AndroidDriver而非原来的AppiumDriver的原因

    AppiumDriver升级到2.0.0版本引发的问题--Cannot instantiate the type AppiumDriver 1. 问题描述和起因在使用Appium1.7.0及其以下版本 ...

  9. jquery json对象转换

    jquery json对象转换 <pre>//json数组转json串var arr = [1,2,3, { a : 1 } ];JSON.stringify( arr ); //json ...

  10. PostgreSql11.5源码安装

    参考:https://yq.aliyun.com/articles/675687/ 1.先下载postgresql11.5的源码包:https://www.postgresql.org/ftp/sou ...