前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >python3--类的组合,初始类的继承

python3--类的组合,初始类的继承

作者头像
py3study
发布于 2018-08-02 08:35:06
发布于 2018-08-02 08:35:06
77500
代码可运行
举报
文章被收录于专栏:python3python3
运行总次数:0
代码可运行

面向对象的组合用法

软件重用的重要方式除了继承之外还有另外一种方式,即:组合

组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合

例1

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 人狗大战
class Person:
    def __init__(self, name, sex, hp, ad):  # 对象属性
        self.name = name
        self.sex = sex
        self.hp = hp
        self.ad = ad
        self.money = 0  # 设置初始钱为0

    def attack(self, d):  # 人的攻击方法
        d.hp -= self.ad
        print('{}攻击了{},{}掉了{}点血'.format(self.name, d.name, d.name, self.ad))

    def pay(self):  # 充值方法
        money = int(input('请输入你要充值的金额:').strip())
        self.money += money
        print('你的余额是:{}'.format(self.money))

    def wear(self, weapon):
        # 武器
        if self.money >= weapon.price:
            # 武器类的对象作为人类对象的一个属性
            self.weapon = weapon  # 组合 给人装备了武器
            self.money -= weapon.price
            print('购买成功,你已经顺利装备了{}'.format(weapon.name))
        else:
            print('余额不足,请充值!')

    def attack_with_weapon(self, dog):
        if 'weapon' in self.__dict__:
            self.weapon.skill(dog)
        else:
            print('请先装备武器')


class Dog:
    def __init__(self, name, kind, hp, ad):  # 名字,品种,血量,攻击
        self.name = name
        self.kind = kind
        self.hp = hp
        self.ad = ad

    def bite(self, p):
        p.hp -= self.ad
        print('{}咬了{}一口,{}掉了{}点血'.format(self.name, p.name, p.name, self.ad))


class Weapon:
    def __init__(self, name, price, ad, level):  # 名字,价格,攻击,品级
        self.name = name
        self.price = price
        self.level = level
        self.ad = ad * self.level

    def skill(self, dog):
        dog.hp -= self.ad
        print('{}受到了{}的伤害,{}掉了{}点血'.format(dog.name, self.name, dog.name, self.ad))


# 武器 是人的一个属性
# 武器也是一个类
# 攻击力 价格 名字 品级
# 技能:方法
# 武器 装备

# 实例化 人,狗,武器
sam = Person('奥特曼', '不详', 1, 1)
teddy = Dog('笨笨', 'teddy', 50, 20)
futou = Weapon('斧头', 1000, 100, 1)

lst = ['攻击', '充值', '装备武器', '使用武器攻击']
while True:
    for index, value in enumerate(lst, 1):
        print(index, value)
    num = int(input('请选择操作序号 >>>'))
    if num == 1:
        sam.attack(teddy)
    elif num == 2:
        sam.pay()
    elif num == 3:
        print('装备前余额{}'.format(sam.money))
        sam.wear(futou)
        print('装备后余额{}'.format(sam.money))
    elif num == 4:
        sam.attack_with_weapon(teddy)
    else:
        print('无效的序号')

执行效果

圆环是由两个圆组成的,圆环的面积是外面圆的面积减去内部圆的面积。圆环的周长是内部圆的周长加上外部圆的周长

这个时候,我们就首先实现一个圆形类,计算一个圆的周长和面积,然后在"环形类"中组合圆形的实例作为自己的属性来用

例2,上面类组合的例子不是很懂?来看个简单的吧

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from math import pi  # 导入模块math中的pi
class Circle:  # 圆形面积类
    # 关联:圆形的面积公式不会变
    def __init__(self, r):
        self.r = r

    def cal_area(self):  # 计算圆面积
        return pi * self.r ** 2

    def cal_perimter(self):  # 计算圆周长
        return pi * self.r * 2

class Ring:  # 圆环
    def __init__(self, out_r, in_r):  # out_r外圆半径,in_r内圆半径

        # 组合(即和上面圆形求面积的类关联起来) 实例化一个类Circle,把外圆半径传进去
        self.out_circle = Circle(out_r)

        # 组合(即和上面圆形求面积的类关联起来) 实例化一个类Circle,把内圆半径传进去
        self.in_circle = Circle(in_r)

    def area(self):
        # 圆环面积 = 外圆面积-内圆面积
        return self.out_circle.cal_area() - self.in_circle.cal_area()

    def perimter(self):
        # 圆环周长 = 外圆周长+内圆周长
        return self.out_circle.cal_perimter() + self.in_circle.cal_perimter()

# 实例化Ring类,并传入大圆半径和小圆半径
st = Ring(6, 2)

# 打印圆环面积
print('圆环的面积为:{}'.format(st.area()))

# 打印圆环周长
print('圆环的周长为:{}'.format(st.perimter()))

