Python学习日记(十四)


继承

  • 继承父类的属性和方法,如果子类中定义的属性和方法与父类相同,会覆盖父类,组合纵向关系的类
  • class 子类(父类或基类):
        .....
    
    class parent:
        def f(self):
            print("我是父类")
    class child(parent):
        pass
    c=child()
    c.f()
    我是父类
    
    
    class parent:
        def f(self):
            print("我是父类")
    class child(parent):
        def f(self):
            print("我是子类")
    c=child()
    c.f()
    我是子类
    
    
    class parent:
        def f(self):
            print("我是父类")
    class child(parent):
        def f(self):
            print("我是子类")
    c=child()
    c.f()
    p=parent()
    p.f()
    我是子类
    我是父类
    
  • 在子类中重写初始化函数__init__时要首先把父类的__init__变量加进去,否则会全部覆盖,不能使用父类__init__中的变量
  • __ init__特殊方法不应当返回除了None以外的任何对象
  • import random as r
    class Fish:
        def __init__(self):
            self.x=r.randint(0,10)
        def move(self):
            self.x-=1
            print("我的位置是:",self.x)
    
    class Shark(Fish):
        def __init__(self):
            self.life='good'
    S=Shark()
    S.move()
    Traceback (most recent call last):
      File "E:\大三冬\PYTHON\class2.py", line 13, in 
        S.move()
      File "E:\大三冬\PYTHON\class2.py", line 6, in move
        self.x-=1
    AttributeError: 'Shark' object has no attribute 'x'
  • 在子类中使用父类的方法
    • 调用未绑定的父类方法

可在子类的__init__函数中调用父类的__init__函数,未绑定指的是其中的self任然是指向子类的对象

    • import random as r
      class Fish:
          def __init__(self):
              self.x=r.randint(0,10)
          def move(self):
              self.x-=1
              print("我的位置是:",self.x)
      
      class Shark(Fish):
          def __init__(self):
              Fish.__init__(self)
              self.life='good'
      S=Shark()
      S.move()
      我的位置是: 2
    • 使用super函数
    • 可以帮助我们找到父类的方法并自动传入self参数
    • 在子类的__init__中使用super.需要的父类的方法即可,不用传self参数
      import random as r
      class Fish:
          def __init__(self):
              self.x=r.randint(0,10)
          def move(self):
              self.x-=1
              print("我的位置是:",self.x)
      
      class Shark(Fish):
          def __init__(self):
              super().__init__()
              self.life='good'
      S=Shark()
      S.move()
      我的位置是: 1
  • 多重继承
    • 继承多个父类,容易导致代码混乱,别轻易使用
    • class 子类(父类1,父类2,...):
          ........

组合

  • 把类的实例化放到一个新类中,组合多个横向关系的类
  • class Fish:
        def __init__(self,x):
            self.num=x
    
    class Frog:
        def __init__(self,x):
            self.num=x
    
    class Pool:
        def __init__(self,x,y):
            self.fish=Fish(x)
            self.frog=Frog(y)
        def show(self):
            print('水池中共有%d只鱼和%d只青蛙'%(self.fish.num,self.frog.num))
    
    p=Pool(10,5)
    p.show()
    水池中共有10只鱼和5只青蛙

类、类对象和实例对象

  • 实例属性修改后就覆盖了类属性,但是不会改变类属性,相当于将实例属性指向另一个地址,类属性改变也不会影响实例属性
  • 类属性是静态的,定义了就一直存在,直到程序退出才消失,即使把类删除类的属性也还在,相当于C语言中的静态变量
  • >>> a=C()
    >>> b=C()
    >>> c=C()
    >>> a.count
    0
    >>> a.count=10
    >>> a.count
    10
    >>> b.count
    0
    >>> c.count
    0
    >>> C.count=5
    >>> a.count
    10
    >>> b.count
    0
    >>> c.count
    0
    >>> C.count
    5
  • 属性的名字和方法冲突时属性会覆盖方法
  • >>> class C:
    	def x(self):
    		print('芜湖')
    
    		
    >>> c=C()
    >>> c.x()
    芜湖
    >>> c.x=1
    >>> c.x
    1
    >>> c.x()
    Traceback (most recent call last):
      File "", line 1, in 
        c.x()
    TypeError: 'int' object is not callable

