详解python中的面向对象(下)

类属性

类属性创建有点类似于在类中创建一个全局变量,这个变量类跟实例都可以调用它

# 定义一个模板
class Dog():
	# 定义一个类属性
    number_of_dogs = 0
    # 构造方法 - 添加实例属性,做其他初始化工作
    def __init__(self,name,height,power):
        self.name = name
        self.height = height
        # 设置血量为默认属性,值为10
        self.blood = 10
        self.power = power
        print '{}出生了!汪汪~'.format(self.name)

    # 添加一个方法bark
    def bark(self):
        print '我是{},身高{},攻击力{},血量{}'.format(self.name,self.height,self.power,self.blood)
    # 再添加一个attack()方法来执行攻击这个行为
    def attack(self,dog):
        dog.reduce_blood(self.power)
    def reduce_blood(self,reduce_value):
        if reduce_value > self.blood:
            self.blood = 0
        else:
            self.blood = self.blood-reduce_value
# 创建多个实例
d1 = Dog('大黄',0.7,3)
d2 = Dog('二黑',0.5,4)

# 通过类访问类属性
print Dog.number_of_dogs

# 通过实例访问类属性
print d1.number_of_dogs
print d2.number_of_dogs

唯一不同的是,在修改属性的值的时候,变量跟实例的区别是很大的

#省略部分代码
# 创建多个实例
d1 = Dog('大黄',0.7,3)
d2 = Dog('二黑',0.5,4)

# 类修改类属性
Dog.number_of_dogs = 8

# 通过类访问类属性
print Dog.number_of_dogs

# 实例修改类属性
d1.number_of_dogs = 10

# 通过实例访问类属性
print d1.number_of_dogs
print d2.number_of_dogs

来看一下运行结果:
在这里插入图片描述
总结:

  1. 整个类只有一份,所有实例都共享这一份。
  2. 可以通过类名或者实例名访问类属性,访问的都是同一个。
  3. 修改类属性需要通过类名。
  4. 因为通过实例名就会创建一个同名的实例变量。
  5. 当实例属性与类属性同名时,通过实例访问则实例属性优先。

类方法

类方法就是定义一个属于类的方法,定义格式与实例方法相似,不过要在方法上一行加 @classmethod装饰器来声明:

class Dog():
    dogs = []

    # 构造类方法,返回狗的数量
    @classmethod
    def number_of_dogs(cls):
        return len(cls.dogs)

    # 构造类方法,返回最高大的狗
    @classmethod
    def biggest(cls):
        max_height = 0
        for i in cls.dogs:
            if i.height > max_height:
                max_height = i.height
        return max_height

    # 构造方法 - 添加实例属性,做其他初始化工作
    def __init__(self,name,height,power):
        self.name = name
        self.height = height
        self.blood = 10
        self.power = power
        print '{}出生了!汪汪~'.format(self.name)
        Dog.dogs.append(self)

# 实例化类
d1 = Dog('大黄',70,10)
d2 = Dog('二黑',50,15)

# 调用类方法输出当前狗的数量
print '当前狗的数量为:{}只'.format(Dog.number_of_dogs())
# 调用类方法返回最高大的狗
print '当前狗狗最高身高为:{}公分'.format(Dog.biggest())

练习:

构造一个类方法,要求返回height大于50的狗的数量

class Dog():
    dogs = []
    big_dogs = []

    # 构造一个类方法,要求返回height大于50的狗的数量
    @classmethod
    def num_of_big_dog(cls):
        for i in Dog.dogs:
            if i.height > 50:
                Dog.big_dogs.append(i)
        print '身高大于50公分的狗有{}只'.format(len(Dog.big_dogs))
        
    # 构造方法 - 添加实例属性,做其他初始化工作
    def __init__(self,name,height,power):
        self.name = name
        self.height = height
        self.blood = 10
        self.power = power
        print '{}出生了!汪汪~'.format(self.name)
        Dog.dogs.append(self)

# 实例化多个对象
d1 = Dog('大黄',70,10)
d2 = Dog('二黑',50,15)
d3 = Dog('三傻',45,20)
d4 = Dog('四喜',62,13)
d5 = Dog('五白',30,20)
# 调用类方法输出height大于50的狗的数量
Dog.num_of_big_dog()

静态方法

