Python课堂笔记-第十三讲(面向对象)

一、继承

通过继承我们可以使一个类获取到其他类中的属性和方法。
在定义类时,可以在类名后面的括号中指定当前类的父类(超类、基类)。

# 定义一个动物类(Animal) 定义两个方法 run() sleep()
class Animal:

    def run(self):
        print('动物会跑.......')

    def sleep(self):
        print('动物睡觉......')

# 定义一个狗类
# 直接从Animal类中继承它的属性和方法

class Dog(Animal):

    def run(self):
        print('狗会跑.......')

    def speak(self):
        print('我会看家....')

d = Dog()
print(d)
d.run()

# 运行结果
<__main__.Dog object at 0x000001FC587B8D68>
狗会跑.......

继承提高了类的复用性,让类与类之间产生了关系,有了这个关系,才有了多态的特性。


二、⽅法重写

如果在子类中有和父类同名的方法,则通过子类实例去调用方法时,会调用子类的方法而不是父类的方法,这个特点我们称之为方法的重写(覆盖)。

class A(object):

    def test(self):
        print('A.........')

class B(A):

    def test(self):
        print('B.........')

class C(B):

    def test(self):
        print('C.........')

c = C()
c.test()

# 运行结果
C.........

当我们调用一个对象的方法时:
会优先去当前对象中寻找是否具有该方法,如果有则直接调用;
如果没有,则去当前对象的父类中寻找;
如果父类中有,则直接调用父类中的方法;
如果没有,则去父类中的父类寻找;
以此类推,直到找到object,如果依然没有找到就报错了。


三、super()

如果在子类中也定义了_init_()函数,那么该如何调用基类的_init_()函数?

方法一、明确指定 :

class C(P):
    def __init__(self):
        P.__init__(self)
        print 'calling Cs construtor'

方法二、使用super()方法:

class C(P):
    def __init__(self):
        super(C,self).__init__()
        print 'calling Cs construtor'
c=C()

super()的好处就是可以避免直接使用父类的名字,主要用于多重继承。

class A:
    def m(self):
        print('A')

class B:
    def m(self):
        print('B')

class C(A):
    def m(self):
        print('C')
        super().m()

C().m()

如果你要改变子类继承的父类(由A改为B),你只需要修改一行代码(class C(A): -> class C(B))即可,而不需要在class C的大量代码中去查找、修改基类名。另外一方面,代码的可移植性和重用性也更高。


四、多重继承

多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法。
如果多个父类中有同名的方法,则会先在第一个父类中寻找,然后找第二个,找第三个…前面会覆盖后面的。

class A(object):
    pass

class B(object):
    def test(self):
        print('B.........')

# 可以在类名后的()中添加多个类,实现多重继承
class C(A,B):
    pass

# __bases__ 可以获取当前类所有的父类
print(C.__bases__)
c = C()
c.test()

# 运行结果
(<class '__main__.A'>, <class '__main__.B'>)
B.........


五、多态

同一个变量p在执行同一个方法时,由于p 指向的对象不同,因此它呈现不同的行为特征,这就是多态。

class Dog(object):
    def dog_work(self):
        print('狗正在工作')

class SearchDog(Dog):
    def dog_work(self):
        print('搜救犬正在搜索生命')

class PoliceDog(Dog):
    def dog_work(self):
        print('警犬正在抓坏人')

class FlyDog(Dog):
    def dog_work(self):
        print('飞天犬正在飞')

class BlindDog(Dog):
    def dog_work(self):
        print('导盲犬正在领路')

class Person(object):
    def __init__(self, dog=None):
        self.dog = dog

def work_with_dog(self):
    self.dog.dog_work()

sd = SearchDog()
pd = PoliceDog()
fd = FlyDog()
bd = BlindDog()

p = Person(bd)
p.work_with_dog()

# 运行结果
导盲犬正在领路

