Python核心技术与实战学习笔记(七):Python中的面向对象

7.1 Python类中的各种变量与函数

class Document():
    
    WELCOME_STR = 'Welcome! The context for this book is {}.'
    
    def __init__(self, title, author, context):
        print('init function called')
        self.title = title
        self.author = author
        self.__context = context
    
    # 类函数
    @classmethod
    def create_empty_book(cls, title, author):
        return cls(title=title, author=author, context='nothing')
    
    # 成员函数
    def get_context_length(self):
        return len(self.__context)
    
    # 静态函数
    @staticmethod
    def get_welcome(context):
        return Document.WELCOME_STR.format(context)


empty_book = Document.create_empty_book('What Every Man Thinks \
About Apart from Sex', 'Professor Sheridan Simove')


print(empty_book.get_context_length())
print(empty_book.get_welcome('indeed nothing'))

########## 输出 ##########

init function called
7
Welcome! The context for this book is indeed nothing.
  • 类常量:类内函数外定义的常量,它可以让每个对象都直接访问而不需要重新构造。如上述代码的WELCOME_STR
  • 类函数:能访问和修改对象的属性,第一个参数为cls,表示必须传一个类进来。类函数最常用的功能是实现不同的init构造函数。如上述代码中,使用 create_empty_book类函数创造新的书籍对象,其 context一定为 ‘nothing’。这样的代码,就比直接构造要清晰一些。类函数需要装饰器 @classmethod 来声明。
  • 成员函数:能访问和修改对象的属性,第一个参数为self,代表当前对象的引用。
  • 静态函数:与类没有关联,它的第一个参数没有什么特殊性(类函数是cls,成员函数是self)。一般静态函数用于完成一些简单独立的任务,既方便测试,也能优化代码结构。静态函数可以通过在代码前一行加@staticmethod修饰器表示

7.2 继承

示例代码如下:

class Entity(): 
    def __init__(self, object_type):
        print('parent class init called')
        self.object_type = object_type
    
    def get_context_length(self):
        raise Exception('get_context_length not implemented')
    
    def print_title(self):
        print(self.title)

class Document(Entity):
    def __init__(self, title, author, context):
        print('Document class init called')
        Entity.__init__(self, 'document')
        self.title = title
        self.author = author
        self.__context = context
    
    def get_context_length(self):
        return len(self.__context)
    
class Video(Entity):
    def __init__(self, title, author, video_length):
        print('Video class init called')
        Entity.__init__(self, 'video')
        self.title = title
        self.author = author
        self.__video_length = video_length
    
    def get_context_length(self):
        return self.__video_length

harry_potter_book = Document('Harry Potter(Book)', 'J. K. Rowling',\
 '... Forever Do not believe any thing is capable of thinking independently ...')
harry_potter_movie = Video('Harry Potter(Movie)', 'J. K. Rowling', 120)

print(harry_potter_book.object_type)
print(harry_potter_movie.object_type)

harry_potter_book.print_title()
harry_potter_movie.print_title()

print(harry_potter_book.get_context_length())
print(harry_potter_movie.get_context_length())

########## 输出 ##########

Document class init called
parent class init called
Video class init called
parent class init called
document
video
Harry Potter(Book)
Harry Potter(Movie)
77
120

在继承中,需要注意的有:

  • 构造函数:每个类都有构造函数,子类在生成对象时,是不会自动调用父类的构造函数的,因此必须在子类的构造函数中显式调用父类的构造函数。它们的执行顺序是:子类的构造函数—>父类的构造函数。如上述代码的在子类的构造函数中的Entity.init(self, ‘document’)
  • 父类 get_context_length() 函数中,直接raise Exception,这使得父类实例化的对象调用该函数时会直接返回错误。这是一种比较好的写法,使得子类必须重写该方法。(这种写法适合针对父类中少量有重写要求的函数,若父类中的所有函数我们都想让子类重写的话,那么使用抽象类更方便)
  • 父类中没有重写要求的函数,则可直接用子类对象进行调用即可,而且也不需要在子类中显式声明。这降低了系统的熵值。

7.3 抽象函数和抽象类

示例代码:

from abc import ABCMeta, abstractmethod

class Entity(metaclass=ABCMeta):
    @abstractmethod
    def get_title(self):
        pass

    @abstractmethod
    def set_title(self, title):
        pass

class Document(Entity):
    def get_title(self):
        return self.title
    
    def set_title(self, title):
        self.title = title

document = Document()
document.set_title('Harry Potter')
print(document.get_title())

entity = Entity()

########## 输出 ##########

Harry Potter

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-266b2aa47bad> in <module>()
     21 print(document.get_title())
     22 
---> 23 entity = Entity()
     24 entity.set_title('Test')

TypeError: Can't instantiate abstract class Entity with abstract methods get_title, set_title

在7.2中的示例代码中,父类 get_context_length() 函数直接raise Exception使得父类实例化的对象调用该函数时会直接返回错误。这种写法适合针对父类中少量有重写要求的函数,若父类中的所有函数我们都想让子类重写的话,那么使用抽象类更方便。

from abc import ABCMeta, abstractmethod

class Entity(metaclass=ABCMeta):
    @abstractmethod
    def get_title(self):
        pass

    @abstractmethod
    def set_title(self, title):
        pass

上述代码的Entity即为一个抽象类,特点是所有的函数都是抽象函数(用装饰器@abstractmethod表示),不能直接生成对象,否则会报错。

抽象类的作用就是定义一个接口,它是一种自上而下的设计风范,只需用少量的代码描述清楚要做的事情,定义好接口,就可以交给不同的开发人员开发和对接。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值