1 2 3 4

类的内置方法(魔法方法) 单例模型

类的内置方法(魔法方法)

凡是在类内部定义的,以——开头——结尾的方法,都是类的内置方法,也称之为魔法方法。

会在某种条件下满足自动触发。

——init——触发前,调用该类时,内部会通过——new——产生一个新的对象。

——init——:在调用类时自动触发,通过产生的对象自动调用——init——()(**——new——产生的新的对象 ,触发了——init——调用)

1——init—— 和——new——的用法

class Demo(object):##这个里面的object就是一个新式类 父类

    # 在调用类时触发
    def __init__(self):
        print('在调用类时触发... ')
 # Demo()  调用类
 #####在调用类时触发... 
       # 条件__new__:在__init__触发前,自动触发。
      def __new__(cls, *args, **kwargs):
            print('此处是__new__方法的执行')
        # python内部通过object调用内部的__new__实现产生一个空的对象,然后再去执行__init__
        return object.__new__(cls, *args, **kwargs)

# Demo()
###此处是__new__方法的执行
###在调用类时触发... 

2.——getattr——

class Demo:

    #在“对象.属性”获取属性的时候,如果没有'属性'时触发
    def __getattr__(self, item):##这个是属性名
        print('此处是__getattr__方法的执行')
        print(item)
        return 123

obj = Demo()
print(obj.x)
>>>>>>>>>>>>>>>>>>
此处是__getattr__方法的执行
x
123
如果obj.x = 2
print(obj.x)
最后的结果就是
2###return的结果会被改为2   但是属性print值就不会触发 

3.——getattribute——

class Demo:
    #__getattribute__:在“对象.属性”获取属性的时,无论属性有或者没有
    #都会触发
    y = 12
    def __getattribute__(self,item):
        print(item,'----要打印的东西') #item指的是变量名
        
        #如下面的例子,此处不能通过对象.属性 ,否则会产生递归,程序崩溃,
        # print(self.__dict__)
        # return self.__dict__[item]
        # return self.__dict__[item]


obj = Demo()
# obj.x
obj.y = 2
print(obj.y,'---打印出值')  ###打印结果都是None
>>>>>>>>>>>>>>>
y ----要打印的东西
None ---打印出值

注意:只要——getattr 和——getattribute 同时存在的数据,只会触发——getattribute——

4.——setattr——

class Demo:
    #只有当“对象.属性 = 属性值”,添加或者修改属性时触发
    def __setattr__(self, key, value):
        print('此处是__setattr__方法的执行')
        print(key,value)
        #下面的情况出现了递归
        # self.key = value
        print(self.__dict__)###打印的是一个空{}
        self.__dict__[key] = value###这个是一个字典{‘x’:30} 把新加的值30放进去obj的名词空间里面,才可以打印的出来

obj = Demo()
obj.x = 2
obj.x = 30
print(obj.__dict__)#打印的是空字典,原来设置属性的时候,会自动触发父类中的__setattr__
#内部为对象添加x属性,值为20,如果把__setattr__删除,obj对象中的属性x 才会存在
>>>>>>>>>>>>>>>>
此处是__setattr__方法的执行
x 2
{}
此处是__setattr__方法的执行
x 30
{'x': 2}
{'x': 30}

5.——call——

class Demo:
    #条件:在调用对象 “对象+()”时触发
    def __call__(self, *args, **kwargs):
        print("此处是__call__方法的执行")
        return [1,2,3,4]

obj = Demo()
res = obj()
print(res)
>>>>>>>>>>>>
此处是__call__方法的执行
[1, 2, 3, 4]

6.——str——

class Demo:
    #条件:在打印对象时触发
    #该方法必须有一个字符串的返回值
    def __str__(self):
        print('此处是__str__的方法执行')
        return '111'

obj = Demo()
print(obj)
>>>>>>>>>>>>
此处是__str__的方法执行
111

7.——getitem——

class Demo:
    #在对象通过“对象[key]”获取属性时触发
    def __getitem__(self, item):
        print('此处是__getitem__的方法执行')
        print(item)
        return self.__dict__[item]###这个是一个字典
obj = Demo()
obj.x = 2
print(obj['x'])
>>>>>>>>>>>>>>>>>
此处是__getitem__的方法执行
x
2

单例模型

定义:指的是在确定“类中的属性和方法”不变时,需要反复调用类,产生不同的对象,会产生不同的内存地址,造成资源的浪费。