类和对象的BIF

  • issubclass(class, classinfo)
    如果第一个参数是第二个参数的一个子类,则返回True,否则返回False:
    1??一个类被认为是其自身的子类。
    2??classinfo可以是类对象组成的元组,只要class是其中任何一个候选类的子类,则返回True。
    3??在其他情况下,会抛出一个TypeError异常
    >>> class A:
        pass
    
    >>> class B(A):
        pass
    
    >>> issubclass(B,A)
    True
    >>> issubclass(B,B)
    True
    >>> issubclass(B,object)
    True
    >>> class C:
        pass
    
    >>> issubclass(B,C)
    False
    >>> issubclass(B,(A,C))
    True
    >>> issubclass(B,111)
    Traceback (most recent call last):
      File "", line 1, in 
        issubclass(B,111)
    TypeError: issubclass() arg 2 must be a class or tuple of classes
  • isinstance(object, classinfo)
  • 如果第一个参数是第二个参数的实例对象,则返回True,否则返回False:
    1??如果object是classinfo的子类的一个实例,也符号条件。
    2??如果第一个参数不是对象,则永远返回False。
    3??classinfo可以是类对象组成的元组,只要object是其中任何一个候选对象的实例,则返回True。
    4??如果第二个参数不是类或者由类对象组成的元组,会抛出一个TypeError异常。
  • >>> class A:
        pass
    
    >>> class B(A):
        pass
    
    >>> class C:
        pass
    
    >>> issubclass(B,C)
    False
    >>> b1 = B()
    >>> isinstance(b1,B)
    True
    >>> isinstance(b1,A)
    True
    >>> isinstance(b1,C)
    False
    >>> isinstance(b1,object)
    True
    >>> isinstance(b1,(A,B,C))
    True
    >>> isinstance(111,A)
    False
    >>> isinstance(b1,111)
    Traceback (most recent call last):
      File "", line 1, in 
        isinstance(b1,111)
    TypeError: isinstance() arg 2 must be a type or tuple of types
  • hasattr(object, name) attr即attribute的缩写,属性的意思。其作用就是测试一下对象里是否有指定的属性。
    第一个参数是对象,第二个参数是属性名(属性的字符串名字),举个例子:
    >>> class C:
        def __init__(self, x=0):
            self.x = x
    
            
    >>> c1 = C()
    >>> hasattr(c1, 'x')
    True
    >>> hasattr(c1, 'y')
    False
        · getattr(object, name[, default]) 返回对象指定的属性值,如果指定的属性不存在,则返回default(可选参数)的值;若没有设置default参数,则抛出AttributeError异常。
    >>> class C:
        def __init__(self, x=0, y=1):
            self.x = x
            self.y = y
    
    >>> c1 =C()
    >>> getattr(c1, 'x')
    0
    >>> getattr(c1, 'y')
    1
    >>> getattr(c1, 'z')
    Traceback (most recent call last):
      File "", line 1, in 
        getattr(c1, 'z')
    AttributeError: 'C' object has no attribute 'z'
    >>> getattr(c1, 'z', '您访问的属性不存在')
    '您访问的属性不存在'
  • setattr(object, name, value)
  • 用来设置对象中指定属性的值,如果指定的属性不存在,则新建属性并赋值。
  • >>> setattr(c1, 'x', 111)  # 原来有的覆盖
    >>> getattr(c1, 'x')
    111
    >>> setattr(c1, 'z', 2)  # 没有新建并赋值
    >>> getattr(c1, 'z')
    2
  •  delattr(object, name)
  • 用来删除对象中指定的属性,如果属性不存在,则抛出AttributeError异常。
  • >>> delattr(c1, 'x')
    >>> delattr(c1, 'y')
    >>> delattr(c1, 'z')
    >>> delattr(c1, 'aaa')
    Traceback (most recent call last):
      File "", line 1, in 
        delattr(c1, 'aaa')
    AttributeError: aaa
    >>> 
  • 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)
    
    >>> c = C()
    >>> c.x
    10
    >>> c.x = 12
    >>> c.x
    12
    >>> c.size
    12
    >>> del c.x
    >>> c.size
    Traceback (most recent call last):
      File "", line 1, in 
        c.size
    AttributeError: 'C' object has no attribute 'size'
  • property()函数中的三个函数分别对应的是获取属性的方法、设置属性的方法以及删除属性的方法,这样一来,外部的对象就可以通过访问x的方式,来达到获取、设置或删除属性的目的。

    当需要更改上例中的getSize、setSize或delSize函数的名称时,如果这些方法是作为接口让用户调用的,那么对用户而言就要修改自己调用的方法名,很麻烦,使用了proprty()后,用户就不需担心这种问题了。

习题:

1、定义一个点(Point)类和直线(Line)类,使用getLen方法可以获得直线的长度。

  • 提示:
    1??设点A(X1,Y1)、B(X2,Y2),则两点构成的直线长度为|AB| = √(X1-X2)^2 + (Y1-Y2)^2
    2??Python中计算开根号可使用math模块中的sqrt函数
    3??直线需有两点构成,因此初始化时需要有两个点(Point)对象作为参数
    
    import math
    
    class Point():
        def __init__(self, x=0, y=0):
            self.x = x
            self.y = y
    
        def getX(self):
            return self.x
    
        def getY(self):
            return self.y
    
    class Line():
        def __init__(self, p1, p2):
            self.x = p1.getX() - p2.getX()
            self.y = p1.getY() - p2.getY()
            self.len = math.sqrt(self.x * self.x + self.y * self.y)
    
        def getLen(self):
            return self.len
    
    p1 = Point(1, 1)
    p2 = Point(1, 4)
    line = Line(p1, p2)
    print(line.getLen())