美文网首页
Python元类及单例设计模式案例解析

Python元类及单例设计模式案例解析

作者: 白码会说 | 来源:发表于2020-11-13 22:04 被阅读0次

Time will tell.

一、元类

元类用于创建类的类。在 python 中,万物皆对象,类当然也是对象。

对象是通过类实例化产生的,如果类也是对象的话,必然类对象也是由另一个类实例化产生的。

class Person:
    pass

p = Person()
print(type(p), type(Person), type(object))
# <class '__main__.Person'> <class 'type'> <class 'type'>
# Person类是通过type类实例化产生的(object类内部是由C语言实现的)

# 直接调用type类来产生类对象(默认情况下所有类的元类都是type)
class Student:
    pass

print(type(Student))
# <class 'type'>

二、类的基本组成

  1. 类的名字(字符类型)
  2. 类的父类们 (是一个元组或列表)
  3. 类的名称空间(字典)

三、元类的目的

可以高度地自定义类,例如控制一个类的名字必须以大驼峰的方式来书写。

类也是对象,也有自己的类。

创建类对象做一些限制

  • 想到了初始化方法,我们只要找到了类对象的类(或者说元类),覆盖其中 init方法就能实现需求。
  • 当然我们不能修改源代码,所以应该继承type来编写自己的元类,同时覆盖 init来完成需求。
'''
只要继承了type, 那么这个类就变成了一个元类

'''

class MyType(type):  # 定义一个元类
    def __init__(self, cls_name, bases, dict):
        print(cls_name, bases, dict)
        # Pig () {'__module__': '__main__', '__qualname__': 'Pig'}
        if not cls_name.istitle():
            raise Exception("好好写类名!")
        super().__init__(cls_name, bases, dict)

    pass

# class pig(metaclass=MyType):  # 为Pig类指定了元类为MyType
    # 直接报错,Exception: 好好写类名!
class Pig(metaclass=MyType):

    pass

# # MyType("pig", (), {})  # Exception: 好好写类名!
print(MyType("Pig", (), {}))
# <class '__main__.Pig'>

元类中的 call 方法

  • 当你调用类对象时,会自动执行元类中的 call方法,并将这个类作为第一个参数传入,以及后面的一堆参数。

  • 覆盖元类中的call之后,这个类就无法产生对象对象无法实例化,必须调用super().call()来完成对象的创建并返回其返回值。

call与 init 的使用场景

  • 想要控制对象的创建过程用 call
  • 想要控制类的创建过程用 init
'''
需求:想要把对象的所有属性变成大写
'''

class MyType(type):
    def __call__(self, *args, **kwargs):
        new_args = [item.upper() for item in args]
        return super().__call__(*new_args, **kwargs)

class Person(metaclass=MyType):  # ---> Person = MyType("Person", (), {})
    def __init__(self, name):
        self.name = name

p = Person('jack')
print(p.name)
# JACK

# 要求创建对象时必须以关键字传参
#   覆盖元类的__call__
#   判断有没有传非关键字参数,有就不行

class MyMeta(type):
    # def __call__(self, *args, **kwargs):
    #     obj = object.__new__(self)
    #     self.__init__(obj, *args, **kwargs)
    #     return obj

    def __call__(self, *args, **kwargs):
        if args:
            raise Exception("非法传参(只能以关键字的形式传参!)")
        return super().__call__(*args, **kwargs)

class MyClass(metaclass=MyMeta):
    def __init__(self, name):
        self.name = name

# my_class_obj = MyClass('123')
# # 报错Exception: 非法传参(只能以关键字的形式传参!)
my_class_obj = MyClass(name='123')
print(my_class_obj)
# <__main__.MyClass object at 0x000002161DD187B8>

一旦覆盖了call必须调用父类的call方法来产生对象并返回这个对象。

补充 new方法