之前我们学习了两个方法:实例方法类方法,实例方法的第一个参数是实例,只能调用实例属性,调用类属性则会创建一个与类属性同名的实例属性;类方法的第一个参数是类,只能调用类属性。

如果有一个方法它属于这个类,它既不需要使用实例属性,也不需要使用类属性,那么这个方法就是静态方法

class Dog:

    # 定义静态方法
    @staticmethod
    def info():
        print "Dog is human's best friend~"


# 实例化一个对象
d1 = Dog()

# 调用静态方法
Dog.info()
d1.info()

继承和super()

现在我们手上有3只狗,分别是警犬、牧羊犬、宠物犬,它们有各自的特性,但也有共同的属性,这时候就要用到类的继承了。
在这里插入图片描述
具体代码可以这样实现:

# 定义构造方法
class Dog(object):
    def __init__(self,name,power,height):
        self.name = name
        self.height = height
        self.power = power
        self.blood = 10
    # 构造bark方法
    def bark(self):
        print '我是{},汪汪~'.format(self.name)

# 定义一个SheepDog类,它是Dog的子类,继承Dog的构造方法
class SheepDog(Dog):
    # 定义构造方法,这里添加了一个特性num_of_sheeps
    def __init__(self,name,power,height,num_of_sheeps):
        # 用super()初始化构造父类,这里的super()函数与python3中有所不同!
        super(SheepDog,self).__init__(name,power,height)
        # 设置方法属性
        self.num_of_sheeps = num_of_sheeps

# 实例化一个对象
sd = SheepDog('牧羊犬',10,70,5)
# 调用父类方法
sd.bark()

现在我们做一个练习,把其余的两只狗也定义出来,只定义属性,先不定义它们的方法:

# 定义构造方法
class Dog(object):
    def __init__(self,name,power,height):
        self.name = name
        self.height = height
        self.power = power
        self.blood = 10
    # 构造bark方法
    def bark(self):
        print '我是{},汪汪~'.format(self.name)

# 定义牧羊犬
class SheepDog(Dog):
    # 定义构造方法,这里添加了一个特性num_of_sheeps
    def __init__(self,name,power,height,num_of_sheeps):
        # 用super()初始化构造父类,这里的super()函数与python3中有所不同!
        super(SheepDog,self).__init__(name,power,height)
        # 设置方法属性
        self.num_of_sheeps = num_of_sheeps

# 定义警犬
class PoliceDog(Dog):
    def __init__(self,name,power,height,ability):
        super(PoliceDog,self).__init__(name,power,height)
        self.ability = ability

# 定义宠物犬
class PetDog(Dog):
    def __init__(self,name,power,height,price):
        super(PetDog, self).__init__(name,power,height)
        self.price = price

# 牧羊犬
sd = SheepDog('牧羊犬',10,70,5)
print sd.blood
sd.bark()

# 警犬
pd = PoliceDog('警犬',20,65,7)
print pd.blood
pd.bark()

# 宠物犬
petd = PetDog('宠物犬',1,3,10)
print petd.blood
petd.bark()

给子类添加方法

我峨嵋你继承父类以后,可以使用它的构造方法以及它的类属性,但子类也会有自己的方法,就像上文中的三只狗,它们有一个自己的方法,这时候我们就需要给子类定义方法了。

在这里插入图片描述
添加方法的方式其实也很简单,就是在子类中定义一个新的方法罢了:

# 定义构造方法
class Dog(object):
    def __init__(self,name,power,height):
        self.name = name
        self.height = height
        self.power = power
        self.blood = 10
    # 构造bark方法
    def bark(self):
        print '我是{},汪汪~'.format(self.name)

# 定义一个SheepDog类,它是Dog的子类,继承Dog的构造方法
class SheepDog(Dog):
    # 定义构造方法,这里添加了一个特性num_of_sheeps
    def __init__(self,name,power,height,num_of_sheeps):
        # 用super()初始化构造父类,这里的super()函数与python3中有所不同!
        super(SheepDog,self).__init__(name,power,height)
        # 设置方法属性
        self.num_of_sheeps = num_of_sheeps

    def protect(self):
        print '我开始保护羊群了,汪汪!'

# 定义警犬
class PoliceDog(Dog):
    def __init__(self,name,power,height,ability):
        super(PoliceDog,self).__init__(name,power,height)
        self.ability = ability

    def detect(self):
        print '我开始侦擦了,汪汪!'

