【python】基础知识—继承,多态,鸭子类型,静态方法,类方法

前言

上一篇文章我们讲到了面向对象编程,而面向对象编程有三大特性,分别是封装性继承性以及多态性,这些特点呢,使得我们的程序的扩展性和健壮性变好。

继承

概念

继承,一种对类进行分层划分的概念。其基本思想是在类的基础上制定出一个新的类,而这个类呢,不仅仅可以继承原本类的属性和方法,还可以增加新的属性和方法。先前制定的类呢,就叫做父类,而后制定的类就叫做子类。一般情况下呢,一个子类是可以继承多个父类的。可是,有一些语言是不支持多重继承的,譬如Java和PHP,python是支持的Java和PHP是有接口(interface)和抽象类(abstract)这些概念的,python也有这样的概念,但语法本身是不直接提供(例如abc模块中提供abstractmethod),这些东西呢,也不是我们今天要讨论的重点。

子类的定义

class animal:
    def __init__(self,name):
        self.name=name

    def play(self):
        print('i am',self.name)

class Dog(animal):
    pass
dog=Dog("AM")
dog.play()

运行结果 

i am AM

这个例子里面,在animal这个父类定义了name属性和play这个方法,但我们在Dog里面什么都没有定义。不过呢,因为Dog是由animal继承而来的,所以,Dog拥有name属性和play这个方法。类继承可以帮助我们重用方法,从而减少所需编写的代码量。

两点注意:

  1. 如果子类定义了构造方法,那么父类的构造方法__init__是不会被自动调用的,需要在子类的构造方法中专门调用

    class animal:
        def __init__(self,name):
            self.name=name
    
        def play(self):
            print('i am',self.name)
    
    class Dog(animal):
        def __init__(self):
            print('AM')
    
    dog=Dog()
    
    dog.play()
     运行结果
    AM
    AttributeError: 'Dog' object has no attribute 'name'

    这个例子呢,说明了animal中的构造方法没有被执行。但是,我们可以使用super函数来调用。

    class animal:
        def __init__(self,name):
            self.name=name
    
        def play(self):
            print('i am',self.name)
    
    class Dog(animal):
        def __init__(self):
            super(Dog,self).__init__("AM")
    
    dog=Dog()
    
    dog.play()

    运行结果

    i am AM

    我们在调用animal的构造方法后运行正确

  2. 子类不能继承父类中的私有方法,也不能调用父类的私有方法。

    class animal:
        def __init__(self,name):
            self.__name=name
    
        def __play(self):
            print('animal,__play')
        
        def play(self):
            print("animal,play")
    
    class Dog(animal):
        def __init__(self):
            super(Dog,self).__init__("AM")
        
        def say(self):
            self.play()
            self.__play()
        
    
    dog=Dog()
    
    dog.say()

    运行结果

    animal,play
    AttributeError: 'Dog' object has no attribute '_Dog__play'

    结果说明,父类的私有方法不会被子类继承。

多态 

概念

多态,顾名思义,就是多种形态,即使不知道变量所引用的对象是什么类型的,也能和对象进行操作。多态会根据类的不同而表现出不同的行为。

继承可以帮我们重复代码,但是有时候子类的行为不一定完全和父类一样

例子

class animal:
    def say(self):
        print('animal')

class Dog(animal):
    pass
class Cat(animal):
    pass

dog=Dog()
dog.say()

cat=Cat()
cat.say()
animal
animal

在这里呢,我们是想让dog和cat输出不一样的东西的,那我们要怎么实现呢

class animal:
    def say(self):
        print('animal')

class Dog(animal):
    def say(self):
        print('dog')
class Cat(animal):
    def say(self):
        print("cat")

dog=Dog()
dog.say()

运行结果

dog
cat

这里呢,我们看到“Dog”和“Cat”分别各自调用了自己的方法。
当子类和父类有相同的方法时,子类就会覆盖父类的方法,这样代码在运行的时候就会调用子类的方法,这就是多态。

判断一个实例是不是某个对象可以使用isinstance函数

class animal:
    def say(self):
        print('animal')

class Dog(animal):
    def say(self):
        print('dog')
class Cat(animal):
    def say(self):
        print("cat")

dog=Dog()

cat=Cat()

print(isinstance(dog,Dog))
print(isinstance(dog,animal))
print(isinstance(cat,Cat))
print(isinstance(cat,animal))
print(isinstance(Dog,animal))
print(isinstance(Cat,animal))