让所有的类实例化,指向同一个内存地址,称之为单例模式------->无论产生多少个内存对象,都会指向一个实例。

class Foo:
    def __init__(self,x,y):
        self.x = x
        self.y = y
foo_obj1 = Foo(10,20)
print(foo_obj1.__dict__)
print(foo_obj1)

foo_obj2 = Foo(20,30)
print(foo_obj2.__dict__)
print(foo_obj2)
##foo_obj1 和foo_obj2 的内存空间的地址不一样
>>>>>>>>>>>>>>>
{'x': 10, 'y': 20}
<__main__.Foo object at 0x000002B4F12BF2E8>
{'x': 20, 'y': 30}
<__main__.Foo object at 0x000002B4F12BF400>

单例模式

1.通过classmethod

2.通过装饰器

3.通过——new——实现

4.通过元类实现

5.通过模块实现


 方式一: classmethod
class Singleton1:

    __instance = None

     @classmethod
    def singleton(cls):

         if not cls.__instance:
             cls.__instance = cls() #第一次产生一个obj时 走这个if判断,会把这个__instance附一个值是obj 下次 类再产生对象时 ,因为__instance已经有值了 这个if就不会走了 直接把这之前的obj返回出去,这样就保证了一致性。

         return cls.__instance
obj1 = Singleton.singleton()
obj2 = Singleton.singleton()
print(obj1)
print(obj2)

#这个是复杂的一点的方法
setting中的值
HOST = '180.101.49.12'
PORT = 443

import setting
class MySQL:
    #一个默认的值,用于判断对象是否存在,对象不存在证明值是None
    #—__instance 是类的属性,可以用类来调用
    __instance = None
    def __init__(self,host,port):
        self.host = host
        self.port = port

    @classmethod
    def singleton(cls,host,port):##单例的类方法
        #判断__instance中若没有值,证明没有对象
        if not cls.__instance:
            #产生一个对象并返回
            obj = cls(host,port)
            #
            cls.__instance = obj
        #若__instance 中有值,证明对象存在,则直接返回该对象
        return cls.__instance

    def start_mysql(self):
        print('启动mysql')

    def close(self):
        print('关闭mysql')

obj1 = MySQL.singleton(setting.HOST,setting.PORT)
print(obj1)

obj2 = MySQL.singleton(setting.HOST,setting.PORT)
print(obj2)
>>>>>>>>>>>>>>>>>>>>
<__main__.MySQL object at 0x0000019B5F8FFF60>######现在这个内存地址就是一样了
<__main__.MySQL object at 0x0000019B5F8FFF60>

通过模块实现

#模块 demo
class Singleton:
    pass

obj = Singleton()

#下面的是另外一个py模块的调用(在同一个py页里面)
from demo import obj
print(obj)

from demo import obj
print(obj)
>>>>>>>>>>>>>>>>
<demo.Singleton object at 0x000001E1463044E0>
<demo.Singleton object at 0x000001E1463044E0>

通过装饰器

#用装饰器的方法
def singleton(cls):
    __instance = {} ##这个字典是一个可变的类型,我每次往里面的值obj发生改变 这个的内存地址都不会变,所以是打印出来的内存地址都是一样的

    def inner(*args, **kwargs):
        if cls not in __instance:
            obj = cls (*args,**kwargs)
            __instance[cls] = obj

        return __instance[cls]
    return inner

@singleton
class Father:
    pass
print(Father())
print(Father())
>>>>>>>>>>>>>
<__main__.Father object at 0x0000019FDD15F518>
<__main__.Father object at 0x0000019FDD15F518>

通过__new__ d的方法

class Singleton2:
    __instance  = None

    def __new__(cls,*args,**kwargs):###这个是重写了父类的--new-- 父类里面的还是存在的,只是这个用于 调用--new--的方法 会先从类中查找,因为类中重写了 ,有。
            cls.__instance = object.__new__(cls)
        return cls.__instance
obj1 = Singleton2()
print(obj1)
obj2 = Singleton2()
print(obj2)
>>>>>>>>>>>>>>
<__main__.Singleton2 object at 0x0000023C04EFF518>
<__main__.Singleton2 object at 0x0000023C04EFF518>
posted @ 2019-12-05 20:24  ^更上一层楼$  阅读(239)  评论(0编辑  收藏  举报