1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
      <output id="hzk7v"></output>
    2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
    3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>

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

       更新时间2019年04月12日 11:49:23   作者微信1257309054   我要评论

      这篇文章主要介绍了Python面向对象程序设计类的多态用法,结合实例形式详细分析了Python面向对象程序设计中类的多态概念原理用法及相关操作注意事项,需要的朋友可以参考下

      本文实例讲述了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.
      #定义一个人类,可以喂猫和老鼠?#36828;?#35199;
      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.在内存中出现的时机不同[类属?#36816;?#30528;类的加载而出现,对象属?#36816;?#30528;对象的创建而出现]

      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

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

      为了给所有的实例?#21450;?#23450;方法可以通过给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绑定方法后所有的实例均可调用

      4slots

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

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

      比如只允许给Person实例添加nameage属性为了达到限制的目的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加?#32454;?#31867;的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装饰器就是负责把一个方法变成属性调用的
      [email protected]的实现比?#32454;?#26434;,我们先考虑如何使用,把一个getter方法变成属性,只需要加上@property就可以了,此时@property本身又创建了另一个装饰器@属性setter,负责把一个setter方法变成属性赋值.
      [email protected]广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行?#26412;?#20943;少了出错的可能性

      6运算符重载

      类可以重载加减运算打印函数调用索引等内置运算运算符重载使我们的对象的?#24418;?#19982;内置函数一样在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 ?#32423;?#27979;试 bool(X)
      lt gt le ge eq ne 特定的比较 ?#26469;?#20026;XYX<=YX>=Y X==YX!=Y 注释lt: less than, gt: greater than, le: less equal, ge: greater equal, eq: equal, ne: not equal
      radd ?#20063;?#21152;法 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

      更多关于Python相关内容?#34892;?#36259;的读者可查看本站专题Python面向对象程序设计入门与进阶教程Python数据结构与算法教程Python函数使用技巧总结Python字符串操作技巧汇总Python编码操作技巧总结Python入门与进阶经典教程

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

      相关文章

      最新评论

      3dԻв

        1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
          <output id="hzk7v"></output>
        2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
        3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>

            1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
              <output id="hzk7v"></output>
            2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
            3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>