多态

关注公众号“轻松学编程”了解更多。

1、多态使用

一种事物的多种体现形式,举例:动物有很多种
注意: 继承是多态的前提
函数重写就是多态的体现形式

演示:重写Animal类

第一步:先定义猫类和老鼠类,继承自object,在其中书写构造方法和eat方法

第二步: 抽取Animal父类,定义属性和eat方法,猫类与老鼠类继承即可

第三步: 定义人类,在其中分别定义喂猫和喂老鼠的方法

第四步:使用多态,将多个喂的方法提取一个。

# 测试类
from cat import Cat
from mouse import Mouse
from person import Person
'''
多态: 一种事物的多种状态
需求:人可以喂任何一种动物
'''
#创建猫和老鼠的对象
tom = Cat("tom")
jerry = Mouse("jerry") #调用各自的方法
tom.eat()
jerry.eat() #定义了一个有name属性和eat方法的Animal类,让所有的动物类都继承自Animal. #定义一个人类,可以喂猫和老鼠吃东西
per = Person()
#per.feedCat(tom)
#per.feedMouse(jerry) #思考:人要喂100种动物,难道要写100个feed方法吗?
#前提:tom和jerry都继承自动物
per.feedAnimal(tom)
per.feedAnimal(jerry)
输出:
tom吃
jerry吃
给你食物
tom吃
给你食物
jerry吃
#animal.py文件中的动物类
class Animal(object):
def __init__(self, name):
self.name = name
def eat(self):
print(self.name + "吃")
#cat.py文件中的猫类
class Cat(Animal):
def __init__(self, name):
#self.name = name
super(Cat,self).__init__(name)
#mouse.py中的老鼠类
class Mouse(Animal):
def __init__(self, name):
#self.name = name
super(Mouse,self).__init__(name)
#person.py中的人类
class Person(object):
def feedAnimal(self, ani):
print("给你食物")
ani.eat()

2、对象属性与类属性

对象属性和类属性的区别:

a.定义的位置不同,类属性是直接在类中的属性,对象属性是在定义在构造方法中的属性;

b.对象属性使用对象访问,类属性使用类名访问;

c.在内存中出现的时机不同[类属性随着类的加载而出现,对象属性随着对象的创建而出现];

d.优先级不同,对象属性的优先级高于类属性。

class Person(object):
#1.定义位置
#类属性:直接定义在类中的属性
name = "person"
def __init__(self, name):
#对象属性:定义在构造方法中的属性
self.name = name
#2.访问方式
print(Person.name)
per = Person("tom")
#对象属性的优先级高于类属性
print(per.name)
#动态的给对象添加对象属性
per.age = 18
#只针对当前对象生效,对于类创建的其他对象没有作用
print(Person.name)
per2 = Person("lilei")
#print(per2.age) #没有age属性
#删除对象中的name属性,再调用会使用到同名的类属性
del per.name
print(per.name) #注意事项:不要将对象属性与类属性重名,因为对象属性会屏蔽掉类属性,但是当删除对象属性之后,再使用就能使用到类属性了.
输出:
person
tom
person
person

3、动态添加属性和方法

正常情况下,我们定义了一个class,创建一个class的实例后,我们可以给该实例绑定任何的的属性和方法,这就是动态语言的灵活性。

python语言的特点:灵活。

这里说的动态添加属性和方法主要指的是关于__slots__函数的使用

from types import MethodType

#定义一个空类
'''
class Person():
pass
'''
class Person(object):
__slots__ = ("name","age","speak","hobby")
pass
# 动态添加属性[体现了动态语言的特点:灵活性]
per = Person()
per.name = "tom"
print(per.name) #动态添加方法
def say(self):
print("my name is "+ self.name)
per.speak = say
per.speak(per)
#这样实现不好,所以引入MethodType
def hobby(self):
print("my hobby is running")
per.hobby = MethodType(hobby,per)
per.hobby() 输出:
tom
my name is tom
my hobby is running

