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编程机制等)

  • 相关阅读:
    ant 软件包不存在报错
    在 Internet Explorer 中使用 Windows 窗体控件
    智能客户端
    Back to the Future with Smart Clients
    "Automation 服务器不能创建对象" 的解决方案
    Top 10 Reasons for Developers to Create Smart Clients
    Updater Application Block for .NET
    Smart Client Application Model and the .NET Framework 1.1
    Security and Versioning Models in the Windows Forms Engine Help You Create and Deploy Smart Clients
    智能客户端技术总结(二)
  • 原文地址:https://www.cnblogs.com/l0zh/p/13739753.html
Copyright © 2011-2022 走看看