面向过程与面向对象
程序包括:
- 数据:数据类型,数据结构
- 处理过程:算法
两种程序设计思想
面向过程:
- 面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度(C语言)
- 以操作(函数)为主体,然后把对象作为参数传给主体。
#处理学生信息
# 1.用字典存储姓名和分数
student1 = {'name': '小贝', 'score': 98}
student2 = {'name': '闻闻', 'score': 93}
# 2.定义打印分数的函数
def print_score(student):
print('姓名:%s,分数:%d' % (student['name'], student['score']))
# 3.调用打印分数的函数
print_score(student1)
print_score(student2)
面向对象:
- 把计算机程序视为一组对象的集合,而每一个对象都可以接受其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递(python语言)
- 以数据为主体,然后把特征或者动作分别作为对象的属性和方法。
# 1.定义学生类
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print('姓名:%s,分数:%d' % (self.name, self.score))
# 2.实例化学生类
student1 = Student('小贝', 98)
student2 = Student('闻闻', 93)
# 3.调用实例的方法
student1.print_score()
student2.print_score()
区别:
类
- 描述相似对象的共性,对象是类的实例。
- 包括:数据(属性)、操作(方法)
类定义
语法:
calss<类名>:
<方法定义>
类对象
- 类对象支持两种操作:属性引用和实例化
- 属性引用使用和python中所有的属性引用一样的标准语法:obj.name
- 类对象创建以后,类命名空间中所有的命名都是有效属性名。
- 在类中,定义的变量就是一个属性,定义的一个函数就是一个方法。
class Human: #定义一个类,类名首字母要大写
# 这是两个属性,相当于平时的变量
arms = 2
legs = 2
hair = '各种颜色的头发'
#这是类的方法,相当于我们定义的函数,但是函数第一个参数必须是self
def walk(self):
print('直立行走')
def speak(self):
print('说着各式各样的语言')
# 类的实例化
human = Human()
print(human.arms)
# 输出:2
print(human.legs)
# 输出:2
print(human.hair)
# 输出:各种颜色的头发
human.walk()
# 输出:直立行走
human.speak()
# 输出:说着各式各样的语言
类定义中self的含义
- self 表示创建的实例本身
''' 错误示例 '''
class Human:
arms = 2
legs = 2
hair = '各种颜色的头发'
def walk(self):
print('直立行走')
def speak(self):
print('说着各式各样的语言')
def intro(self):
# 类的方法里访问类的属性
print('人类有%d条胳膊%d条腿' % (arms, legs))
# 类的实例化
human = Human()
'''
我们在类的方法里直接访问类的属性是不行的。
访问类的属性要先实例化,然后通过 实例名.属性 进行访问,
类的方法内访问类的属性时,类的实例还没被创建。这时候我们就用到了self
'''
human.intro()
# 报错:NameError: name 'arms' is not defined on line 14
''' 修改后的代码 '''
class Human:
arms = 2
legs = 2
hair = '各种颜色的头发'
def walk(self):
print('直立行走')
def speak(self):
print('说着各式各样的语言')
def intro(self):
# 类的方法里访问类的变量
print('人类有%d条胳膊%d条腿' % (self.arms, self.legs)) #这里加入了self
'''
当执行 human.intro() 这行代码时,Python 会将 human 作为第一个参数偷偷传递给
self,这样我们就不再需要传入第一个参数,并能通过 self 访问类的属性和方法了。
'''
# 类的实例化
human = Human()
human.intro()
# 输出:人类有2条胳膊2条腿
总结:
- 创建类方法时,第一个参数一定要设置为self,但是调用的时候要忽略他。
- 在类内使用定义的方法(函数)或者是属性(变量)时,要用self.方法()或者是self.属性。
初始化方法def __init__(self):
PS:init左右是两个下划线!!!
- 使用初始化方法后,当函数实例化之后,该方法会自动被执行。
- 当实例化完成之后,初始化方法会自动执行,这样我们就完成了自定义的属性初始值设置。然后我们可以通过 实例名.属性名 在类外访问或 self.属性名 在类的方法中访问了。
class Human:
# 除了进行固定的初始值设置,初始化方法 可以接收其他参数,进行自定义的属性初始值设置
def __init__(self, name, arms, legs, hair):
# self.不能丢
self.name = name
self.arms = arms
self.legs = legs
self.hair = hair
def walk(self):
print('直立行走')
def speak(self):
print('说着各式各样的语言')
def intro(self):
print('我叫{},我有{}'.format(self.name, self.hair))
#类实例化,同时给类传入四个参数给__init__()函数
xiaobei = Human('小贝', 2, 2, '粉红色的头发')
print(xiaobei.name)
# 输出:小贝
xiaobei.intro()
# 输出:我叫小贝,我有粉红色的头发
描述类 __str__(self):
PS:同样,str左右是两个下划线!!!
PS2:__str__(self):
方法最后要用return返回,不可以用print。
class Human:
arms = 2
legs = 2
hair = '各种颜色的头发'
def __str__(self):
return '人类有%d条胳膊%d条腿' % (self.arms, self.legs)
def walk(self):
print('直立行走')
def speak(self):
print('说着各式各样的语言')
human = Human()
#实例化之后,我们直接print(实例名),结果为 __str__() 方法的返回值
print(human)
# 输出:人类有2条胳膊2条腿
类继承
class 子类(父类):
class Human:
arms = 2
legs = 2
hair = '各种颜色的头发'
def walk(self):
print('直立行走')
def speak(self):
print('说着各式各样的语言')
#Chinese类中什么都没有,但是他继承了Human类,就可以直接调用Human类中的属性和方法
class Chinese(Human):
pass
xiaobei = Chinese()
print(xiaobei.arms)
# 输出:2
xiaobei.walk()
# 输出:直立行走
多层继承
语法:
class B (A): #B继承了A类,B就可以调用A类中的属性和方法
pass
class C (B): #C继承了B类,C就可以调用B的东西,也就可以调用A的东西
pass
# 师傅
class Master:
book = '九阴真经'
def kungfu(self):
print('九阴白骨爪')
# 徒弟
class Apprentice(Master):
book2 = "九阳神功" #徒弟可以新增一个属性
def kungfu(self): #徒弟对师傅类中的kungfu方法进行重写,调用徒弟之后结果就会改变
print("九阴白骨爪改进版")
def kungfu2(self): #徒弟还可以新增一个方法
print("金刚不坏之躯")
xiaobei = Apprentice()
print(xiaobei.book)
#输出:九阴真经
print(xiaobei.book2)
#输出:九阳神功
xiaobei.kungfu()
#输出:九阴白骨爪改进版
xiaobei.kungfu2()
#输出:金刚不坏之躯
多重继承
语法:
class D (A,B,C):
class Chinese:
hair = '黑头发'
skin = '黄皮肤'
def speak_chinese(self):
print('说汉语')
class American:
hair = '金头发'
skin = '白皮肤'
def speak_english(self):
print('说英语')
#横向继承,调用属性或者方法时,从左到右依次寻找,如果第一个没有,就从第二个寻找;
#如果都没有,就会报错
#新建和重写跟多层继承一样
class ABC(Chinese, American):
pass
abc = ABC()
print(abc.hair)
# 输出:黑头发
print(abc.skin)
# 输出:黄皮肤
abc.speak_chinese()
# 输出:说汉语
abc.speak_english()
# 输出:说英语
小游戏(天下第一武道大会)
from random import randint, random
class Player:
def __init__(self, name):
self.name = name
self.health = 100
def attack(self, target): # 攻击方法:攻击者 attack target
print(self.name + '发起攻击') # self.name 为攻击者
damage = randint(10, 20) #随机伤害
baoji = randint(30,60) #随机暴击
target.defend(damage,baoji, self.name)
def defend(self, damage,baoji, attack_name): # 防御方法:以下的 self.health 和 self.name 均为被攻击者target
# 补全 defend() 方法
pi = randint(1, 100)
if 20 < pi <= 80:
self.health = self.health - damage
print("{0}受到来自{3}的{1}点伤害,血量剩余{2}".format(self.name, damage, self.health, attack_name))
if self.health <= 0:
print("{}被击败".format(self.name))
elif pi > 80: #20%几率产生暴击
self.health = self.health - baoji
print("{3}发动致命一击!{0}受到{1}点伤害,血量剩余{2}".format(self.name, baoji, self.health, attack_name))
if self.health <= 0:
print("{}被击败".format(self.name))
else: #20%几率产生防御
print("{}防御成功".format(self.name))
kakarotto = Player('孙悟空')
piccolo = Player('比克大魔王')
# 使用循环轮番攻击,当有人被击败后停止循环
i = 1
while True:
if kakarotto.health > 0:
kakarotto.attack(piccolo)
print("第{}回合结束".format(i).center(20, '-'))
i += 1
else:
break
if piccolo.health > 0:
piccolo.attack(kakarotto)
print("第{}回合结束".format(i).center(20, '-'))
i += 1
else:
break
其中attck() 方法和 defend() 方法中的self.name不一样
孙悟空发起攻击
比克大魔王防御成功
-------第1回合结束-------
比克大魔王发起攻击
孙悟空受到来自比克大魔王的12点伤害,血量剩余88
-------第2回合结束-------
孙悟空发起攻击
比克大魔王受到来自孙悟空的12点伤害,血量剩余88
-------第3回合结束-------
比克大魔王发起攻击
比克大魔王发动致命一击!孙悟空受到55点伤害,血量剩余33
-------第4回合结束-------
孙悟空发起攻击
比克大魔王受到来自孙悟空的14点伤害,血量剩余74
-------第5回合结束-------
比克大魔王发起攻击
孙悟空受到来自比克大魔王的16点伤害,血量剩余17
-------第6回合结束-------
孙悟空发起攻击
孙悟空发动致命一击!比克大魔王受到59点伤害,血量剩余15
-------第7回合结束-------
比克大魔王发起攻击
孙悟空受到来自比克大魔王的16点伤害,血量剩余1
-------第8回合结束-------
孙悟空发起攻击
比克大魔王受到来自孙悟空的15点伤害,血量剩余0
比克大魔王被击败
-------第9回合结束-------