欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Pyhton-类(2)

程序员文章站 2022-05-29 20:25:22
·类(2) @ 继承(inheritance) 什么是继承: B继承A:A是父类(超类),B是子类(基类)。继承可以实现代码重复利用,实现属性和方法继承。 继承可以使子类拥有父类的属性和方法,也可以重新定义某些属性、重写某些方法,即覆盖父类原有的属性和方法,使其获得父类不同的功能。当然,也可以在子类 ......

·类(2)

 

@ 继承(inheritance)


什么是继承:

b继承a:a是父类(超类),b是子类(基类)。继承可以实现代码重复利用,实现属性和方法继承。

继承可以使子类拥有父类的属性和方法,也可以重新定义某些属性、重写某些方法,即覆盖父类原有的属性和方法,使其获得父类不同的功能。当然,也可以在子类中新设置属性和方法。从技术上看,oop里继承最主要的用途是实现多态,对于多态而言,最重要的是接口的继承性(属性和方法是否存在继承性),这是不一定的。继承也不是全为了代码的重复利用,而是为了理顺关系。

对于 python 中的继承,前面一直在使用,那就是我们写的类都是新式类,所有新式类都是继承自 object 类。不要忘记,新式类的一种写法:

class newstyle(object):
    pass

这就是典型的继承。

继承的基本概念:

class person:
    def __init__(self,name):
        self.name = name
        
    def get_name(self):
        print ("hello,{}!".format(self.name))

    def setheight(self, n):
        self.length = n

    def breast(self, n):
        print ("my breast is: ",n)

class boy(person):
    def setheight(self):
        print ("the height is:1.80m .")


j = boy('jimmy')
j.get_name()
j.setheight()
j.breast(90)
打印结果:
hello,jimmy!
the height is:1.80m .
my breast is:  90

首先,定义了一个父类 person,定义一个子类 boy,boy类的括号中是person,这就意味着 boy 继承了 person,boy 是 person 的子类,person 是 boy 的父类。那么 boy 就全部拥有了 person 中的方法和属性。

如果 boy 里面有一个和 person 同样名称的方法,那么就把 person 中的同一个方法遮盖住了,显示的是 boy 中的方法,这叫做方法的重写实例化类 boy之后,执行实例方法  j.setheight(),由于在类 boy中重写了 setheight 方法,那么 person 中的那个方法就不显作用了,在这个实例方法中执行的是类 boy 中的方法。

虽然在类 boy 中没有看到 get_name() 方法,但是因为它继承了 person,所以 j.get_name() 就执行类 person 中的方法。同理  j.breast(90) ,它们就好像是在类 boy 里面已经写了这两个方法一样。既然继承了,就可以使用。

多重继承:

子类继承多个父类:

 

class person:
    def eye(self):
        print("two eyss")
    def breast(self,n):
        print("the breast is:",n)
class girl:
    age = 18
    def color(self):
        print("the girl is white.")
class hotgirl(person,girl):
    pass

 

在类的名字后面的括号中把所继承的两个类的名字写上,hotgirl 就继承了person 和 girl这两个类。实例化类 hotgirl,既然继承了上面的两个类,那么那两个类的方法就都能够拿过来使用。在类 girl 中, age = 28,在对 hotgirl 实例化之后,因为继承的原因,这个类属性也被继承到 hotgirl 中,因此通过实例得到它。

继承的特点,即将父类的方法和属性全部承接到子类中;如果子类重写了父类的方法,就使用子类的该方法,父类的被遮盖。

 多重继承的顺序:

如果一个子类继承了两个父类,并且两个父类有同样的方法或者属性,那么在实例化子类后,调用那个方法或属性,是属于哪个父类的呢?造一个没有实际意义,纯粹为了解决这个问题的程序:

class k1(object):
    def foo(self):
        print("k1-foo")
class k2(object):
    def foo(self):
        print("k2-foo")
    def bar(self):
        print("k2-bar")
class j1(k1, k2):
    pass
class j2(k1, k2):
    def bar(self):
        print("j2-bar")
class c(j1, j2):
    pass

print(c.__mro__)
m = c()
m.foo()
m.bar()
打印结果:
(<class '__main__.c'>, <class '__main__.j1'>, <class '__main__.j2'>, <class '__main__.k1'>, <class '__main__.k2'>, <class 'object'>)
k1-foo
j2-bar

print c.__mro__打印出类的继承顺序。

从上面清晰看出来了,如果要执行 foo() 方法,首先看 j1,没有,看 j2,还没有,看 j1 里面的 k1,有了,即 c(没有)==>j1(没有)==>j2(没有)==>k1(找到了)bar() 也是按照这个顺序,在 j2 中就找到了一个。

这种对继承属性和方法搜索的顺序称之为广度优先新式类用以及 python3.x 中都是按照此顺序原则搜寻属性和方法的。

但是,在旧式类中,是按深度优先的顺序的。因为后面读者也基本不用旧式类,所以不举例。

 

@ super函数


 对于初始化函数的继承,跟一般方法的继承不同:

class person:
    def __init__(self):
        self.height = 160
    def about(self, name):
        print("{} is about {}".format(name, self.height))
class girl(person):
    def __init__(self):
        self.breast = 90
    def about(self, name):
        print("{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast))

cang = girl()
cang.about("wangguniang")
打印结果:
traceback (most recent call last):
  file "test1.py", line 14, in <module>
    cang.about("wangguniang")
  file "test1.py", line 11, in about
    print("{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast))
attributeerror: 'girl' object has no attribute 'height'

在上面这段程序中,类 girl 继承了类 person。在类 girl 中,初始化设置了 self.breast = 90,由于继承了 person,按照前面的经验,person 的初始化函数中的 self.height = 160 也应该被 girl 所继承过来。然后在重写的 about 方法中,就是用 self.height

实例化类 girl,并执行 cang.about("wangguniang"),试图打印出一句话 wangguniang is a hot girl, she is about 160, and her bereast is 90。保存程序,运行报错!

信息显示 self.height 是不存在的。也就是说类 girl 没有从 person 中继承过来这个属性。

 girl中发现, about 方法重写了,__init__方法,也被重写了。它跟类 person 中的__init__重名了,也同样是重写了那个初始化函数。这是因为在子类中重写了某个方法之后,父类中同样的方法被遮盖了。

使用super 函数:

class person:
    def __init__(self):
        self.height = 160
    def about(self, name):
        print("{} is about {}".format(name, self.height))
class girl(person):
    def __init__(self):
        super().__init__()
        self.breast = 90
    def about(self, name):
        print("{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast))

cang = girl()
cang.about("wangguniang")
打印结果:
wangguniang is a hot girl, she is about 160, and her breast is 90

在子类中,__init__方法重写了,为了调用父类同方法,使用 super(girl, self).__init__()的方式。super 函数的参数,第一个是当前子类的类名字,第二个是 self,然后是点号,点号后面是所要调用的父类的方法。同样在子类重写的 about 方法中,也可以调用父类的 about 方法。

最后要提醒注意:super 函数仅仅适用于新式类。

 

@ 绑定方法与非绑定方法


要通过实例来调用类的方法(函数),经常要将类实例化。方法是类内部定义函数,只不过这个函数的第一个参数是 self。(可以认为方法是类属性,但不是实例属性)。必须将类实例化之后,才能通过实例调用该类的方法。调用的时候在方法后面要跟括号(括号中默认有 self 参数,可以不写出来)。通过实例调用方法,称这个方法绑定在实例上。