当程序涉及Dog 类的dog_work方法时,该方法所需要的参数是非常灵活的,程序为该方法传入的参数只要具有指定方法就行,至于该方法呈现怎样的行为特征,则完全取决于对象本身,这就大大提高了dog_work()方法的灵活性。


六、属性和方法

  • 类属性
    直接在类中定义的属性。
    类属性可以通过类或类的实例访问到,但是类属性只能通过类对象来修改,无法通过实例对象修改。

  • 实例属性
    通过实例对象添加的属性。
    实例属性只能通过实例对象来访问和修改,类对象无法访问修改。

  • 类方法
    在类的内容以@classmethod 来修饰的方法。
    类方法第一个参数是cls 也会自动被传递,cls就是当前的类对象。

  • 实例方法
    在类中定义,以self为第一个参数的方法都是实例方法。
    实例方法在调用时,Python会将调用对象以self传入;
    实例方法可以通过类实例和类去调用;
    当通过实例调用时,会自动将当前调用对象作为self传入;
    当通过类调用时,不会自动传递self,我们必须手动传递self。

  • 类方法和实例方法的区别
    实例方法的第一个参数是self,类方法的第一个参数是cls。
    类方法可以通过类去调用,也可以通过实例调用。

  • 静态方法
    在类中⽤@staticmethod来修饰的方法属于静态方法
    静态方法不需要指定任何的默认参数,静态方法可以通过类和实例调用;
    静态方法,基本上是⼀个和当前类无关的方法,它只是一个保存到当前类中的函数;
    静态方法一般都是些工具方法,和当前类无关。

  • Python3 类方法总结
    普通方法:对象访问;
    私有方法:两个下划线开头,只能在类内部访问;
    静态方法:类和对象访问,不能和其他方法重名,不然会相互覆盖,后面定义的会覆盖前面的;
    类方法:类和对象访问,不能和其他方法重名,不然会相互覆盖,后面定义的会覆盖前面的;
    多继承情况下:从左到右查找方法,找到为止,不然就抛出异常。

class People:

    # 定义基本属性
    name=''
    age=0
    # 定义私有属性外部无法直接访问
    __weight=0
    def __init__(self,n,a,w):
        self.name = n
        self.age = a
        self.__weight = w
    def speak(self):
        print("%s say : i am %d."%(self.name,self.age))
p = People('Python',10,20)
p.speak()
# __weight无法直接访问
print(p.name,'--',p.age)#,'--',p.__weight)

单继承:

class Student(People):
    grade=''
    def __init__(self,n,a,w,g):
        People.__init__(self,n,a,w)
        self.grade = g

    # 覆写父类方法
    def speak():
        print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))

class Speak():
    topic=''
    name=''
    def __init__(self,n,t):
        self.name = n
        self.topic = t
    # 普通方法,对象调用
    def speak(self):
        print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))

    # 私有方法,self调用
    def __song(self):
        print('唱一首歌自己听',self);

    # 静态方法,对象和类调用,不能和其他方法重名,不然会相互覆盖,后面定义的会覆盖前面的
    @staticmethod
    def song():
        print('唱一首歌给类听:静态方法');

    # 普通方法,对象调用
    def song(self):
        print('唱一首歌给你们听',self);
        
    # 类方法,对象和类调用,不能和其他方法重名,不然会相互覆盖,后面定义的会覆盖前面的
    @classmethod
    def song(self):
        print('唱一首歌给类听:类方法',self)

多继承:

class Sample(Speak,Student):
    a = ''
    def __init__(self,n,a,w,g,t):
        Student.__init__(self,n,a,w,g)
        Speak.__init__(self,n,t)
test = Sample('Song',24,56,7,'Python')
test.speak()
test.song()
Sample.song()
Sample.song()
test.song()

# test.__song() 无法访问私有方法


总结

python核心编程课堂笔记-第十三讲(面相对象)点击访问源图


版权声明:本文为chris7266原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。