但是,给一个实例绑定的方法对另外一个实例是不起作用的。

为了给所有的实例都绑定方法,可以通过给class绑定方法

#动态添加方法
def say(self,name):
self.name = name
print("my name is "+ self.name)
Person.speak = say
per2 = Person()
per2.speak('hh')
输出:
my name is hh

给class绑定方法后,所有的实例均可调用。

4、slots

通常情况下,上面的say方法可以直接定义在class中,但动态绑定允许我们在程序在运行的过程中动态的给class添加功能,这在静态语言中很难实现。

如果我们想限制实例的属性怎么办?

比如,只允许给Person实例添加name,age属性,为了达到限制的目的,Python中允许在定义class的时候,定义一个特殊的变量【slots】变量,来限制该class添加的属性

class Person(object):
__slots__=("name","age")
#[不想无限制的任意添加属性]
#比如,只允许给对象添加name, age属性
#解决:定义类的时候,定义一个特殊的属性(__slots__),可以限制动态添加的属性范围
per = Person()
per.height = 170
print(per.height)
这样做会报错
AttributeError: 'Person' object has no attribute 'height'

使用slots的时候需要注意,slots定义的属性仅仅对当前类的实例起作用,对继承的子类是不起作用的。

除非在子类中也定义slots,这样子类实例允许定义的属性就是自身的slots加上父类的slots。

总结:

__slots__:
语法:
__slots__ = (属性名1,属性名2,...) 作用:
限制类的属性名
注意:当子类没有添加slots时,子类继承父类的时候,它的属性名不受父类的影响
若子类中也添加slots,子类的限制应该是父类的slots与子类slots的并集

5、@property

绑定属性时,如果我们直接把属性暴露出去,虽然写起来简单,但是没有办法检查参数,导致可以随意的更改。

比如:

p = Person()
p.age = -1

这显然不合常理,为了限制age的范围,我们可以通过setAge()的方法来设置age,再通过getAge()的方法获取age,这样在setAge()中就可以检查输入的参数的合理性了。

class Person(object):
def __init__(self, name, age):
# 属性直接对外暴露
# self.age = age
# 限制访问
self.__age = age
self.__name = name
# self.__name = name def getAge(self):
return self.__age def setAge(self, age):
if age < 0:
age = 0
self.__age = age # 通过@property和@age.setter改变原来的get/set方法
# 方法名为受限制的变量去掉双下划线
# 相当于get方法
@property
def age(self):
return self.__age # 相当于set的方法
@age.setter # 去掉下划线.setter
def age(self, age):
if age < 0:
age = 0
self.__age = age @property
def name(self):
return self.__name @name.setter
def name(self, name):
self.__name = name per = Person("lili", 18)
# 属性直接对外暴露
# 不安全,没有数据的过滤
# per.age = -10
# print(per.age) # 使用限制访问,需要自己写set和get的方法才能访问
# 劣势:麻烦,代码不直观
# 思考问题:如果我就想使用对象"."的方式访问对象的私有属性,怎么办?
# per.setAge(15)
# print(per.getAge()) # property:可以让你对受限制访问的属性使用"."语法
per.age = 80 # 相当于调用setAge
print(per.age) # 相当于调用getAge print(per.name)
输出:
80
lili
property
总结语法:
针对私有化的属性添加的。
@property
def 属性名(self):
return self.__属性名 @属性名.setter
def 属性名(self, 值):
#业务逻辑处理
self.属性名 = 值

总结:

> a.装饰器(decorator)可以给函数动态加上功能,对于类的方法,装饰器一样起作用,
> python内置的@property装饰器就是负责把一个方法变成属性调用的。
>
> b.@property的使用,把一个getter方法变成属性,只需要加上@property就可以了,
> 此时@property本身又创建了另一个装饰器@属性setter,
> 负责把一个setter方法变成属性赋值.
>
> c.@property广泛应用在类的定义中,可以让调用者写出简短的代码,
> 同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。