执行顺序

执行结果

圆环的面积为:100.53096491487338

圆环的周长为:50.26548245743669

例3,还是类组合!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class BirthDate:  # 生日类
    def __init__(self, year, month, day):
        self.year = year  # 年
        self.month = month  # 月
        self.day = day  # 日

class Couse:  # 课程类
    def __init__(self, name, price, period):
        self.name = name  # 课程名
        self.price = price  # 课程价格
        self.period = period  # 课程班级()

class Teacher:  # 老师类
    def __init__(self, name, gender, birth, course):
        self.name = name  # 姓名
        self.gender = gender  # 性别
        self.birth = birth  # 生日
        self.course = course  # 课程

    def teach(self):
        print('teaching')

# 实例化 组合:一个类的对象作为另一个类对象的属性
pl = Teacher('sam', 'boy',BirthDate('2008', '12', '12'),Couse('Python3', '20000', '11期'))
print(pl.birth.year, pl.birth.month, pl.birth.day)
print(pl.course.name, pl.course.price, pl.course.period)

执行结果

2008 12 12

Python3 20000 11期

类组合什么时候需要用到?

当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好

初始面向对象小结

面向对象的思想

    不关注程序执行的过程

    关心的是一个程序中的角色以及角色与角色之间的关系

在python中一切皆对象

实例化的过程

创建一个对象

__init__给对象添加一些属性,对象默认的名字self

将self所指向的内存空间返回给实例化它的地方

使用这个对象可以找到两个东西

1 对象所在的内存空间中存储的属性

2 类对象指针所指类中的所有方法和静态属性

对象找名字的时候:先找自己内存空间中的,再找类的

对象没有权利修改类中的静态变量和方法,如果修改了,那么就存在自己的对象空间里面

类名:实例化对象,调用静态属性,执行方法

交互:对象可以作为参数传递给类中的方法

组合:对象可以作为一个对象的属性

组合和交互在python中随处可见

例1

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class B:pass

class A:
    def func(self, aaa):
        print(aaa)

a = A()
b = B()
a.func(b)  # b = B()

执行结果,打印类(B)的内存地址

例2

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class B:pass
class A:
    def func(self, aaa): # aaa = '666'
        self.aaa = aaa

a = A() # 实例化
b = B() # 实例化
a.func('666') #执行func并传入一个字符串'666'
print(a.aaa.startswith('6')) #判断'666'是否以'6'开头

执行结果

True

面向对象的三大特性

继承

多态

封装

什么是继承

继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类

python中类的继承分为:单继承和多继承

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class ParentClass1:  # 定义父类
    pass

class ParentClass2:  # 定义父类
    pass

class SubClass1(ParentClass1):  # 单继承,基类是ParentClass1,派生类是SubClass
    pass

class SubClass2(ParentClass1, ParentClass2):  # python支持多继承,用逗号分隔开多个继承的类
    pass

# 查看继承
# __base__只查看从左到右继承的第一个子类, __bases__则是查看所有继承的父类
print(SubClass1.__bases__)
print(SubClass2.__bases__)

# 提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类
print(ParentClass1.__bases__)
print(ParentClass2.__bases__)

执行结果

