【相关文章】元类和类装饰器以及单例设计模式

一.类装饰器

1.无参类装饰器
class Decorator:
    def __init__(self,m):  # 用来接收外部传进来的函数引用
        self.m=m
    def __call__(self, *args, **kwargs):
        self.m(*args,**kwargs)
        print("涂粉...")
        print('涂口红')
        print('变年轻了')
@Decorator  # girl=Decorator(girl)
def girl():
    print('俺是大妈...')
girl()

执行步骤如下:

  1. girl=Decorator(girl)
  2. 将函数girl的引用传入装饰器中
  3. 后面使用girl()调用这个函数,也就是装饰器中的m()
  4. 记得我们学过,函数也是一种对象,如果我们想要调用函数这个对象,我们必须重写__call__方法;
  5. 重写__call__方法,并且在__call__中进行调用.
2.带参数的装饰器之函数实现
class Decorator:
    def __init__(self,n):
        self.n=n  # 已确定n传进来了
    def __call__(self,f):
        def wrapper(*args, **kwargs):
            r=f(*args, **kwargs)
            print(r)
            print('涂口红')
            print('变年轻了')
        return  wrapper

@Decorator(5)  # girl=Decorator(girl)
def girl(*args, **kwargs):
    print(args,kwargs)
    print('俺是大妈...')
    return '但是:'
girl('hello',m='world')
  1. @Decorator(5)第一次将装饰器的参数通过__init__(self,n)传入类中,让n来接收
  2. 我们现已接收到了装饰器的参数,(记住,这时候没有调用__call__,调用__call__()是通过装饰器的再次装饰而调用的,如果想要调用__call__()方法,必须通过创建对象调用),通过装饰器的再次装饰,创建了一个装饰去decorato()对象,这就调用了__call__()方法,将函数girl的引用传了进来,也就是f.
  3. 为了装饰,我们覆盖魔术方法__call__()并将要装饰的函数通过return wrapper返回出去,girl来接收
  4. 这是girl=wrapper,通过girl(‘hello’,m=‘world’)对wrapper对函数的调用,我们再次进入到wrapper函数中,这次带进来的参数是(‘hello’,m=‘world’).
  5. 调用f函数,将通过wrapper接收到的参数通过函数r=f(*args, **kwargs),接收函数f,也就是要装饰的对象的返回值r
3.带参数的装饰器之类实现
class Decorator:
    def __init__(self,n):
        self.n=n  # 已确定n传进来了
    def __call__(self,func):
        print(func)  # 已经将函数的引用传了进来
        class inner_class:
            def __init__(self,*args,**kwargs):
                print(args)
                print(kwargs)
                self.func=func
            def __call__(self, *args, **kwargs):
                r=self.func(*args, **kwargs)
                print(r)
                print("涂粉...")
                print('涂口红')
                print('变年轻了')
        return  inner_class(func)
        # 将其传出去之后,经过girl('hello',m='world'),创建了内部类inner_class的对象,
        # 通过__init__()接收参数,通过__call__()调用新创建的这个对象(只有实现__call__方法,对象才能像函数一样调用)
@Decorator(5)  # girl=Decorator(girl)
def girl(*args, **kwargs):
    print(args,kwargs)
    print('俺是大妈...')
    return '但是:'
girl('hello',m='world')

二.元类

1.什么是元类

元类就是创建类的类,它是所有类的鼻祖(包括object),int是用来创建整型对象的,str是用创建字符对象的,而type是用来创建类对象的(包括整型,字符型等,我说的是一切对象,python中一切皆对象中的对象),元类就是创建类对象这种东西的.type是python的内建函数,如果把类比作模板,那么元类就是创建模板的东西.

2.初学一段话
元类被称为 Python 中的“深奥的巫术”。尽管你需要用到它的地方极少(除非你基于 zope 编程),可事实上它的基础理论其实令人惊讶地易懂。

一切皆对象
一切都有类型
 “class”和“type”之间本质上并无不同
类也是对象
它们的类型是 type
以前,术语 type 用于内置类型,而术语 class 用于用户定义的类,但自 Pythoon 2.2 以来“class”和“type”本质上并无不同。

对于旧风格(old-style)类的类型是 types.ClassType

类的类是……

它的元类……

就像对象是类的实例一样,类是它的元类的实例。

调用元类可以创建类。

确切来说,Python 中的其它对象也是如此。

因此当你创建一个类时……

解释器会调用元类来生成它……

