当前位置:脚本大全 > > 正文

python面向对象实例教程(Python面向对象程序设计类的多态用法详解)

时间:2021-10-18 11:46:42类别:脚本大全

python面向对象实例教程

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

    上一篇下一篇

    猜您喜欢

    热门推荐