引子

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

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. Python3基础 list dict set 均为unhashable type

             Python : 3.7.3          OS : Ubuntu 18.04.2 LTS         IDE : pycharm-community-2019.1.3    ...

  2. Laya的版本管理

    参考: Laya项目发布详解 发布时,勾选开启版本管理 点击上图“是否开启版本管理”右边的+号. 可以选择加入版本管理,或者排除版本管理的文件夹. 比如我要排除bin/test这个文件夹下的文件,不使 ...

  3. [图片问答]LODOP字体设置方法

    字体设置方法:一.整体设置(针对文本项),打印初始化后.增加打印项之前调用本函数LODOP.SET_PRINT_STYLE("FontSize",11);二.单个打印项(针对文本项 ...

  4. [LeetCode] 293. Flip Game 翻转游戏

    You are playing the following Flip Game with your friend: Given a string that contains only these tw ...

  5. 高级UI-滤镜和颜色通道

    滤镜在图片处理里面有很多的运用,尤其是相机使用了大量的滤镜,通过对颜色通道的调和,可以呈现出各种各样的效果 对图像进行一定的过滤加工处理,使用Paint设置滤镜效果 很多高级UI使用时候需要关闭硬件加 ...

  6. 考前最后的感叹:CSP2019 Bless All! & AFO

    因为没有退路,所以勇往直前. ----来自高二老年选手小蒟蒻XY Upd:凉凉了,你们都稳了...我看来是超不过准考证号了qwq[大哭] Upd:来自联考txdy的神仙gcz Upd:久远的回忆:会不 ...

  7. MySQL执行计划值type,强烈推荐

    表结构: create table user ( id int primary key, name varchar(), sex varchar(), index(name) )engine=inno ...

  8. idea关闭sonarLint自动扫描

    手动运行SonarLint 停止SonarLint自动检测代码之后,可以使用Ctrl+Shift+S手动运行SonarLint检查代码

  9. 第1/7Beta冲刺

    1.团队成员 成员姓名 成员学号 秦裕航 201731062432(组长) 刘东 201731062227 张旭 201731062129 王伟 201731062214 2.SCRU部分 2.1各成 ...

  10. React路由传参的三种方式

    方式 一:          通过params         1.路由表中                     <Route path=' /sort/:id '   component= ...