定义一个继承自 object 的普通类意味着调用 type 来创建它:
3.type内建函数
  1. 类是对象的类,类的类是type(包括object),默认元类是type
    使用底层的东西(内建函数type)创建一个类
class A(object):
    num = 100

def print_b(self):
    print(self.num)

@staticmethod
def print_static():
    print("----haha-----")

@classmethod
def print_class(cls):
    print(cls.num)

B = type("B", (A,), {"print_b": print_b, "print_static": print_static, "print_class": print_class})
b = B()
b.print_b()
b.print_static()
b.print_class()
  1. 用法
    1]type(对象)–>返回当前对象的类型
    2]type(name,bases,attrs) ----> name类名,bases:tuple保存所有的父类,attrs{}字典,类中的所有属性,所有的类底层都是经过type构建出来的,我们现在就可以自定义一个元类
    3]自定义元类
class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        print(name)
        print(bases)
        print(attrs)
        attrs['b'] = 'world'
        if attrs.get('test'):
            attrs.pop('test')
        return type.__new__(cls, name, bases, attrs)

class MyList(object, metaclass=ListMetaclass):
    a = 'hello'

    def test(self):
        print('---->test')


l = MyList()
print(MyList.__dict__)
print(l)
print(l.a)
# print(l.b)
# l.test()

元类就是类的类,默认是type,所有的类都要经过type,但是我们可以自定元类,就像所有类的父类都是object一样,默认是object,但我们可以更改它

4.元类的作用
  1. 拦截类的创建
  2. 修改类
  3. 返回修改之后的类
5.__metaclass__属性

你可以在定义一个类的时候为其添加__metaclass__属性。

class Foo(object):
    __metaclass__ = something…
    pass

如果你这么做了,Python就会用元类来创建类Foo。小心点,这里面有些技巧。你首先写下class Foo(object),但是类Foo还没有在内存中创建。Python会在类的定义中寻找__metaclass__属性,如果找到了,Python就会用它来创建类Foo,如果没有找到,就会用内建的type来创建这个类。把下面这段话反复读几次。

class Foo(Bar):
    pass