当你要创建类对象时( 类 + () ),会首先执行元类中的 new方法,拿到一个空对象,然后会自动调用 init方法来对这个类进行初始化操作。

class MyMeta(type):
    # def __call__(self, *args, **kwargs):
    #     obj = object.__new__(self)
    #     self.__init__(obj, *args, **kwargs)
    #     return obj
    pass

如果你覆盖了 new方法,则必须保证 new方法必须有返回值,且必须是对应的类对象。

class Meta(type):

    def __new__(cls, *args, **kwargs):
        print(cls)  # 元类自己
        print(args)  # 创建类需要的几个参数  类名,基类,名称空间
        print(kwargs)  # 空的
        print("__new__ run")
        # return super().__new__(cls,*args,**kwargs)  # 等同于下面这句
        obj = type.__new__(cls, *args, **kwargs)
        return obj

    def __init__(self, a, b, c):
        super().__init__(a, b, c)
        print("__init__ run")

class A(metaclass=Meta):
    pass

print(A)
# <class '__main__.Meta'>
# ('A', (), {'__module__': '__main__', '__qualname__': 'A'})
# {}
# __new__ run
# __init__ run
# <class '__main__.A'>

newinit都可以实现控制类的创建过程,但 init更简单。

四、最后来说说单例设计模式

1、设计模式用于解决某种固定问题的套路,如:MVC、MTV…

2、单例指的是一个类只能产生一个对象,可以节省空间。

3、为什么要用单例:

  • 是为了节省空间,节省资源。
  • 当一个类的所有对象属性全部相同时则没有必要创建多个对象。
class Single(type):
    def __call__(self, *args, **kwargs):
        if hasattr(self, 'obj'):  # 判断是否存在已经有了的对象
            return getattr(self, 'obj')  # 有就把那个对象返回

        obj = super().__call__(*args, **kwargs)  # 没有则创建
        print("new 了")
        self.obj = obj  # 并存入类中
        return obj

class Student(metaclass=Single):
    def __init__(self, name):
        self.name = name

class Person(metaclass=Single):
    pass

# 只会创建一个对象
Person() # 只会执行一次
# new 了
Person()
Person()
Person()
Person()
...

好啦,本章内容今天就分享到这里了。如果你还对后续内容感兴趣,或是对Python实例练习题、面试题、自动化软件测试感兴趣的话可以加入我们175317069一起学习。有各项学习资源发放,更有行业深潜多年的测试人技术分析讲解。期待你的加入!

最后祝愿你能成为一名优秀的工程师!

欢迎【评论】、【点赞】、【关注】~

Time will tell.(时间会证明一切)

相关文章

  • Python元类及单例设计模式案例解析

    Time will tell. 一、元类 元类用于创建类的类。在 python 中,万物皆对象,类当然也是对象。 ...

  • 单例模式只有饿汉式和懒汉式吗?这几种单例模式你见过吗

    设计模式之单例模式-单例模式的几种实现方式及小案例 本文出处:凯哥Java(wx:kaigejava) 单例模式有...

  • python单例模式

    Python单例模式 单例模式 单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。...

  • python中OOP的单例

    目录 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • 单例

    目标 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • python 单例

    仅用学习参考 目标 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计...

  • python设计模式 - 单例模式元类

    python 环境 简介 元类是一个类的类,也就是说该类是它的元类的实例。类的定义由它的元类决定,通过元类,程序员...

  • 设计模式之单例模式

    单例设计模式全解析 在学习设计模式时,单例设计模式应该是学习的第一个设计模式,单例设计模式也是“公认”最简单的设计...

  • Python 单例模式

    元类方法__call__ 可以这样使用: 如下: 调用__call__实现python 单例模式 元类继承: 测试:

  • python面试题之单例模式

    python面试题之单例模式 ​单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。...

网友评论

      本文标题:Python元类及单例设计模式案例解析

      本文链接:https://www.haomeiwen.com/subject/ulnbbktx.html