029_Python知识点_面向对象进阶_元类&抽象基类&自省机制&slots

1. 元类

1.1 理解类、对象

Python中一切皆对象。 --> 所以类也是对象 --> 那么,谁创建了类? --> 元类
元类:类的类,也就是类的模板。元类的实例为类,正如类的实例为对象。

  • 分支语句动态创建类:结合分支语句等,使用class关键字动态的创建类。当使用class关键字时,Python解释器自动创建这个对象。
  • type函数动态创建类:
    • type函数功能一:判断对象的类型。–> eg:type('abc')
    • type函数功能二:动态的创建类。type可以接受一个类的描述作为参数,然后返回一个类。
# type函数创建类:
# 语法:type(函数名, (父类, ), {属性, 函数, ...})
def hello():
    print("--hello--")

myclass = type("MyClass", (object, ), {'my_args': 'haha', 'hello': hello})
print(myclass.my_args)
myclass.hello()

1.2 元类的使用场景

元类的使用:

  1. 拦截类的创建
  2. 修改类
  3. 返回修改之后的类

动态生成类,不能控制类是如何生成的。python3 的metaclass可动态创建类。
4). 很多Web框架都会使用metaclass 来创建类。掌握元类对理解源代码至关重要。eg: ORM框架类

应用:自定义元类实现单例模式

class Singleton(type):
    """自定义元类实现单例模式"""
    cache = {}
    def __call__(cls):
        if cls not in cls.cache:
            cls.cache[cls] = super(Singleton, cls).__call__()
        return cls.cache[cls]

class Person(object, metaclass=Singleton):  # metaclass一个指定元类的参数
    pass

if __name__ == '__main__':
	# 注意:Person是Singleton元类实例化出的对象, Person()就是对象(), 执行Singleton.__call__魔术方法.
    p1 = Person()
    p2 = Person()
    print("单例模式是否成功:", p1 is p2)

2. 抽象基类

抽象基类有两个特点:

  1. 规定继承类 (子类) 必须具有抽象基类中指定的方法,即用@abc.abstractmethod装饰的方法
  2. 抽象基类无法实例化

基于上述两个特点,抽象基类主要用于接口设计
实现抽象基类可以使用内置的abc模块
代码示例:

import abc

class Human(metaclass=abc.ABCMeta):
    # 该装饰器规定:继承抽象类的子类在定义时必须要定义的抽象方法
    @abc.abstractmethod
    def introduce(self):
        print("__抽象类__")
	
	# 因为没有@abc.abstractmethod装饰器,在子类中hello方法不是必须的
    def hello(self):
        print("__hello__")

class Person(Human):
    # 1. 规定子类中必须具有抽象基类指定的方法
    def introduce(self):
        print("__子类__抽象类__")

# 2. 抽象基类无法实例化
# TypeError: Can't instantiate abstract class Human with abstract methods introduce
# h = Human()

p = Person()
p.introduce()

3. 自省机制

自省机制:

  1. 在日常生活中,自省 (introspection) 是一种自我检查行为。
  2. 在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力。
  3. 例如Python、Ruby、object-C、C++都有自省的能力,这里面的C++的自省的能力最弱,只能够知道是什么类型,而像Python可以知道是什么类型,还有什么属性。

Python中常见的自省机制:
函数用法有: dir()、type()、hasattr(),、setattr()、getattr()、delattr()、isinstance(),通过这些函数,我们能够在程序运行时得知对象的类型,判断对象是否存在某个属性,访问对象的属性。

>>> s = "abc"
# 1. 查看 s 的全面属性和方法
>>> dir(s) 
['__add__',
 '__class__',
 '__contains__',
 '__delattr__',
 ...
 'translate',
 'upper',
 'zfill']
 
 # 2. 返回对象类型
>>> type(s)
str

 # 3. 判断对象类型,返回bool值
>>> isinstance(s, str)
True

>>> def hello():
   ...:     pass
# 4. 设置对象属性,如 hello.name = 'xiaohong'
>>> setattr(hello, "name", "xiaohong")

# 5. 判断对象中是否包含某个属性,返回bool值
>>> hasattr(hello, "name")
True

# 6. 获取对象中的某个属性值
>>> getattr(hello, "name")
'xiaohong'

# 7. 删除对象中的某个属性
>>> delattr(hello, "name")
>>> hasattr(hello, "name")
False

4. __slots__

Python是动态语言,动态语言与静态语言的不同之处是:

  1. 动态语言:可以在运行的过程中,修改代码
  2. 静态语言:编译时已经确定好代码,运行过程中不能修改

如何要限制实例中的属性

  1. Python允许在定义class的时候,定义一个特殊的 __slots__变量,来限制该class实例能添加的属性。
  2. 使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的

代码示例:

import time

class Date(object):
	# 限制示例中能够添加的属性有:'__year', '__month', '__day'
    __slots__ = '__year', '__month', '__day'

    def __init__(self, year, month, day):
        self.__year = year
        self.__month = month
        self.__day = day

    @property
    def year(self):
        return self.__year

    @property
    def month(self):
        return self.__month

    @property
    def day(self):
        return self.__day

    @classmethod
    def today(cls):
        time_tuple = time.localtime()
        return cls(time_tuple.tm_year, time_tuple.tm_mon, time_tuple.tm_mday)  # 返回实例化对象

    def __str__(self):
        return "%s-%s-%s" % (self.year, self.month, self.day)


if __name__ == '__main__':
    date = Date(2020, 1, 4)
    print("date数据类型: ", type(date))
    print("date有year属性吗?", hasattr(date, "year"))
    print("date有time属性吗?", hasattr(date, "time"))
    # setattr(date, "time", "2020-11-11") # AttributeError: 'Date' object has no attribute 'time'
    # print(getattr(date, "time"))
    today = date.today()
    print("today数据类型: ", type(today))
    # print("今天是%s年%s月的第%s天" % (today.year, today.month, today.day))
    print(today)

执行结果:
在这里插入图片描述

发布了37 篇原创文章 · 获赞 0 · 访问量 5310

猜你喜欢

转载自blog.csdn.net/qq_21156327/article/details/103898839