运行结果

True
True
True
True
False
False

我们通过结果,可以看到,‘dog’不仅仅是‘Dog'的实例,也是’animal‘的实例,cat就同理了,而Dog和Cat是类,自然就不是实例了。

class animal:
    def say(self):
        print('animal')

class Dog(animal):
    def say(self):
        print('dog')
class Cat(animal):
    def say(self):
        print("cat")

def Animal_say(Animal:animal):
    Animal.say()

dog=Dog()
cat=Cat()

Animal_say(dog)
Animal_say(cat)
dog
cat

上面这个例子告诉我们,函数Animal根本不管你是Cat的还是Dog的,只要你是animal的子类就可以了 。

鸭子类型

概念

鸭子类型(duck typing)是动态类型的一种风格。在这种风格里面,一个语法的有效语义,不是由继承自特定的类或实现特定的接口决定的,而是由当前方法和属性的集合决定的。

为什么叫鸭子类型

这里有个很生动的例子:当一只鸟走起路来像鸭子,游泳像鸭子,叫起来也像鸭子,那么这只鸟不就可以叫做鸭子吗。

在鸭子类型中,我们所关心的不是对象的类型本身,而是它如何使用。鸭子类型通常不是得益于测试方法和函数中参数的类型,而是依赖文档,代码和测试来确保其正常运行。从静态语言转向动态类语言的用户通常尝试添加一些静态的(在运行之前)类型检查,从而影响了鸭子类型的益处和可伸缩性,并约束了语言的动态特性。

鸭子类型在多态实现中的应用

class Dog:
    def say(self):
        print('Dog')
class Cat:
    def say(self):
        print("Cat")

def Animal_say(Animal):
    Animal.say()

dog=Dog()
cat=Cat()

Animal_say(dog)
Animal_say(cat)

运行结果

Dog
Cat

 在这个例子中,Dog和Cat并没有从animal继承,但都实现了各自的功能。这可以算是“多态”的一种实现方式。python是一个动态的语言,在函数没有被执行时,程序不可以去断定数据的类型(虽可以用函数注释来做限制,但这不是强制性的)只有执行了才去调用相关的方法。这里,我们没有使用继承,但我们仍然可以实现多态。

 类变量和实例变量

类变量

一种在定义类时候定义的变量

class animal:
    name="动物"

区别

类变量不需要实例化就能被调用,相当于绑定在类上,而不是绑定在实例上

class animal:
    name="动物"

print(animal.name)
动物

 但类变量在实例化中也是可以被调用的

class animal:
    name="动物"

dog=animal()
cat=animal()

print(dog.name)
print(cat.name)

animal.name='爬行类动物'

print(dog.name)
print(cat.name)
动物
动物
爬行类动物
爬行类动物

注意:实例不可以修改类变量。如果实例对类变量进行修改,python编译器会新建一个同名的成员变量来代理实例中的类变量。

静态方法和类方法

静态方法

静态方法和类有点相似,在定义类的时候就已经被分配定义好。但静态方法不绑定类也不绑定实例,就给方法加个前缀。定义静态方法是用装饰器实现的。

定义静态方法

class animal:
    name="动物"
   
    @staticmethod
    def play():
        print('playing')

animal.play()

定义静态方法就是在定义函数的上面一行添加一句@staticmethod(装饰器语句)。静态方法不再有默认参数’self‘,因此静态方法本身也不能调用成员变量和成员方法。静态方法不需要实例化之后使用,和类变量一样直接使用就可以了,其他的地方和一般函数一样。

类方法

绑定在定义的类上面的方法,而不是绑定在实例上。

定义类方法

class animal:
    name="动物"
   
    @classmethod
    def play(cls):
        print(cls.name,'playing')

animal.play()
动物 playing

语法和静态方法差不多,但不一样的是,类方法和成员方法一样都会有一个初始的参数,这个参数又不同于成员方法。成员方法的第一个参数指的是实例,而类方法指向的是定义的类本身,所以类方法可以读取和修改类变量。

总结

我们用两篇文章对python语言中的面向对象编程进行了详细的介绍,后续我们会讲一下模块,文件与io的操作,还有一些关于python的其他有趣的知识,希望大家能关注一下博主,博主也会和大家分享所学的知识,谢谢啦!

  • 26
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值