6、运算符重载

​ 类可以重载加减运算,打印,函数调用,索引等内置运算,运算符重载使我们的对象的行为与内置函数一样,在python调用时操作符会自动的作用于类的对象,python会自动的搜索并调用对象中指定的方法完成操作。

1、常见运算符重载方法

常见运算符重载方法

方法名 重载说明 运算符调用方式
init 构造函数 对象创建: X = Class(args)
del 析构函数 X对象收回
add sub 加减运算 X+Y, X+=Y/X-Y, X-=Y
or 运算符| X|Y, X|=Y
str_ repr 打印/转换 print(X)、repr(X)/str(X)
call 函数调用 X(*args, **kwargs)
getattr 属性引用 X.undefined
setattr 属性赋值 X.any=value
delattr 属性删除 del X.any
getattribute 属性获取 X.any
getitem 索引运算 X[key],X[i:j]
setitem 索引赋值 X[key],X[i:j]=sequence
delitem 索引和分片删除 del X[key],del X[i:j]
len 长度 len(X)
bool 布尔测试 bool(X)
lt gt le ge eq ne 特定的比较 依次为X<Y,X>Y,X<=Y,X>=Y, X==Y,X!=Y 注释:(lt: less than, gt: greater than, le: less equal, ge: greater equal, eq: equal, ne: not equal )
radd 右侧加法 other+X
iadd 实地(增强的)加法 X+=Y(or else add)
iter next 迭代 I=iter(X), next()
contains 成员关系测试 item in X(X为任何可迭代对象)
index 整数值 hex(X), bin(X), oct(X)
enter exit 环境管理器 with obj as var:
get set delete 描述符属性 X.attr, X.attr=value, del X.attr
new 创建 在__init__之前创建对象
# 举例
# 数字和字符串都能相加
#print(1 + 2)
#print("1" + "2") # 不同的类型用加法会有不同的解释 class Person(object):
def __init__(self, num):
self.num = num # 运算符重载
def __add__(self, other):
return Person(self.num + other.num) # 方法重写
def __str__(self):
return "num = " + str(self.num) # 如果两个对象相加会怎样?
# 对象相加,编译器解释不了,所以就要用到运算符重载
per1 = Person(1)
per2 = Person(2)
print(per1 + per2)
# 结果为地址:per1+per2 === per1.__add__(per2),如果想得到num的和则重写str方法
# 上述打印就等价于:print(per1.__add__(per2)),只不过add方法会自动调用
print(per1)
print(per2)
输出:
num = 3
num = 1
num = 2

后记

【后记】为了让大家能够轻松学编程,我创建了一个公众号【轻松学编程】,里面有让你快速学会编程的文章,当然也有一些干货提高你的编程水平,也有一些编程项目适合做一些课程设计等课题。

也可加我微信【1257309054】,拉你进群,大家一起交流学习。
如果文章对您有帮助,请我喝杯咖啡吧!

公众号

关注我,我们一起成长~~

