python实现类的多态
多态
关注公众号“轻松学编程”了解更多。
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实现类的多态的更多相关文章
- python(7)–类的多态实现
第一步: 先定义三个类: class Animal: def __init__(self, name): self.name = name #这个方法的意思是,如果继承该类,就得自己写talk方法,如 ...
- Python面向对象 -- 继承和多态、获取对象信息、实例属性和类属性
继承和多态 继承的好处: 1,子类可以使用父类的全部功能 2,多态:当子类和父类都存在相同的方法时,子类的方法会覆盖父类的方法,即调用时会调用子类的方法.这就是继承的另一个好处:多态. 多态: 调用方 ...
- Python 类的多态的运用
#类的多态的运用 #汽车类 class Car(object): def move(self): print("move ...") #汽车商店类 class CarStore(o ...
- python's twenty-first day for me 抽象类和接口类以及多态
归一化设计: 不管是哪一个类的对象,都调用同一个函数去完成相似的功能. class Alipay: def pay(self,money): print('使用支付宝支付了%s' % money) c ...
- python:类的基本特征------继承、多态与封装
一.继承 1,什么是继承 继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类 python中类的继承分为:单继承和多继承 cl ...
- Python类的多态的例子
1 # -*- coding: utf-8 -*- 2 # 类的多态 3 4 # 定义Person父类 5 class Person(object): 6 def __init__(self, nam ...
- python基础——继承和多态
python基础——继承和多态 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超类 ...
- python的类和对象——进阶篇
写在前面的话 终于,又到了周五.当小伙伴们都不再加班欢欢喜喜过周末的时候,我刚刚写完这一周的游戏作业,从面对晚归的紧皱眉头到现在的从容淡定,好像只有那么几周的时间.突然发现:改变——原来这么简单.很多 ...
- python(6)-类
面向对象编程是一种编程方式,此编程方式的落地需要使用 "类" 和 "对象" 来实现,所以,面向对象编程其实就是对 "类" 和 "对 ...
随机推荐
- Python-面向网络编程-socket原理
socket 整个计算机网络是由协议构成,想要通信必须遵守对应的协议,如Web中的http协议.传输协议TCP和UDP等等.在网络工程师的眼中,可能现在网络上的一切都是socket,一切皆socket ...
- Python-判断变量类型和继承链-type isinstance
在很多情况下,需要对类型进程动态判断,因为不同的数据类型不能互相做运算并且各自拥有不同的运算逻辑,所有需要判断对象的类型,常用的是type和isinstance,type更过用于获取对象是什么类型构建 ...
- Java知识系统回顾整理01基础03变量07final关键字
一.final赋值 final 修饰一个变量,有很多种说法,比如不能改变等等 准确的描述是 当一个变量被final修饰的时候,该变量只有一次赋值的机会 二.在声明的时候赋值 i已经被赋值为5,所以这里 ...
- Java知识系统回顾整理01基础03变量04类型转换
一.不同类型之间的数据可以互相转换,但是要满足一定的规则 二.数据类型转换规则 转换规则如图所示 精度高的数据类型就像容量大的杯子,可以放更大的数据 精度低的数据类型就像容量小的杯子,只能放更小的数 ...
- matlab中polyfit
来源:https://ww2.mathworks.cn/help/matlab/ref/polyfit.html?searchHighlight=polyfit&s_tid=doc_srcht ...
- Java (三)APACHE Commons IO 常规操作
上一篇:Java (二)基于Eclipse配置Commons IO的环境 例1:查看文件.文件夹的长度(大小). 1 import java.io.File; 2 3 import org.apach ...
- 099 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 02 案例分析及实现 03 编写并测试Student类
099 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 02 案例分析及实现 03 编写并测试Student类 本文知识点:编写并测试Subject类 说明: ...
- JavaScript筛选数组
要求: 从一个数组中,筛选出符合条件的元素,放到新数组中. 有一数组[1, 19, 2, 8, 9, 15, 11, 7, 6, 4, 18, 10],将超过10的元素删除. 代码实现: var ar ...
- 第一次使用HSDB
今天看了几篇大佬关于HSDB使用的文章,自己也依样画葫芦的用来一下,强大的一匹!!! HSDB(Hotspot Debugger),JDK自带的工具,用于查看JVM运行时的状态. HSDB位于C:\P ...
- RHSA-2019:0201-低危: systemd 安全更新
[root@localhost ~]# cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) 修复命令: 使用root账号登陆She ...