首页 > 编程语言 > 详细

python中__new__方法详解及使用

时间:2021-06-10 17:29:26      阅读:36      评论:0      收藏:0      [点我收藏+]

__new__的作用

在Python中new方法与init方法类似,但是如果两个都存在那么new先执行,先调用了__new__()方法,在调用__init__()初始化

object将__new__()方法定义为静态方法,并且至少需要传递一个参数cls,cls表示需要实例化的类,此参数在实例化时由Python解释器自动提供。

__new__()必须要有返回值,返回实例化出来的实例,需要注意的是,可以return父类__new__()出来的实例,也可以直接将object的__new__()出来的实例返回。

__init__()有一个参数self,该self参数就是__new__()返回的实例,__init__()在__new__()的基础上可以完成一些其它初始化的动作,__init__()不需要返回值。

若__new__()没有正确返回当前类cls的实例,那__init__()将不会被调用,即使是父类的实例也不行。

我们可以将类比作制造商,__new__()方法就是前期的原材料购买环节,__init__()方法就是在有原材料的基础上,加工,初始化商品环节。

实际应用过程中,我们可以这么使用:

该类中的__new__()方法的使用,就是再进行初始化之前,检查缓存中是否存在该对象,如果存在则将缓存存放对象直接返回,如果不存在,则将对象放至缓存中,供下次使用。

实例

class Person(object):
  
    def __init__(self, name, age):
        self.name = name
        self.age = age
     
    def __new__(cls, name, age):
        if 0 < age < 150:
            return object.__new__(cls)
            # return super(Person, cls).__new__(cls)
        else:
            return None
  
    def __str__(self):
        return ‘{0}({1})‘.format(self.__class__.__name__, self.__dict__)
  
print(Person(‘Tom‘, 10))
print(Person(‘Mike‘, 200))

结果:

Person({‘age‘: 10, ‘name‘: ‘Tom‘})
None

1、__new__方法默认返回实例对象供__init__方法、实例方法使用。

class Foo(object):
    ‘‘‘黄哥python培训,黄哥所写‘‘‘
    price = 50

    def how_much_of_book(self, n):
        print(self)
        return self.price * n

foo = Foo()
print(foo.how_much_of_book(8))
print(dir(Foo))

分析上面的代码,这个类实例化过程,Foo类继承object类,继承了object的__new__方法。

当你没有重写这个方法(通俗来说,你没有在Foo类中没有定义__new__方法),Foo实例化是默认自动调用父类__new__方法,这个方法返回值为类的实例(self),提供这个函数how_much_of_book,默认的第一个参数self。

class Foo(object):
    price = 50

    def __new__(cls, *agrs, **kwds):
        inst = object.__new__(cls, *agrs, **kwds)
        print(inst)
        return inst


    def how_much_of_book(self, n):
        print(self)
        return self.price * n

foo = Foo()
print(foo.how_much_of_book(8))
# <__main__.Foo object at 0x1006f2750>
# <__main__.Foo object at 0x1006f2750>
# 400

请看上面代码,Foo类中重载了__new__方法,它的返回值为Foo类的实例对象。

2、__init__ 方法为初始化方法,为类的实例提供一些属性或完成一些动作。

class Foo(object):

    def __new__(cls, *agrs, **kwds):
        inst = object.__new__(cls, *agrs, **kwds)
        print(inst)
        return inst


    def __init__(self, price=50):
        self.price = price

    def how_much_of_book(self, n):
        print(self)
        return self.price * n

foo = Foo()
print(foo.how_much_of_book(8))

# <__main__.Foo object at 0x1006f2750>
# <__main__.Foo object at 0x1006f2750>
# 400

3、__new__ 方法创建实例对象供__init__ 方法使用,__init__方法定制实例对象。

__new__ 方法必须返回值,__init__方法不需要返回值。(如果返回非None值就报错)

 

4、一般用不上__new__方法,__new__方法可以用在下面二种情况。

__new__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.

继承不可变数据类型时需要用到__new__方法(like int, str, or tuple) 。

class Inch(float):
    "Convert from inch to meter"
    def __new__(cls, arg=0.0):
        return float.__new__(cls, arg*0.0254)

print(Inch(12))

用在元类,定制创建类对象

class MetaClass(type):

    def __new__(meta, name, bases, dct):
        print ‘-----------------------------------‘
        print "Allocating memory for class", name
        print meta
        print bases
        print dct
        return super(MetaClass, meta).__new__(meta, name, bases, dct)

    def __init__(cls, name, bases, dct):
        print ‘-----------------------------------‘
        print "Initializing class", name
        print cls
        print bases
        print dct
        super(MetaClass, cls).__init__(name, bases, dct)


class Myclass(object):
    __metaclass__ = MetaClass

    def foo(self, param):
        print param


p = Myclass()
p.foo("hello")

# -----------------------------------
# Allocating memory for class Myclass
# <class ‘__main__.MetaClass‘>
# (<type ‘object‘>,)
# {‘__module__‘: ‘__main__‘, ‘foo‘: <function foo at 0x1007f6500>, ‘__metaclass__‘: <class ‘__main__.MetaClass‘>}
# -----------------------------------
# Initializing class Myclass
# <class ‘__main__.Myclass‘>
# (<type ‘object‘>,)
# {‘__module__‘: ‘__main__‘, ‘foo‘: <function foo at 0x1007f6500>, ‘__metaclass__‘: <class ‘__main__.MetaClass‘>}
# hello

 一个比较实际的例子,是在Django admin 表单验证的时候如何访问当前请求request。StackFlow的链接如下: http://stackoverflow.com/questions/1057252/how-do-i-access-the-request-object-or-any-other-variable-in-a-forms-clean-met/6062628#6062628

首先想到的是把request也传递过去,在clean方法就可以使用了。

class MyForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop(‘request‘)
        super(MyForm, self).__init__(*args, **kwargs)
    
    def clean(self):
        #这里可以得到self.request的信息
        pass

在平常的view用下面的代码调用:

f = MyForm(request.POST, request=request)

但是在定制ModelAdmin的时候却不行,因为admin只提供get_form这个方法,返回值是类对象,而不是实例对象

    get_form(self, request, *args, **kwargs):
        # 这行代码是错误的
        # return MyForm(request=request) 
        return MyForm     # OK

用__new__方法可以解决这个问题。

def get_form(self, request, *args, **kwargs):
    class ModelFormMetaClass(MyForm):
        def __new__(cls, *args, **kwargs):
            kwargs[‘request‘] = request
            return MyForm(*args, **kwargs)
    return ModelFormMetaClass

那么结果如何呢,add_view的调用代码如下:

def add_view(self, request, form_url=‘‘, extra_context=None)"
    ...
    ModelForm = self.get_form(request)
    if request.method == ‘POST‘:
        form = ModelForm(request.POST, request.FILES)
        #可以获取request参数
        # print form.request
        if form.is_valid():
            pass
        else:
            pass
    else:
        ...(计算initial)
        form = ModelForm(initial=initial)

分析:form = ModelFormMetaClass(request.POST, request.FILES),按照通常的理解右边应该返回的是ModelFormMetaClass的一个实例,由于重写了__new__函数,没有调用父类函数,而是直接返回了一个带有request参数的MyForm实例,然后调用__init__函数,因此最后ModelFormMetaClass()返回也是这个实例,而左边也需要的是MyForm的实例对象。因此__new__函数的作用是创建一个实例。

备注:MetaClass它会降低代码的可读性,也有替代方案,不建议项目中使用。有兴趣的话可以参考这里。

python中__new__方法详解及使用

原文:https://www.cnblogs.com/fat-girl-spring/p/14871132.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!