gpt4 book ai didi

Python面向对象程序设计类的多态用法详解

转载 作者:qq735679552 更新时间:2022-09-28 22:32:09 24 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章Python面向对象程序设计类的多态用法详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

本文实例讲述了python面向对象程序设计类的多态用法。分享给大家供大家参考,具体如下:

多态 。

1、多态使用 。

一种事物的多种体现形式,举例:动物有很多种 。

注意: 继承是多态的前提 。

函数重写就是多态的体现形式 。

演示:重写animal类 。

第一步:先定义猫类和老鼠类,继承自object,在其中书写构造方法和eat方法 第二步: 抽取animal父类,定义属性和eat方法,猫类与老鼠类继承即可 第三步: 定义人类,在其中分别定义喂猫和喂老鼠的方法 第四步:使用多态,将多个喂的方法提取一个.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 测试类
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吃 。

?
1
2
3
4
5
6
#animal.py文件中的动物类
class animal( object ):
   def __init__( self , name):
     self .name = name
   def eat( self ):
     print ( self .name + "吃" )
?
1
2
3
4
5
#cat.py文件中的猫类
class cat(animal):
   def __init__( self , name):
     #self.name = name
     super (cat, self ).__init__(name)
?
1
2
3
4
5
#mouse.py中的老鼠类
class mouse(animal):
   def __init__( self , name):
     #self.name = name
     super (mouse, self ).__init__(name)
?
1
2
3
4
5
#person.py中的人类
class person( object ):
   def feedanimal( self , ani):
     print ( "给你食物" )
     ani.eat()

2、对象属性与类属性 。

对象属性和类属性的区别

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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函数的使用 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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绑定方法 。

?
1
2
3
4
5
6
7
#动态添加方法
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添加的属性 。

?
1
2
3
4
5
6
7
8
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__

语法:

?
1
__slots__ = (属性名 1 ,属性名 2 ,...)

作用:

限制类的属性名 。

注意:当子类没有添加slots时,子类继承父类的时候,它的属性名不受父类的影响 。

若子类中也添加slots,子类的限制应该是父类的slots与子类slots的并集 。

5、@property 。

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

比如:

?
1
2
p = person()
p.age = - 1

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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 。

总结语法:

针对私有化的属性添加的.

?
1
2
3
@property
   def 属性名( self ):
     return self .__属性名
?
1
2
3
4
@属性名.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 特定的比较 依次为xy,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之前创建对象

  。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 举例
# 数字和字符串都能相加
#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 。

希望本文所述对大家python程序设计有所帮助.

原文链接:https://blog.csdn.net/lm_is_dc/article/details/80171357 。

最后此篇关于Python面向对象程序设计类的多态用法详解的文章就讲到这里了,如果你想了解更多关于Python面向对象程序设计类的多态用法详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com