Python做了如下的操作:

  1. Foo中有__metaclass__这个属性吗?如果是,Python会通过__metaclass__创建一个名字为Foo的类(对象)
  2. 如果Python没有找到__metaclass__,它会继续在Bar(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。
  3. 如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。
  4. 如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象。
  5. 现在的问题就是,你可以在__metaclass__中放置些什么代码呢?答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者任何使用到type或者子类化type的东东都可以。

三.单例设计模式

1.学前一席话

单例是一种 设计模式 ,应用该模式的类只会生成一个实例。
单例模式保证了在程序的不同位置都 可以且仅可以取到同一个对象实例 :如果实例不存在,会创建一个实例;如果已存在就会返回这个实例。
因为单例是一个类,所以你也可以为其提供相应的操作方法,以便于对这个实例进行管理。
举个例子来说,比如你开发一款游戏软件,游戏中需要有“场景管理器”这样一种东西,用来管理游戏场景的切换、资源载入、网络连接等等任务。
这个管理器需要有多种方法和属性,在代码中很多地方会被调用,且被调用的必须是同一个管理器,否则既容易产生冲突,也会浪费资源。
这种情况下,单例模式就是一个很好的实现方法。
单例模式广泛应用于各种开发场景,对于开发者而言是必须掌握的知识点,同时在很多面试中,也是常见问题。

2.实现单例实现之__new__()魔术方法
class Person:
    __instance = None

    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = object.__new__(cls, *args, **kwargs)
        return cls.__instance

    def __init__(self):
        print('---->init')

p1 = Person()
p2 = Person()
p3 = Person()

print(id(p1))
print(id(p2))
print(id(p3))
3.单例模式实现之函数装饰器实现
def func_decorator(cls):
    _instance = {}

    def wrapper(*args, **kwargs):
        if cls not in _instance:
            _instance[cls] = cls()
        return _instance[cls]

    return wrapper


@func_decorator  # 1.cls = cls_decorator()  2. Singleton = cls
class Singleton:
    def __init__(self):
        print('---->Singleton init')


print(Singleton)
s1 = Singleton()  # cls()
s2 = Singleton()

print(s1 is s2)
4. 单例模式实现之类装饰器实现
class cls_decorator:
    def __init__(self, f):
        self.f = f
        self.__instance = {}

    def __call__(self, *args, **kwargs):
        if self.f not in self.__instance:
            self.__instance[self.f] = self.f()  # self.f = Singleton   Singleton()
        return self.__instance[self.f]  # {'Singleton':<Singleton object at 0x00000000022205F8>}
       
 @cls_decorator  # 1.cls = cls_decorator()  2. Singleton = cls
class Singleton:
    def __init__(self):
        print('---->Singleton init')


print(Singleton)
s1 = Singleton()  # cls()
s2 = Singleton()
print(s1 is s2)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 单例模式是一种软件设计模式,其目的是保证一个只有一个实例,并提供一个全局访问点来访问这个实例。 在 Python 中,可以使用装饰器实现单例模式。装饰器是一种特殊的装饰器,它可以在定义时使用,用于修改的行为。 下面是使用装饰器实现单例模式的示例代码: ``` def singleton(cls): instance = None def wrapper(*args, **kwargs): nonlocal instance if instance is None: instance = cls(*args, **kwargs) return instance return wrapper @singleton class MyClass: pass ``` 在上面的代码中,`singleton` 是一个装饰器,它接受一个作为参数,并返回一个内部函数 `wrapper`。`wrapper` 函数检查是否已经创建了的实例,如果没有,就创建一个新的实例,并将其保存在 `instance` 变量中。如果已经创建了实例,就直接返回该实例。 使用装饰器实现单例模式时,可以使用 `nonlocal` 声明来修改内部函数中的局部变量,这样就可以在多次调用 `wrapper` 函数时保存的实例。 使用装饰器实现单例模式后,就可以像调用普通一样调用单 ### 回答2: Python单例模式可以通过使用装饰器实现装饰器可以在原始上添加额外的功能,比如只实例化一个对象。 下面是一个使用装饰器实现Python单例模式的例子: ```python def singleton(cls): instances = {} def wrapper(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return wrapper @singleton class MyClass: def __init__(self, x): self.x = x # 测试 obj1 = MyClass(10) obj2 = MyClass(20) # obj1 和 obj2指向同一个对象 print(obj1.x) # 输出 10 print(obj2.x) # 输出 10 print(obj1 is obj2) # 输出 True ``` 在这个例子中,我们定义了一个名为singleton的装饰器函数。singleton函数接受一个作为参数,并返回一个新的封装函数wrapper。wrapper函数在被调用时会首先检查是否已经存在该的实例,如果不存在则创建一个新的实例并保存在字典instances中,然后返回该实例。这样,每次创建新的对象时都会先检查是否已经有了同样的实例,如果有则返回之前的实例,实现单例模式。 我们的示例中,我们定义了一个名为MyClass的,并在其上应用了singleton装饰器。这样,无论我们创建多少个MyClass的实例,它们都会指向同一个对象,因为只有第一次创建时实际上调用了MyClass的构造函数,后续创建都直接返回了之前的实例。 使用装饰器实现Python单例模式可以简化代码,并且保证了只有一个实例存在。这对于需要限制实例数量的场景非常有用。 ### 回答3: Python单例模式是一种设计模式,用于确保一个只有一个实例,并提供一个全局访问点。 使用装饰器实现Python单例模式是一种常见的方法。装饰器一个接受作为参数并返回修改后的的函数。 下面是一个使用装饰器实现Python单例模式的例子: ```python def singleton(cls): instances = {} def wrapper(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return wrapper @singleton class MyClass: def __init__(self, name): self.name = name def say_hello(self): print("Hello, I am", self.name) # 创建实例 obj1 = MyClass("Object 1") obj2 = MyClass("Object 2") # 打印实例的名称 print(obj1.name) # Output: Object 1 print(obj2.name) # Output: Object 1 # 调用实例的方法 obj1.say_hello() # Output: Hello, I am Object 1 obj2.say_hello() # Output: Hello, I am Object 1 ``` 在上述例子中,`singleton` 是一个装饰器函数。当我们在 `MyClass` 上使用 `@singleton` 时,`singleton(MyClass)` 被调用并返回一个新的 `wrapper`。在这个新的 `wrapper` 中,我们使用 `instances` 字典来存储已经创建的实例。在 `wrapper` 的构造函数中,我们首先检查 `cls` 是否已经在 `instances` 中,如果没有,则创建一个新的实例并将其添加到 `instances` 中。最后,我们返回 `instances[cls]`,即返回已经创建的实例。 通过使用装饰器实现Python单例模式,我们可以确保在程序运行时只有一个实例存在,并且可以通过任何地方访问该实例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值