python基础--类竟然还可以这样创建!

传统类的创建

'''单例模式的类'''
class MySingleton:
    __obj = None
    __init_flag = True
    def __new__(cls, *args, **kwargs):
        if cls.__obj  == None:
            cls.__obj = object.__new__(cls)
            '''
            如果是return cls,则返回这个类的一个实例
            这里调用的是实例的私有变量__obj,即返回None
            '''
            return cls.__obj

    def __init__(self,name):
        if MySingleton.__init_flag:
            print("init...")
            self.name = name
            MySingleton.__init_flag = False
  
#a = MySingleton("aa")#只能够调用一次,调用后出触发初始化flag,使得__new__返回一个空的object类
#print(a)
#b = MySingleton("bb")
#print(b)

通过type创建类

type创建类的格式:类名 = type(‘类名’,(父类,),{‘方法名’:方法的内存地址})

def func(self):  #创建方法
    print("hello {0}".format(self.name))

>>> A=type("A",(MySingleton,),{"talk":func})
>>> a=A("test")
init...
>>> a.talk()
hello test

>>> B=type("B",(object,),{"talk":func})
>>> b=B("test")
>>> b.talk()
hello test

总结:类 是由 type 类 实例化产生的

  • __new__方法
    new方法是类自带的一个方法,可以重构,__new__方法在实例化的时候也会执行,并且先于__init__方法之前执行.
class Foo(object):
  
    def __init__(self,name):
        self.name = name
  
        print("Foo __init__")
  
    def __new__(cls, *args, **kwargs):
        print("Foo __new__",cls, *args, **kwargs)
        return object.__new__(cls)
  
f = Foo("test")
  
#输出
Foo __new__ <class '__main__.Foo'> test  #执行了new方法
Foo __init__  #执行了__init__方法

new方法作用

作用:所有对象都是通过new方法来实例化的,new里面调用了init方法,所以在实例化的过程中先执行的是new方法,而不是init方法。
①重构__new__方法

class Foo(object):
  
    def __init__(self,name):
        self.name = name
        print("Foo __init__")
  
    def __new__(cls, *args, **kwargs):
        print("Foo __new__",cls, *args, **kwargs)
  
f = Foo("shuaigaogao")  #实例化
  
#输出
Foo __new__ <class '__main__.Foo'> shuaigaogao

由上面的例子看出,没有执行__init__方法

②重构__new__方法,并继承父类的__new__方法

class Foo(object):
  
    def __init__(self,name):
        self.name = name
  
        print("Foo __init__")
  
    def __new__(cls, *args, **kwargs):   #cls相当于传入类Foo
        print("Foo __new__",cls, *args, **kwargs)
        return object.__new__(cls)  #继承父类的__new__方法,这边必须以返回值的形式继承
  
f = Foo("shuaigaogao")
  
#输出
Foo __new__ <class '__main__.Foo'> shuaigaogao
Foo __init__

由上面不难看出,大多数情况下,你都不要去重构你的__new__方法,因为你父类中已经有__new__方法了,已经帮你写好了怎么去创建类,如果你重写的话,就会覆盖父类的里面的__new__方法。但是你重构可以增加一点小功能,但是你覆盖了以后还是需要继承父类回来,要不然你的这个实例就创建不了。

  • 补充
    new() 通常会返回该类的一个实例,但有时也可能会返回其他类的实例,如果发生了这种情况,则会跳过对 init() 方法的调用。
class nonZero(int):
    def __new__(cls,value):
        return super().__new__(cls,value) if value != 0 else None
    def __init__(self,skipped_value):
        print("__init__()")
        super().__init__()

a=nonZero(-12) #会返回此类的实例,调用init
b=nonZero(0) #会返回None,即非此类
print(type(a)) #此类
print(type(b)) #非此类

'''
#输出
__init__()
<class '__main__.nonZero'>
<class 'NoneType'>
'''

使用场景

我想对我自己写的一些类进行定制,就在它实例化之前就进行定制,就可以用到__new__方法,new方法就是用来创建实例的,重构new方法,必须以返回值的形式继承父类的new方法。

①需求:我在创建对象时候,同时创建一个类变量

class Foo(object):
  
    def __init__(self,name):
        self.name = name
  
        print("Foo __init__")
  
    def __new__(cls, *args, **kwargs):  #cls相当于是传入的类名Foo
        cls.name = "shuaigaogao"  #创建对象是定义静态变量
        print(cls.name)
        return object.__new__(cls)  #继承父类的__new__方法
  
f = Foo("shuaigaogao")
print(Foo.name)

"""
#输出
shuaigaogao
Foo __init__
shuaigaogao
"""

__metaclass__方法

  • metaclass作用

类 是由 type 类实例化产生

那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?

答:类中有一个属性 metaclass,其用来表示该类由 谁 来实例化创建,所以,我们可以为 metaclass 设置一个type类的派生类,从而查看 类 创建的过程。

# -*- coding: utf-8 -*-
"""
Created on Mon Feb 22 17:54:46 2021

@author: daicong
"""
class MyType(type):
    def __init__(self,*args,**kwargs):
 
        print("Mytype __init__",*args,**kwargs)   #2、其次被执行
 
    def __call__(self, *args, **kwargs):
        print("Mytype __call__", *args, **kwargs) #3、其次被执行
        obj = self.__new__(self)                  
        print("obj ",obj,*args, **kwargs)         #5、其次被执行
        print(self)                               #6、其次被执行
        self.__init__(obj,*args, **kwargs)
        return obj
 
    def __new__(cls, *args, **kwargs):
        print("Mytype __new__",*args,**kwargs)     #1、首先执行new
        return type.__new__(cls, *args, **kwargs)  #返回实例化类,调用init
 
print('here...')
class Foo(object,metaclass=MyType):
 
    def __init__(self,name):
        self.name = name
 
        print("Foo __init__")                      #7、最后被执行
 
    def __new__(cls, *args, **kwargs):
        print("Foo __new__",cls, *args, **kwargs)  #4、其次被执行
        return object.__new__(cls)                 #返回实例化类,调用init
 
f = Foo("Alex")                                    #输出1、2、3、4、5、6、7
print("f",f)                                       
print("fname",f.name)

'''
#输出
here...
1、Mytype __new__ Foo (<class 'object'>,) {'__module__': '__main__', '__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x0000019A54F22280>, '__new__': <function Foo.__new__ at 0x0000019A54F221F0>}
2、Mytype __init__ Foo (<class 'object'>,) {'__module__': '__main__', '__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x0000019A54F22280>, '__new__': <function Foo.__new__ at 0x0000019A54F221F0>}
3、Mytype __call__ Alex
4、Foo __new__ <class '__main__.Foo'>
5、obj  <__main__.Foo object at 0x0000019A54F0C310> Alex
6、<class '__main__.Foo'>
7、Foo __init__
#上面是在实例化的阶段输出的
f <__main__.Foo object at 0x0000019A54F0C310>
fname Alex
'''
'''

执行顺序

类的生成 调用 顺序依次是 new --> init --> call

参考:what-are-metaclasses-in-python

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值