zoukankan      html  css  js  c++  java
  • Python基础(十)—面向对象的深入讲解(继承、Mixin编程机制等)

    面向对象的三大特征

    面向对象(Object Oriented),对象=属性+方法

    • 封装
      对象封装了属性、方法的函数,成为一个独立性的模块(信息隐蔽),使得对象更安全。

    • 继承
      面向对象的一个重要特性是复用性,继承是实现复用性的一个重要手段,继承就是子对象可以继承父对象的属性和行为,亦即父对象拥有的属性和行为,其子对象也就拥有了这些属性和行为。

    • 多态
      多态性是指不同对象对同一方法响应不同的行动。

    self、_init_(self)、公有&私有

    • self
      相当于其他语言的this,每次实例化一个对象都保存了不同的self,当进行该对象的操作时,接受到第一个参数self,python则知道是哪一个实例的对象。
      	class Ball:
      	    def setName(self, name):
      	        self.name = name
      
      	    def kick(self):
      	        print('这是%s' % self.name)
      
      	ball = Ball()
      	ball.setName('足球')
      	ball.kick()
      
    • _init_(self)
      类似与其他语言的构造方法,是在实例化对象的时候执行的函数。
      	class Ball:
      	    def __init__(self, name):  # 可以对name进行参数的默认设置
      	        self.name = name
      
      	    def kick(self):
      	        print('这是%s' % self.name)
      
      	ball = Ball('足球')
      	ball.kick()
      
    • 公有&私有
      python的属性和方法默认都是公有的。可以通过 name manging(名字改编)也就是在属性前加上“__”两个下划线就可以变为私有,但是也不是绝对的私有。
      class Person:
          __name = 'lz'
      
      def getName(self):
          return self.__name
      
      p = Person()
      # print(p.__name)  # 报错AttributeError: 'Person' object has no attribute '__name'
      print(p.getName())  # lz
      print(p._Person__name)  # lz
      

    继承的一些特性

    继承对象的时候,子类会继承父类的属性和方法,但是前提是子类没有自己的构造函数(__init(self)),若有自己的构造方法(子类会覆盖父类的同名方法)。

    • __init__继承父类
      子类在使用了自己的__init__的时候,想要继承父类的属性,可以通过以下两种方法
      • 调用未绑定的父类方法
      • 使用super函数
      	class Fish:
      	    def __init__(self, x, y):
      	        self.x = x
      	        self.y = y
      
      	class Shark(Fish):
      	    def __init__(self, x, y, z):
      	        # Fish.__init__(self, x, y)  # 方法一:调用未绑定的父类方法,此时的self是子类的实例对象,所以称为未绑定父类的方法。因此容易想到调用的时候可以使用Fish.__init__(shark)
      	        super(Shark, self).__init__(x, y)  # 方法二:使用super函数,python推荐使用的方法
      	        self.z = z
      
    • python可以实现多重继承,但是python并不推荐。
      	class Ball(Ball1, Ball2)
      
    • 组合
      如果要求定义一个类:水池类,里面有鱼、乌龟。这种情况,可以使用组合的方式。
      	class Turtle:
      	    def __init__(self, x):
      	        self.num = x
      
      	class Fish:
      	    def __init__(self, x):
      	        self.num = x
      
      	class Pool:
      	    def __init__(self, x, y):
      	        self.turtle = Turtle(x)
      	        self.fish = Fish(y)
      
      	    def print_num(self):
      	        print('水池内有乌龟%d条,鱼%d条' % (self.turtle.num, self.fish.num))
      
      	pool = Pool(1, 10)
      	pool.print_num()
      

    Mixin编程机制

    • 简介
      Mixin 编程是一种开发模式,是一种将多个类中的功能单元的进行组合的利用的方式,这听起来就像是有类的继承机制就可以实现,然而这与传统的类继承有所不同。通常 Mixin 并不作为任何类的基类,也不关心与什么类一起使用,而是在运行时动态的同其他零散的类一起组合使用。
    • 特点
      • 可以在不修改任何源代码的情况下,对已有类进行扩展;
      • 可以保证组件的划分;
      • 可以根据需要,使用已有的功能进行组合,来实现“新”类;
      • 很好的避免了类继承的局限性,因为新的业务需要可能就需要创建新的子类。
    • 实现
      • 多继承
        Python支持多继承,即一个类可以继承多个子类。可以利用该特性,可以方便的实现mixin继承。如下代码,类A,B分别表示不同的功能单元,C为A,B功能的组合,这样类C就拥有了类A, B的功能。
      	class A:
      	    def get_a(self):
      	    print 'a'
      
      	class B:
      	    def get_b(self):
      	    print 'b'
      
      	class C(A, B): 
      	    pass
      
      	c = C()
      	c.get_a()
      	c.get_b()
      
      • __bases__属性
        多继承的实现就会创建新类,有时,我们在运行时,希望给类A添加类B的功能时,也可以利用python的元编程特性,__bases__属性便在运行时轻松给类A添加类B的特性,如下代码:
          A.__bases__ += (B,)
          a.get_b()
        
          # 其实__bases__也是继承的机制,因为__bases__属性存储了类的基类。因此多继承的方法也可以这样实现:
          class C:
              pass
        
          C.__bases__ += (A, B, )
        
      • 插件方式
        以上两种方式,都是基于多继承和python的元编程特性,然而在业务需求变化时,就需要新的功能组合,那么就需要重新修改A的基类,这回带来同步的问题,因为我们改的是类的特性,而不是对象的。因此以上修改会对所有引用该类的模块都收到影响,这是相当危险的。通常我们希望修改对象的行为,而不是修改类的。同样的我们可以利用__dict__来扩展对象的方法。
          class PlugIn(object):
              def __init__(self):
                  self._exported_methods = []
                  
              def plugin(self, owner):
                  for f in self._exported_methods:
                      owner.__dict__[f.__name__] = f
        
              def plugout(self, owner):
                  for f in self._exported_methods:
                      del owner.__dict__[f.__name__]
        
          class AFeature(PlugIn):
              def __init__(self):
                  super(AFeature, self).__init__()
                  self._exported_methods.append(self.get_a_value)
        
              def get_a_value(self):
                  print 'a feature.'
        
          class BFeature(PlugIn):
              def __init__(self):
                  super(BFeature, self).__init__()
                  self._exported_methods.append(self.get_b_value)
        
              def get_b_value(self):
                  print 'b feature.'
        
          class Combine:pass
        
          c = Combine()
          AFeature().plugin(c)
          BFeature().plugin(c)
        
          c.get_a_value()
          c.get_b_value()
        

    类、类对象和实例对象

    三者是什么:定义的时候是类;在写完类之后就变成类对象;实例化一个类对象的时候,就是实例对象

      	class Ball:
      		name = '球'
    
    • 三者的相互影响
      类定义 -> 类对象 -> 实例对象。类定义中定义的属性都是静态属性,类属性和类对象相互绑定,不会依赖实例化对象。所以当实例对象的属性改变时,只是实例属性覆盖了类属型。反之,当实例对象的属性没改变,那就是还受类属型的影响

      	class Fish:
      	    size = 10
      
      	a = Fish()
      	b = Fish()
      	c = Fish()
      
      	print(a.size, b.size, c.size)  # 10 10 10
      
      	c.size += 10
      	print(a.size, b.size, c.size)  # 10 10 20
      
      	Fish.size += 100
      	print(a.size, b.size, c.size)  # 110 110 20
      
    • 类属性名和方法同名时,方法会被覆盖

    • 绑定
      python严格要求方法需要实例才能调用,这其实就是python的绑定概念。

      	class BB:
      	    def setXY(self, x, y):
      	        self.x = x
      	        self.y = y
      	    def printXY(self):
      	        print(self.x, self.y)
      
      	bb = BB()
      	print(bb.__dict__)
      	print(BB.__dict__)
      
      	bb.setXY(5, 10)  # 这里其实相当于bb.setXY(bb, 5, 10)
      	print(bb.__dict__)
      	print(BB.__dict__)
      
      	del BB
      	# cc = BB()  # 报错
      	bb.printXY()  # 5 10。因为实例化之后,就成为了静态属性,所以不会受影响
      

    对象的内置方法

    下面介绍对象的一些内置方法(本身具备有的)。

    • issubclass(class, classinfo)
      如果class是classinfo的子类就返回True,其他情况则返回False,有些特殊情况:
      • 一个类是自身的子类
      • classinfo可以是类对象组成的元组,只要与其中一个匹配,则返回True
      • issubclass(className, object) # True
    • isinstance(obecjt, classinfo)
      检查一个实例对象obecjt,是否属于classinfo类,同样classinfo可以是元组的格式。
      • 如果第一个参数object不是对象,则永远返回False
      • 如果第二个参数classinfo不是类或者类对象组成的元组,会抛出“TypeError”的异常
    • hasattr(object, name)
      查看实例对象object,是否有参数name,其中name是字符串的格式。
    • getattr(object, name[, default])
      返回对象object指定的属性值name,如果指定的属性不存在,则返回定义的default,如果没有定义默认值,则抛出异常NameError…not defined
    • setattr(object, name, value)
      设置对象object指定的属性值name,如果属性不存在,则会新建该指定属性,值为value
    • delattr(object, name)
      删除对象object指定的属性值name,如果属性不存在,则抛出异常AttributeError
    class A:
        def __init__(self, x=1):
            self.x = x
    class B(A):
        def __init__(self, x, y=-1):
            super(B, self).__init__(x)
            self.y = y
    
    b1 = B(2, -2)
    print(issubclass(B, B))  # True
    print(issubclass(B, (A, object)))  # True
    
    print(isinstance(b1, (A, object)))  # True
    
    print(hasattr(b1, 'x'), b1.x)  # True 2
    print(hasattr(b1, 'y'), b1.y)  # True -2
    
    print(getattr(b1, 'x', 10))  # 2
    print(getattr(b1, 'z', 'z参数不存在'))  # z参数不存在
    
    print(setattr(b1, 'x', 10), b1.x)  # None 10
    print(setattr(b1, 'z', 'z参数不存在'), b1.z)  # None z参数不存在
    
    print(delattr(b1, 'x'))  # None delattr
    
    • property(fget=None, fset=None, fdel=None, doc=None)
      通过类定义的属性设置属性。
    class C:
        def __init__(self, size = 10):
            self.size = size
        def getSize(self):
            return self.size
        def setSize(self, value):
            self.size = value
        def delSize(self):
            del self.size
        x = property(getSize, setSize, delSize)
    
    c1 = C(20)
    # 获取
    print(c1.getSize())  # 20
    print(c1.x)  # 20
    # 设置
    c1.x = 30
    print(c1.x)  # 30
    # 删除
    del c1.x
    # print(c1.x)  # 报错
    

    文章参照小甲鱼

    个人博客:Loak 正 - 关注人工智能及互联网的个人博客
    文章地址:Python基础(十)—面向对象的深入讲解(继承、Mixin编程机制等)

  • 相关阅读:
    MYSQL
    Oracle建立表空间和用户
    oracle创建表空间
    MySQL数据库远程连接开启方法
    linux mkfs命令参数及用法详解---linux格式化文件系统命令(包括swap分区)
    小峰Hibernate简介与HelloWorld
    数据结构与算法JavaScript描述——链表
    数据结构与算法JavaScript描述——使用队列
    数据结构与算法JavaScript描述——队列
    数据结构与算法JavaScript描述——栈的使用
  • 原文地址:https://www.cnblogs.com/l0zh/p/13739753.html
Copyright © 2011-2022 走看看