python实现类的多态的更多相关文章

  1. python(7)–类的多态实现

    第一步: 先定义三个类: class Animal: def __init__(self, name): self.name = name #这个方法的意思是,如果继承该类,就得自己写talk方法,如 ...

  2. Python面向对象 -- 继承和多态、获取对象信息、实例属性和类属性

    继承和多态 继承的好处: 1,子类可以使用父类的全部功能 2,多态:当子类和父类都存在相同的方法时,子类的方法会覆盖父类的方法,即调用时会调用子类的方法.这就是继承的另一个好处:多态. 多态: 调用方 ...

  3. Python 类的多态的运用

    #类的多态的运用 #汽车类 class Car(object): def move(self): print("move ...") #汽车商店类 class CarStore(o ...

  4. python's twenty-first day for me 抽象类和接口类以及多态

    归一化设计: 不管是哪一个类的对象,都调用同一个函数去完成相似的功能. class Alipay: def pay(self,money): print('使用支付宝支付了%s' % money) c ...

  5. python:类的基本特征------继承、多态与封装

    一.继承 1,什么是继承 继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类 python中类的继承分为:单继承和多继承 cl ...

  6. Python类的多态的例子

    1 # -*- coding: utf-8 -*- 2 # 类的多态 3 4 # 定义Person父类 5 class Person(object): 6 def __init__(self, nam ...

  7. python基础——继承和多态

    python基础——继承和多态 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超类 ...

  8. python的类和对象——进阶篇

    写在前面的话 终于,又到了周五.当小伙伴们都不再加班欢欢喜喜过周末的时候,我刚刚写完这一周的游戏作业,从面对晚归的紧皱眉头到现在的从容淡定,好像只有那么几周的时间.突然发现:改变——原来这么简单.很多 ...

  9. python(6)-类

    面向对象编程是一种编程方式,此编程方式的落地需要使用 "类" 和 "对象" 来实现,所以,面向对象编程其实就是对 "类" 和 "对 ...

随机推荐

  1. Android App 侧边栏菜单的简单实现

    效果图 Layout 注意事项 想要实现侧边栏,需要配合使用DrawerLayout.因为会用到嵌套布局,所以根布局不能是 ConstraintLayout,最好使用 LinearLayout 布局. ...

  2. ES 入门 - 基于词项的查询

    准备 首先先声明下,我这里使用的 ES 版本 5.2.0. 为了便于理解,这里以如下 index 为格式,该格式是通过 PMACCT 抓取的 netflow 流量信息, 文中所涉及的到的例子,全基于此 ...

  3. Java知识系统回顾整理01基础03变量04类型转换

    一.不同类型之间的数据可以互相转换,但是要满足一定的规则 二.数据类型转换规则 转换规则如图所示  精度高的数据类型就像容量大的杯子,可以放更大的数据 精度低的数据类型就像容量小的杯子,只能放更小的数 ...

  4. 不会吧,这也行?iOS后台锁屏监听摇一摇

    目录 背景介绍 探索过程 其他 APP 有没有类似功能 系统提供的摇一摇回调能否满足 其他方法能否实现 利用 CoreMotion 框架,监听加速计原始数据 通过加速计监听摇一摇 控制器相关逻辑和代码 ...

  5. Dockerize ASP。净样板项目

    Get the source code from the Github repository. 介绍 在这篇文章中,我将一步步地向你展示如何在Docker上运行ABP模块零核心模板.然后,我们将讨论其 ...

  6. 实时,异步网页使用jTable, SignalR和ASP。NET MVC

    下载source code - 984.21 KB 图:不同客户端的实时同步表. 点击这里观看现场演示. 文章概述 介绍使用的工具演示实现 模型视图控制器 遗言和感谢参考历史 介绍 HTTP(即web ...

  7. fio硬盘测速windows+linux

    一.FIO工具简介 Fio工具的介绍网上有很多,都是可以通用的,这里就不做太多个人描述了,直接借鉴一下 fio是一种I / O工具,用于基准测试和压力/硬件验证.它支持19种不同类型的I / O引擎( ...

  8. TP5上传图片到七牛云,并且删除七牛云的图片

    一,通过composer 下载七牛云 sdk composer require qiniu/php-sdk 二,手动下载七牛云sdk 1,https://developer.qiniu.com/kod ...

  9. lua 源码阅读 1.1 -> 2.1

    lua 1.1 阅读1. hash.c 中 a) 对建立的 Hash *array 用 listhead 链式结构来管理,新增lua_hashcollector,用来做 Hash 的回收处理. ps: ...

  10. Verilog基础入门——Vivado工程创建(三)

    Verilog基础入门--Vivado工程创建(三) Vivado是Verilog语言的一个集成环境,目前使用的版本为英文版,简单介绍一下在Vivado中创建一个工程并写入源文件 [配置] win10 ...