# 定义宠物犬
class PetDog(Dog):
    def __init__(self,name,power,height,price):
        super(PetDog, self).__init__(name,power,height)
        self.price = price

    def sing(self):
        print '我开始唱歌了,汪汪!'

# 牧羊犬
sd = SheepDog('牧羊犬',10,70,5)
sd.bark()
# 调用牧羊犬子方法
sd.protect()

# 警犬
pd = PoliceDog('警犬',20,65,7)
pd.bark()
# 调用警犬子方法
pd.detect()

# 宠物犬
petd = PetDog('宠物犬',1,3,10)
petd.bark()
# 调用宠物犬子方法
petd.sing()

重写父类方法

重写的格式就是在子类中定义一个与父类方法同名的子方法即可:

# 定义构造方法
class Dog(object):
    def __init__(self,name,power,height):
        self.name = name
        self.height = height
        self.power = power
        self.blood = 10
    # 构造bark方法
    def bark(self):
        print '我是{},汪汪~'.format(self.name)

# 定义一个SheepDog类,它是Dog的子类,继承Dog的构造方法
class SheepDog(Dog):
    # 定义构造方法,这里添加了一个特性num_of_sheeps
    def __init__(self,name,power,height,num_of_sheeps):
        # 用super()初始化构造父类,这里的super()函数与python3中有所不同!
        super(SheepDog,self).__init__(name,power,height)
        # 设置方法属性
        self.num_of_sheeps = num_of_sheeps

    def protect(self):
        print '我开始保护羊群了,汪汪!'

# 定义警犬
class PoliceDog(Dog):
    def __init__(self,name,power,height,ability):
        super(PoliceDog,self).__init__(name,power,height)
        self.ability = ability

    def detect(self):
        print '我开始侦擦了,汪汪!'

    def bark(self):
        print '我是{},这是我自己的方法,我重写了父类方法~'.format(self.name)

# 定义宠物犬
class PetDog(Dog):
    def __init__(self,name,power,height,price):
        super(PetDog, self).__init__(name,power,height)
        self.price = price

    def sing(self):
        print '我开始唱歌了,汪汪!'

# 警犬
pd = PoliceDog('警犬',20,65,7)
# 重写父类方法
pd.bark()
# 调用警犬子方法
pd.detect()

如果你想既重写了父类方法,又要调用原父类方法的话,我们可以用super()来实现这个功能

# 定义构造方法
class Dog(object):
    def __init__(self,name,power,height):
        self.name = name
        self.height = height
        self.power = power
        self.blood = 10
    # 构造bark方法
    def bark(self):
        print '我是{},汪汪~'.format(self.name)

# 定义一个SheepDog类,它是Dog的子类,继承Dog的构造方法
class SheepDog(Dog):
    # 定义构造方法,这里添加了一个特性num_of_sheeps
    def __init__(self,name,power,height,num_of_sheeps):
        # 用super()初始化构造父类,这里的super()函数与python3中有所不同!
        super(SheepDog,self).__init__(name,power,height)
        # 设置方法属性
        self.num_of_sheeps = num_of_sheeps

    def protect(self):
        print '我开始保护羊群了,汪汪!'

# 定义警犬
class PoliceDog(Dog):
    def __init__(self,name,power,height,ability):
        super(PoliceDog,self).__init__(name,power,height)
        self.ability = ability

    def detect(self):
        print '我开始侦擦了,汪汪!'
        # 调用父类方法
        super(PoliceDog,self).bark()
        
    def bark(self):
        print '我是{},这是我自己的方法,我重写了父类方法~'.format(self.name)

# 定义宠物犬
class PetDog(Dog):
    def __init__(self,name,power,height,price):
        super(PetDog, self).__init__(name,power,height)
        self.price = price

    def sing(self):
        print '我开始唱歌了,汪汪!'

# 警犬
pd = PoliceDog('警犬',20,65,7)
# 重写父类方法
pd.bark()

练习:

把剩下的两只狗的bark方法也进行重写

# 定义构造方法
class Dog(object):
    def __init__(self,name,power,height):
        self.name = name
        self.height = height
        self.power = power
        self.blood = 10
    # 构造bark方法
    def bark(self):
        print '我是{},汪汪~'.format(self.name)

