• Day 5-8 自定义元类控制类的实例化行为


    __call__方法:

    对象后面加括号,触发执行。

    注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

     1 class Foo:
     2 
     3     def __init__(self):
     4         pass
     5 
     6 
     7     def __call__(self, *args, **kwargs):  # 在类中,使用__call__方法,表示实例化的对象可以被调用,也可以传参数进来.
     8         print(args)
     9         print(kwargs)
    10 
    11 
    12 
    13 
    14 obj = Foo()  #obj是由Foo类实例化得来的.那么Foo也是可以被调用的.那么Foo的类的内部也应该有一个__call__的方法.
    那么Foo的类是元类type,那么type内部肯定也有一个__call__方法
    15 16 #Foo是由元类实例化得来的,所以元类内部也有一个__call__方法,会在调用Foo的时候触发执行 17 #Foo(1,2,3)等价于 Foo__call__(Foo,1,2,3) 18 obj(1,2,3,x=99,y=100) # 传参到__call__方法中,相当于obj.__call__(obj, 1,2,3,x=99,y=100)
    打印输出: (1, 2, 3) {'x': 99, 'y': 100}

    自定义元类控制类的实例化行为:

     1 class Mymeta(type):  # 继承默认元类的一堆属性
     2     def __init__(self,class_name, class_body, class_dic):
     3         if not class_name.istitle():
     4             raise TypeError("类名首字母必须大写!")
     5 
     6         if "__doc__" not in class_dic or not class_dic["__doc__"].strip():
     7             raise TypeError("必须有注释,且注释不能为空!")
     8 
     9         super().__init__(class_name, class_body, class_dic)
    10 
    11 
    12     def __call__(self, *args, **kwargs):#Chinese.__call__(Chinese,"jack",18)
    13         # print("__call__ in Mymeta")
    14         print(self)     # Chinese
    15         print(args)     # "jack",18
    16         print(kwargs)   #{}
    17         #实际上是在__call__做了3件事
    18         #1.创建一个空对象
    19         obj = object.__new__(self) # self =Chinese
    20         #2.初始化对象
    21         self.__init__(obj, *args, **kwargs)
    22         #3.返回对象
    23         return obj
    24 
    25 
    26 
    27 class Chinese(object, metaclass=Mymeta):
    28     """
    29     休息休息
    30     """
    31     def __init__(self, name, age):
    32         self.name = name
    33         self.age = age
    34 
    35     def tell(self):
    36         print("name:%s,age:%s" % (self.name, self.age))
    37 
    38 
    39 
    40 
    41 obj1 = Chinese("jack",18) # Chinese.__call__(Chinese,"jack",18) 相当于调用mymeta下的__call__方法.

    单例模式:

     1 # 单例模式
     2 
     3 
     4 class MySql:
     5     __instance =None
     6     def __init__(self):
     7         self.host = "127.0.0.1"
     8         self.port = "3306"
     9 
    10 
    11     @classmethod
    12     def singeton(cls):
    13         if not cls.__instance :  # 检测如果__instance没有值.为None!如果一个对象中的元素是None,not 对象,则返回False
    14             # print("s",cls.__instance)
    15             obj =cls()          # 就实例化一个对象
    16             cls.__instance =obj # 把实例化对象的值赋给cls__instance
    17         return cls.__instance
    18 
    19 sql1 = MySql.singeton()
    20 sql2 = MySql.singeton()
    21 print(sql1 is sql2)
    22 print(id(sql1))
    23 print(id(sql2))
    24 """
    25  # 由于sql1和sql2都是由MySql实例化得来的,而且它们的参数都是一样的.这样实例化对象,太浪费内存空间了.
    我们之前学过a = 1, b =a
    26 其实a,b都指向了1的内存地址.那么我们在实例化相同参数的对象时,也可以使用这种方法.
  • 相关阅读:
    在JBuilder8中使用ANT
    协程初探
    JavaScript编写了一个计时器
    Codeforces Round #272 (Div. 1)D(字符串DP)
    UI測试内容
    我为什么做程序猿訪谈录
    使用Java高速实现进度条
    做web项目时对代码改动后浏览器端不生效的应对方法(持续更新)
    将markdown格式转化为bootstrap风格html
    char* 和char[]的差别
  • 原文地址:https://www.cnblogs.com/lovepy3/p/9011827.html
Copyright © 2020-2023  润新知