python123第三周答案_第三周:Python抽象类

Python抽象类

在Python中抽象类只能被继承,不能被实例化。

并且,抽象类中只有抽象方法和普通方法。

定义抽象类和抽象方法

Python的抽象类的定义需要abc模块。(= =...)

# 导入抽象类需要用到的库

from abc import ABCMeta, abstractmethod

class Person(metaclass=ABCMeta):

"""使用元类(模板类)"""

pname = "这是Person抽象类" # 可以定义属性

# 定义抽象方法,抽象方法不需要方法体

# 需要在方法前加@abstractmethod装饰器

@abstractmethod

def run(self):

pass # 不需要写方法体

@classmethod # 可以定义类方法

def eat(cls):

print("在吃东西啊")

@staticmethod

def drink(): # 可以定义静态方法

print("在喝东西啊")

def sleep(self): # 可以定义普通方法

print("在睡觉啊")

抽象方法不需要写方法体,但并不是不能写。可以写,但是没有用。

抽象类中可以定义属性、类方法、静态方法

使用抽象类和抽象方法

class Student(Person):

sno = 123 # 学号

# 不会提示要要重写方法

def run(self):

print("跑")

# 不重写抽象方法就无法实例化对象,并且抛异常

s = Student()

s.run() # 跑

s.eat() # 在吃东西啊

s.sleep() # 在睡觉啊

print(s.pname) # 这是Person抽象类

s.drink() # 在喝东西啊

# p = Person() 运行时抛异常

继承了抽象类,就必须重写抽象类中的抽象方法,否则无法实例化对象,并抛异常。

应该尽量避免多继承

如果出现多继承,那么对于同名抽象方法,哪个继承类靠前就是实现的哪个类的抽象方法。

这对于抽象方法来说没什么意义。

但是!

由于抽象类不止能写抽象方法,还可以写属性、类方法、静态方法、普通方法,这些方法如果同名,就是按继承顺序来继承和重写的了。

class A(metaclass=ABCMeta):

num = 10

def __init__(self):

print("这是A的构造方法")

@abstractmethod

def show(self):

pass

@classmethod # 可以定义类方法

def eat(cls):

print("吃 1")

@staticmethod

def drink(): # 可以定义静态方法

print("喝 1")

def sleep(self): # 可以定义普通方法

print("睡 1")

class B(metaclass=ABCMeta):

num = 20

def __init__(self):

print("这是B的构造方法")

@abstractmethod

def show2(self):

pass

@classmethod # 可以定义类方法

def eat(cls):

print("吃 2")

@staticmethod

def drink(): # 可以定义静态方法

print("喝 2")

def sleep(self): # 可以定义普通方法

print("睡 2")

class C(B, A):

def show(self):

print("showA")

def show2(self):

print("showB")

c = C()

# 在打印20前,先打印了 这是B的构造方法 但是没有打印 这是A的构造方法

print(c.num) # 20

c.show() # showA

c.eat() # 吃 2

c.drink() # 喝 2

c.sleep() # 睡 2

c.show2() # showB

抽象类中可以写构造方法,但是子类继承时只会调用第一个继承类的构造方法。

抽象类方法和抽象静态方法

class A和class B中增添这两个方法

@classmethod

@abstractmethod

def swim(cls): # 抽象 类方法

pass

@staticmethod

@abstractmethod

def run(): # 抽象 静态方法

pass

与抽象方法一样,方法体可以不写,能写,但没必要。

子类必须实现这两个方法才能实例化。

不过!

子类实现后,就是普通方法了。与普通抽象方法的实现没啥区别。

class C(B, A):

def show(self):

print("show")

def swim(self):

print("swim")

def run(self):

print("run")

# 不能这样永类名调用

C.swim()

C.run()

所以还要在实现的方法上加对应的装饰器。

@classmethod

def swim(cls):

print("swim")

@staticmethod

def run():

print("run")

然而这时写反装饰器(不按抽象类中的来),也不会有啥事。

所以说抽象类只保证了抽象类本身不能实例化,和子类必须实现与抽象的方法(抽象方法、抽象类方法、抽象静态方法)同名的方法。

但是不保证子类的实现方法和原抽象的方法是同种类型。

简单来说,只要子类有同名的方法就行,管它是不是为了实现抽象的方法的,还是自己本身独有的。

抽象“属性”

Python中有个个特殊的装饰器@property。用了它,方法就可以当属性一样用(调用时不需要加(),直接.属性名)

@property

@abstractmethod

def age(self): # 抽象属性

pass

但是在实现时也必须要加上@property,否则也就当成普通方法了。

@property

def age(self):

print("age")

return 22

print(c.age) # 先打印 22 再打印 age

print(type(c.age)) #

c.age = 30 # 这样会抛异常,只读不能修改

print(c.age)

这个属性是只读的,不能修改。

当然可以配合@X.setter和@X.deleter来使得该“抽象”属性可读可写可删除。(其中X是@property修饰的方法的方法名)

这里不演示了,有兴趣的可以去查看@property/@X.setter/@X.deleter三个装饰器的使用情况和方法。

也一定要注意子类中实现时,对应也要加上装饰器修饰,否则会被当成普通方法。

使用抽象类的好处

对于一些有相似属性和方法类,可以统一把这些属性和方法抽出来放在一个类中。

这样可以很好的理清类直接的继承关系、方法属性的意义、做到了解耦合。

比如说,猫和狗都是动物,都有年龄、性别等属性、都有吃喝拉撒睡等动作(假设这些共有动作两者是不同的)。那么就可以把这些属性和动作抽出来放在一个动物类中(class Animal)。让猫类(class Cat)和狗类(class Dog)都继承这个动物类,然后根据自身特点实现这些属性和动作即可。

其实如果动作相同的话就没必要写成抽象方法,而是写成普通方法即可,这样不需要重写方法,直接调用就行。

抽象就是一种规范,让继承了 抽象类 后的子类必须实现抽象方法才能够实例化。

接口?

Python中没有接口的概念,但是鉴于Java的接口理念,Python可以用abc模块像实现抽象类那样,来实现接口类。

只要在类中只写抽象的方法、static和final属性(用@property等和@staticmethod配合着使用),那么就可以。

当然肯定没有Java中那么严格的检验,不过也勉强能做到。

但最终还是用看开发的需求来决定是否要这样去写,不能为了炫技而去写一些只能自己才能看懂的代码啊,那就失去了编程的初衷了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值