# 定义牧羊犬
class SheepDog(Dog):
    # 定义构造方法,这里添加了一个特性num_of_sheeps
    def __init__(self,name,power,height,num_of_sheeps):
        # 用super()初始化构造父类,这里的super()函数与python3中有所不同!
        super(SheepDog,self).__init__(name,power,height)
        # 设置方法属性
        self.num_of_sheeps = num_of_sheeps

    def protect(self):
        print '我开始保护羊群了,汪汪!'

    def bark(self):
        print '我是{},这是我自己的方法,我重写了父类方法~'.format(self.name)
        super(SheepDog, self).bark()

# 定义警犬
class PoliceDog(Dog):
    def __init__(self,name,power,height,ability):
        super(PoliceDog,self).__init__(name,power,height)
        self.ability = ability

    def detect(self):
        print '我开始侦擦了,汪汪!'

    def bark(self):
        print '我是{},这是我自己的方法,我重写了父类方法~'.format(self.name)
        # 调用父类方法
        super(PoliceDog,self).bark()

# 定义宠物犬
class PetDog(Dog):
    def __init__(self,name,power,height,price):
        super(PetDog, self).__init__(name,power,height)
        self.price = price

    def sing(self):
        print '我开始唱歌了,汪汪!'

    def bark(self):
        print '我是{},这是我自己的方法,我重写了父类方法~'.format(self.name)
        super(PetDog, self).bark()

# 牧羊犬
sd = SheepDog('牧羊犬',10,70,5)
# 重写父类方法
sd.bark()

# 警犬
pd = PoliceDog('警犬',20,65,7)
# 重写父类方法
pd.bark()

# 宠物犬
petd = PetDog('宠物犬',1,3,10)
# 重写父类方法
petd.bark()

命名规则

类名:驼峰,如SheepDog、PoliceDog
方法名、变量名、参数、文件名:
		全小写,多个单词下划线连接
		如:get_pwd,start_attack
		如果是文件名,可以变成getpwd,为了引用起来方便
私有属性:在属性前加_,例如_weight,不过依然可以访问,只是一种命名规范
Python解释器御用:方法前加__,例如:__init__

模块、类和引入

现在我们创建一个新的文件game.py,引用我们上文写好的dog.py,像这样就可以了

import dog

pet_dog = dog.PetDog('小可爱',1,30,998)
pet_dog.bark()
print pet_dog.price

标准库中的类

我们结合标准库中的类来进行一个继承,在python中有一个Turtle类,是一个绘图海龟,现在我们来写一个属于自己的小海龟
在这里插入图片描述

这里物品们定义一个自己的类Myturtle,并且定义一个自己的方法big_circle:

import turtle

class MyTurtle(turtle.Turtle):
    def big_circle(self):
        self.color('red')
        self.circle(100)


s = turtle.Screen()
t = MyTurtle()
t.big_circle()
s.mainloop()

运行结果:
在这里插入图片描述
后续我会在另一篇文章中更新一下这个部分,本文中就先不做过多介绍了

其他实例作为属性

假设现在我们要给每条出厂的宠物狗配置一个狗窝,我们可以通过__init__方法添加参数来实现,也可以构造一个DogHost方法,把他实例化来充当宠物狗的属性:

# 定义构造方法
class Dog(object):
    def __init__(self,name,power,height):
        self.name = name
        self.height = height
        self.power = power
        self.blood = 10
        self._weight = 30

    # 构造bark方法
    def bark(self):
        print '我是{},汪汪~'.format(self.name)

# 定义一个SheepDog类,它是Dog的子类,继承Dog的构造方法
class SheepDog(Dog):
    # 定义构造方法,这里添加了一个特性num_of_sheeps
    def __init__(self,name,power,height,num_of_sheeps):
        # 用super()初始化构造父类,这里的super()函数与python3中有所不同!
        super(SheepDog,self).__init__(name,power,height)
        # 设置方法属性
        self.num_of_sheeps = num_of_sheeps

    def protect(self):
        print '我开始保护羊群了,汪汪!'

    def bark(self):
        print '我是{},这是我自己的方法,我重写了父类方法~'.format(self.name)
        super(SheepDog, self).bark()

