_new__和__init__的区别
__new__是Python面向对象语言中一个很少用的函数,更多使用的是__init__这个函数。例如:
class Book(object):
def __init__(self, title):
super(Book, self).__init__(self)
self.title = title # Define a book b = Book('The Django Book')
print b.title
上面算是OOP语言的入门代码了,粗略一看__init__和java中的构造函数一样,其实不然,实际上它根本不能算的上构造函数。__new__才是创建实例的方法。
根据官方文档:
__init__是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值。
__new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例,是个静态方法。
也就是,__new__在__init__之前被调用,__new__的返回值(实例)将传递给__init__方法的第一个参数,然后__init__给这个实例设置一些参数。
class Book(object):
def __new__(cls, title):
print '__new__'
return super(Book, cls).__new__(cls) def __init__(self, title):
print '__init__'
super(Book, self).__init__(self)
self.title = title b = Book('The Django Book')
print b.title
上面执行的结果:
__new__
__init__
The Django Book
__new__的应用场景
官方文档指出__new__方法的两种用法。
允许继承不可变类型(str,int, tuple)
关于这种也有比较多的例子,网上搜到的例子基本上都属于理论性,实际中用法不太常见。
在MetaClass中使用
MetaClass算是Python的语法糖吧,简单来说通过它可以动态生成或更改class的定义。
一个比较实际的例子,是在Django admin 表单验证的时候如何访问当前请求request。StackFlow的链接如下:
首先想到的是把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它会降低代码的可读性,也有替代方案,不建议项目中使用。有兴趣的话可以参考这里。
_new__和__init__的区别的更多相关文章
- 【转】python类中super()和__init__()的区别
[转]python类中super()和__init__()的区别 单继承时super()和__init__()实现的功能是类似的 class Base(object): def __init__(se ...
- Python 中的__new__和__init__的区别
[同] 二者均是Python面向对象语言中的函数,__new__比较少用,__init__则用的比较多. [异] __new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例对象,是 ...
- python__new__与__init__的区别
__new__ __init__区别 1 class A(object): 2 def __init__(self,*args, **kwargs): 3 print "init A&quo ...
- python中super().__init__和类名.__init__的区别
super().__init__相对于类名.__init__,在单继承上用法基本无差 但在多继承上有区别,super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次 多继承时 ...
- python类中super()和__init__()的区别
class Base(object): def __init__(self): print 'Base create' class childB(Base): def __init__(sel ...
- __init__ __new__区别
请运行代码: class A: def __init__(self): print "A.__init" def __new__(self): print "A.__ne ...
- __new__和__init__的区别
__new__是一个静态方法,而__init__是一个实例方法. __new__方法会返回一个创建的实例,而__init__什么都不返回. 只有在__new__返回一个cls的实例时后面的__init ...
- __new__() 与__init__()的区别
__new__作用于__init__之前.前者可以决定是否调用后者,或者说可以决定调用那个类的__init__方法. 首先要知道在面向对象编程中,实例化基本遵循创建实例对象,初始化实例对象,最后返回实 ...
- 元类编程-- __new__和__init__的区别
class User: def __new__(cls, *args, **kwargs): print (" in new ") return super().__new__(c ...
随机推荐
- L2 Regularization for Neural Nerworks
L2 Regularization是解决Variance(Overfitting)问题的方案之一,在Neural Network领域里通常还有Drop Out, L1 Regularization等. ...
- 关于eclipse中的maven插件问题
最近上课讲eclipse 中的maven插件 有一个坑确实比较坑,实际上就是一个配置的原因. 就是在eclipse中设置java 的buildpath的时候,一般不注意往往都设置成了jre的,这样的话 ...
- IDF-CTF-cookie欺骗 writeup
题目链接: http://ctf.idf.cn/index.php?g=game&m=article&a=index&id=40 知识点:base64解码, cookie欺骗 ...
- [功能集锦] 002 - mysql查询数据库字典+导出+样式一键整合至excel
写在前面: 因为工作时候经常遇到半路接手项目的情况,由于年代久远,数据库字典这块经常缺失.故写此篇,以便复用,也希望对大家有点帮助. 随笔内容不高级,如有不妥,不吝指正. 20190730-加了一些简 ...
- Java稀疏数组
一.概述 1.概念 2.处理方法 3.示例 原数组如下: 转换为稀疏数组如下: 二.代码 1.主方法 @Testpublic void SparseTest() { // 创建一个原始的二维数组 11 ...
- 2019Flutter面试题最新整理大全(含答案)
一.前言2019年行将结束,也该规划一下自己的职业生涯了:是选择继续从事Android(Android的话已经火了几年了,现在算是进入寒冬了,需要考虑清楚)?还是学习新的跨平台开发Flutter技术? ...
- Python入门习题3.天天向上
例3.1 一年365天,以第一天的能力值为基数,记为1.0,当好好学习时能力值相比前一天提高1%,当没有学习时能力值相比前一天下降1%.每天努力(dayup)和每天放任(daydown),一年下来的能 ...
- 在vue中设计一个客户签名的功能
直接贴代码: <template> <div class="hello"> <p>签字:</p> <canvas id=&qu ...
- shell本地变量和环境变量的对比
- 编译错误:warning C4005]ws2def.h(91): warning C4005: “AF_IPX”: 宏重定义 winsock.h(460) : 参见“AF_IPX”的前一个定义
[问题] ws2def.h(91): warning C4005: “AF_IPX”: 宏重定义: winsock2.h(460) : 参见“AF_IPX”的前一个定义 [原因] windows.h头 ...