首先,通过之前学习的函数编写一个 人狗大战 的例子。
分析下这个需求,人 狗 大战 三个事情。
角色:人、狗
动作:狗咬人,人打狗
先创建人和狗两个角色:
def person(name, hp, aggr, sex): data = { 'name': name, 'hp': hp, 'aggr': aggr, 'sex': sex } return data def dog(name, hp, aggr, dog_type): data = { 'name': name, 'hp': hp, 'aggr': aggr, 'dog_type': dog_type } return data kk = person('kk', 100, 5, 'male') # 人的角色 gg = dog('gg', 100, 10, 'teddy') # 狗的角色
人创建完成,但是我们还有两个动作才能开始游戏,于是使用函数在写两个动作:
def person(name, hp, aggr, sex): data = { 'name': name, 'hp': hp, 'aggr': aggr, 'sex': sex } return data def dog(name, hp, aggr, dog_type): data = { 'name': name, 'hp': hp, 'aggr': aggr, 'dog_type': dog_type } return data kk = person('人', 100, 5, 'male') gg = dog('狗狗', 100, 10, 'teddy') def bite(g, p): p['hp'] -= g['aggr'] print('%s 被咬,掉了%s 的血。' %(p['name'], g['aggr'])) bite(gg, kk) def hit(p, g): g['hp'] -= p['aggr'] print('%s 被打,掉了%s 的血。' %(g['name'], p['aggr'])) hit(kk, gg)
上面的代码已经实现了我们最初设计的人狗大战,但是每个函数都是相互独立的,没有任何限制。也就是说,可以出现以下这种情况:
hit(gg, kk)
bite(kk, gg)
执行结果:
人 被打,掉了10 的血。
狗狗 被咬,掉了5 的血。
这样,人和狗正好相反了,应该是人打狗,狗咬人才对。因此必须要加上限制:
def person(name, hp, aggr, sex): data = { 'name': name, 'hp': hp, 'aggr': aggr, 'sex': sex } def hit(g): g['hp'] -= data['aggr'] print('%s 被打,掉了%s 的血。' % (g['name'], data['aggr'])) data['hit'] = hit return data def dog(name, hp, aggr, dog_type): data = { 'name': name, 'hp': hp, 'aggr': aggr, 'dog_type': dog_type } def bite(p): p['hp'] -= data['aggr'] print('%s 被咬,掉了%s 的血。' % (p['name'], data['aggr'])) data['bite'] = bite return data kk = person('人', 100, 5, 'male') gg = dog('狗狗', 100, 10, 'teddy') kk['hit'](gg) gg['bite'](kk)
这样,我们在代码层面就实现了限制,代码基本完美了。
回看我们上面的代码,创建的是角色函数,也就是通过角色函数,我们可以创建无数的人和狗大战。
人是人类、狗是狗类 通过这样的思想来进行编程就是面向对象的编程思想。从角色和大类入手,上帝视角
比如:
人类,是一个大类,这个大类里面有各种各样的属性,比如吃饭,睡觉,打豆豆这都是共性。
类中还有方法,方法就是一个过程,一个动作,做某件事。
比如:爬山、打篮球。这些都是动作,都应该是一个方法出现;
面向过程与面向对象
面向过程的程序设计核心是过程。过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线。
优点:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可;
缺点:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
应用场景:一般 bash 脚本都是面向过程思想写出来的,处理流程化事件。
面向对象的程序设计
面向对象的程序设计的核心是对象。
优点:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差,无法像面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间交互解决问题。
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的地方;
在python中面向对象的程序设计并不是全部。
面向对象编程可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率,基于面向对象的程序可以使它人更加容易理解你的代码逻辑。
虽然 面向对象很好用,但是它并没有比面向过程高级,对于不同的应用需求场景采用合适的编程思想才是最重要的。
def functionName(args): 函数体
class Data: pass
类有两种作用:属性引用和实例化
属性引用(类名.属性)
class Person: role = 'person' def walk(self): print('person is walking...')
上面代码中 role 是 Person的一个属性,walk 是 Person的方法。
print(Person.role) # 查看人的role属性 print(Person.walk) # 引用人的走路方法,注意,这里不是在调用
实例化:类名加括号就是实例化,会自动触发 __init__ 函数的运行,可以用它来为每个实例定制自己的特征
class Person: def __init__(self, name): self.name = name p = Person('hkey') # 实例化 Person print(p.name) # 执行结果: # hkey p = Person('hkey') 就是一个实例化的过程,实例化会自动执行 __init__()方法。
关于 self
self: 在实例化时自动将对象/实例本身传给__init__的第一个参数
class Person: def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex print(id(self)) p = Person('hkey', 20, 'male') # 实例化 Person print(id(p)) # 执行结果: # 2074449353472 # 2074449353472
通过上面的代码,我们可以查看到 self 和 对象 p 内存空间地址是一致的,印证了上面这句话。
如何查看一个类有哪些属性和方法,可以使用__dict__方法
class Person: def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex print(Person.__dict__) p = Person('hkey', 20, 'male') # 实例化 Person print(p.__dict__)
对象的相关知识
对象是关于类而实际存在的一个例子,即实例
对象/实例只有一种作用:属性引用
class Person: def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex p = Person('hkey', 20, 'male') # 这一步就是实例化一个对象p class Person: def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex p = Person('hkey', 20, 'male') # 实例化 Person print('name:', p.name) print('age:', p.age) print('sex:', p.sex) print('walk:', p.walk) # 在类中,方法也是对象。 # 执行结果: # name: hkey # age: 20 # sex: male # walk: <bound method Person.walk of <__main__.Person object at 0x0000024A4E819400>>
这里,我们把之前人狗大战的例子通过面向对象来重写下:
class Person(object): def __init__(self, name, hp, aggr, job): self.name = name self.hp = hp self.aggr = aggr self.job = job def hit(self, gg): gg.hp -= self.aggr print('