# 定义警犬
class PoliceDog(Dog):
    def __init__(self,name,power,height,ability):
        super(PoliceDog,self).__init__(name,power,height)
        self.ability = ability

    def detect(self):
        print '我开始侦擦了,汪汪!'

    def bark(self):
        print '我是{},这是我自己的方法,我重写了父类方法~'.format(self.name)
        # 调用父类方法
        super(PoliceDog,self).bark()

# 定义宠物犬
class PetDog(Dog):
    def __init__(self,name,power,height,price,house):
        super(PetDog, self).__init__(name,power,height)
        self.price = price
        self.house = house

    def sing(self):
        print '我开始唱歌了,汪汪!'

    def bark(self):
        print '我是{},这是我自己的方法,我重写了父类方法~'.format(self.name)
        super(PetDog, self).bark()

# 定义狗窝
class DogHost:
    def __init__(self,num):
        self.num = num
        print '{}号狗窝已创建'.format(self.num)

定义好了之后,我们去另一个game.py脚本中引用它:

import dog

house = dog.DogHost('9527')
pet_dog = dog.PetDog('小可爱',1,20,998,house)

运行结果:
在这里插入图片描述

写一个简单的英雄联盟

  1. 参考王者荣耀或者你喜欢的其他游戏,创建相应的类和实例。
  2. 要求至少有3个类。
  3. 要求必须有继承关系。
  4. 要求必须有实例属性和类属性。
  5. 要求必须有实例方法和类方法。

我的答案:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/10/27 15:51
# @Author  : Shadow
# @Site    : 
# @File    : LOL.py
# @Software: PyCharm

# 定义一个Hero类作为父类
class Hero(object):
    # 定义类属性
    num_of_hero = []
    # 定义构造方法,并把生成的英雄追加到num_of_hero这个类属性中
    def __init__(self,name,blood,mana,power):
        self.name = name
        self.blood = blood
        self.mana = mana
        self.power =power
        print '英雄【{}】已生成!'.format(self.name)
        self.num_of_hero.append(self)
    # 定义attack方法执行攻击行为
    def attack(self,hero):
        hero.blood = hero.blood - self.power
        if hero.blood > 0:
            print '{}剩余血量为:{}'.format(hero.name,hero.blood)
        else:
            hero.blood = 0
            print '{}已被{}击杀!'.format(hero.name,self.name)
    # 定义info方法来输出英雄属性
    def info(self):
        print '名称:{}\n血量:{}\n法力值:{}\n攻击力:{}'.format(self.name,self.blood,self.mana,self.power)

# 定义Tank类作为Hero类的子类
class Tank(Hero):
    # 定义构造方法
    def __init__(self,name,blood,mana,power,armor):
        # 继承父类属性
        super(Tank, self).__init__(name,blood,mana,power)
        # 定义实例属性
        self.armor = armor
        self.blood = blood+armor*0.5
    # 定义info方法来输出英雄属性,这里继承了父类的info方法并进行了重写
    def info(self):
        super(Tank, self).info()
        print '护甲:{}'.format(self.armor)

# 定义Assassin类作为Hero类的子类
class Assassin(Hero):
    def __init__(self,name,blood,mana,power,critical_strike):
        super(Assassin, self).__init__(name,blood,mana,power)
        self.power = power+critical_strike*0.5
        self.critical_strike = critical_strike
    def info(self):
        super(Assassin, self).info()
        print '暴击率:{}%'.format(self.critical_strike)

# 定义Master类作为Hero类的子类
class Master(Hero):
    def __init__(self,name,blood,mana,power,magic):
        super(Master, self).__init__(name,blood,mana,power)
        self.magic = magic
        self.power = power*0.5+magic

    def info(self):
        super(Master, self).info()
        print '法强:{}'.format(self.magic)


# 实例化三个类
SaiEn = Tank('塞恩',1500,100,300,200)

Jie = Assassin('劫',1200,100,220,90)

Ali = Master('阿狸',1000,500,100,300)

if __name__ == '__main__':
    # 调用类属性并输出当前英雄总数
    print '当已生成{}个英雄!'.format(len(Hero.num_of_hero))
    # 调用attack方法进行10次攻击,直至英雄死亡为止
    for i in range(10):
        Jie.attack(SaiEn)
        if SaiEn.blood <= 0:
            break
        else:
            continue
    # 调用子类info方法,输出当前信息
    SaiEn.info()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值