(

(

继承与抽象(先抽象再继承)

抽象即抽取类似或者说比较像的部分

抽象分为两个层次

  1. 将奥巴马和梅西这两对象比较像的部分抽取成类
  2. 将人,猪,狗这三个类比较像的部分抽取成父类

抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)

继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构

抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类

例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"""
示例 1
    : 猫喵喵,吃喝拉撒
    : 狗汪汪,吃喝拉撒
    如果要分别为猫和狗创建一个类,那么就需要为猫狗定义它们的动作
    代码如下
"""
class :
    def 喵喵(self):
        return '喵喵'
    def (self):
        return '吃'
    def (self):
        return '喝'
    def (self):
        return '拉'
    def (self):
        return '撒'

class :
    def 汪汪(self):
        return '汪汪'
    def (self):
        return '吃'
    def (self):
        return '喝'
    def (self):
        return '拉'
    def (self):
        return '撒'

# 上述代码不难看出,吃喝拉撒是猫和狗都具有的属性,而却分别为猫狗都定义了一次,代码重复性太高

如果用继承的思想,代码应该这样写,如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class 动物:
    def (self):
        return '吃'
    def (self):
        return '喝'
    def (self):
        return '拉'
    def (self):
        return '撒'

# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类
class (动物):
    def 喵喵(self):
        return '喵喵'

# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类
class (动物):
    def 汪汪(self):
        return '汪汪'

上面代码只是一个继承的思想(严格来说,最好不要用中文)实际代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Animal:
    def eat(self):
        print('{}吃'.format(self.name))
    def drink(self):
        print('{}喝'.format(self.name))
    def shit(self):
        print('{}拉'.format(self.name))
    def pee(self):
        print('{}撒'.format(self.name))

class Cat(Animal):
    def __init__(self, name):
        self.name = name
        self.breed = '猫'

    def cry(self):
        print('喵喵')

class Dog(Animal):
    def __init__(self, name):
        self.name = name
        self.breed = '狗'

    def cry(self):
        print('{}汪汪'.format(self.name))

cl = Cat('小白家的小黑猫')
cl.eat()
c2 = Cat('小黑的小白猫')
c2.drink()
d1 = Dog('胖子家的二哈')
d1.eat()
d2 = Dog('瘦子家的藏獒')
d2.cry()

执行结果

小白家的小黑猫吃

小黑的小白猫喝

胖子家的二哈吃

瘦子家的藏獒汪汪

在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同,不可能从头开始写一个类B,这就用到了类的继承的概念

通过继承的方式新建类B,让B继承A,B会'遗传'A的所有属性(数据属性和函数属性)

例1

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Animal:
    '''
    人和狗都是动物,所以创造一个Animal基类
    '''
    def __init__(self, name, aggressivity, life_value):
        self.name = name  # 人和狗都有自己的昵称
        self.aggressivity = aggressivity  # 人和狗都有自己的攻击力
        self.life_value = life_value  # 人和狗都有自己的生命值

    def eat(self):
        print('{} is eating'.format(self.name))

class Dog(Animal):
    pass

class Person(Animal):
    pass

egg = Person('egon', 10, 1000)
ha2 = Dog('二愣子', 50, 1000)
egg.eat()
ha2.eat()

执行结果

egon is eating

二愣子 is eating

提示:用已经有的类建立一个新的类,这样就重用了已经有的软件中的一部分设置,大大降低了编程工作量,这就是常说的软件重用,不仅可以重用自己的类,也可以继承别人的,比如标准库,来定制新的数据类型,这样就大大缩短了软件开发周期,对大型软件开发来说,意义重大

派生

当然子类也可以添加自己新的属性或者在自己这里重新定义这种属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Animal:
    '''
    人和狗都是动物,所以创造一个Animal基类
    '''
    def __init__(self, name, aggressivity, life_value):
        self.name = name  # 人和狗都有自己的昵称;
        self.aggressivity = aggressivity  # 人和狗都有自己的攻击力;
        self.life_value = life_value  # 人和狗都有自己的生命值;

    def eat(self):
        print('%s is eating' % self.name)

class Dog(Animal):
    '''
    狗类,继承Animal类
    '''
    def bite(self, people):
        '''
        派生:狗有咬人的技能
        :param people:
        '''
        people.life_value -= self.aggressivity

class Person(Animal):
    '''
    人类,继承Animal
    '''
    def attack(self, dog):
        '''
        派生:人有攻击的技能
        :param dog:
        '''
        dog.life_value -= self.aggressivity

egg = Person('egon',10,1000)
ha2 = Dog('二愣子',50,1000)
print(ha2.life_value)
egg.attack(ha2)
print(ha2.life_value)

执行结果

1000

990

像ha2.life_value之类的属性引用,会先从实例中找life_value然后去类中找,然后再去父类中找,直到最顶级的父类

经典面试题

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Parent:
    def __init__(self):
        self.func()
    def func(self):
        print('in parent func')

class Son(Parent):
    def func(self):
        print('in son func')

class Att(Son):
    def func(self):  #如果子类中的方法与父类中的方法名字相同,执行自己的(子类的)
        print('in att func')

s = Att()

执行结果

in att func

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018/04/12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
vue项目刷新当前页面的方法
尝试了几种刷新页面的方法, 比如 : 1、浏览器直接刷新(会出现短暂的白页面现象) 2、设置一个空白页面,需要刷新的时候跳转到空页面再从空页面跳回来 (些许麻烦) 3、使用 provide /inject (目前觉得最实用,主讲此方法)
全栈程序员站长
2022/09/27
1.4K0
Vue刷新当前页面
这个姿势是利用了 history 中前进和后退的功能,传入 0 刷新当前页面。但是有一个问题就是页面整个刷新过程中会白屏,严重影响用户的体验感,效果不好。
青梅煮码
2023/03/13
2.9K0
js刷新当前页面的5种方式
bForceGet, 可选参数, 默认为 false,从客户端缓存里取当前页。true, 则以 GET 方式,从服务端取最新的页面, 相当于客户端点击 F5(“刷新”)
全栈程序员站长
2022/09/07
10.4K0
Vue刷新页面的三种方式[通俗易懂]
我们在写项目的时候,经常会遇到,用户执行完某个动作,改变了某些状态,需要重新刷新页面,以此来重新渲染页面。如:用户登录成功、增加、删除、更新等。
全栈程序员站长
2022/11/02
9240
vue关于页面刷新的几个方式[通俗易懂]
在需要页面刷新的地方写上:this.$router.push(’/emptyPage’),跳转到一个空白页。在emptyPage.vue里beforeRouteEnter 钩子里控制页面跳转,从而达到刷新的效果
全栈程序员站长
2022/11/03
2.4K0
vue关于页面刷新的几个方式[通俗易懂]
Vue无感刷新当前页面
Dawnzhang
2023/10/16
4840
Vue刷新当前页面(成功)
但是这个办法会让整个当前页面刷新,相当于F5。如果项目中只是做一个编辑修改操作,希望修改后数据立马改变,但是使用此方法会出现一个短暂的空白页(如下图),用户效果特别不好,不推荐。
全栈程序员站长
2022/11/03
3.6K0
Vue刷新当前页面(成功)
Vue.js项目刷新当前路由(页面)的方法与实践
越来越多的前端项目使用MVVM框架Vue.js进行架构开发,充分利用了Vue.js的数据驱动、双向数据绑定、组件化开发以及其优秀的社区生态(官网+第三方扩展支持)等能力。Vue.js在提升性能方面着重的使用了组件复用能力,极大的优化了DOM更新的速度,提升了用户体验。
胡哥有话说
2019/07/25
9.4K0
vue项目如何刷新当前页面
1.场景 在处理列表时,常常有删除一条数据或者新增数据之后需要重新刷新当前页面的需求。 2.遇到的问题
lyudev
2022/08/04
1.5K0
vue页面刷新方法_vue返回上一页怎么实时刷新
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
全栈程序员站长
2022/11/07
3.5K0
vue项目如何刷新当前页面「建议收藏」
想必大家在刨坑vue的时候也遇到过下面情形:比如在删除或者增加一条记录的时候希望当前页面可以重新刷新或者如下面这种:
全栈程序员站长
2022/09/18
2K0
vue项目如何刷新当前页面「建议收藏」
vue页面刷新_vue强制重置组件
经常使用vue的小伙伴看到这个应该很熟悉吧,我们经常用它来实现前进后退,但别忘了它还可以实现自身页面刷新
全栈程序员站长
2022/11/03
2.4K0
vue页面刷新_vue强制重置组件
Ant-design-vue+vue-i18n实现前端国际化
项目基于Vue-cli3.x进行开发,使用了ant-design-vue框架,然后需要做国际化。此时做国际化需要考虑两方面的国际化,一是ant-design-vue内部组件的国际化,二是国际化我们的业务显示,业务显示我们选用vue-i18n进行国际化。
青年码农
2020/10/13
3.8K0
Ant-design-vue+vue-i18n实现前端国际化
vue 项目中英文切换
最近vue项目需要中英文切换,查了资料,发现大部分都是采用 vue-i18n,但是写的比较简单,大部分都是全局引入语言包,遇到的几个问题
tianyawhl
2020/10/28
3.1K0
vue 项目中英文切换
vue刷新页面的方法_vue局部刷新页面
在项目中经常遇到一个问题,例如新增完表单数据和需要重新刷新页面。类似的业务还有很多。这时我们可以考虑的方式如下
全栈程序员站长
2022/11/03
2.8K0
Vue如何刷新当前页面?我是这样做的,你呢?
以上问题都是日常开发中遇到的,所以有此记录,如果你有不同的解决方案,欢迎留言告诉哦,不同的思路带来不同的碰撞,哈哈。
执行上下文
2022/07/26
6650
Vue最佳实践和实用技巧(下)
attrs还可与listeners搭配使用,listeners包含了父组件传递的事件(不包含.native修饰器),它可以通过v-on="
用户6256742
2024/05/18
2030
Vue 开发必须知道的 36 个技巧【近1W字】
https://juejin.im/user/5ad2d884518825556e5e882a
秋风的笔记
2020/10/27
1K0
Vue权限路由思考
登录成功后同时要做很多事情,具体业务具体对待。后台管理系统 登录成功后会请求当前用户的菜单权限接口,来获取用户的可访问的路由(动态路由),获取成功后,Vue Router 是不能直接使用的,必须得解析成符合Vue Router 可识别的格式 . ❞
山月
2021/04/07
3930
Vue权限路由思考
[Vue 牛刀小试]:第十四章 - 编程式导航与实现组件与 Vue Router 之间的解耦
  在上一章的学习中,通过举例说明,我们了解了 Vue Router 中命名路由、命名视图的使用方法,以及如何通过 query 查询参数传参,或者是采用 param 传参的方式实现路由间的参数传递。通过学习我们可以发现,在实现路由间的参数传递时,我们将 Vue Router 与我们的组件强耦合在一起,这无疑是不合适的,那么本章我们就来学习,如何实现组件和 Vue Router 之间的解耦。
程序员宇说
2019/07/31
1.1K0
相关推荐
vue项目刷新当前页面的方法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档