_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 ...
随机推荐
- org.w3c.dom。 XML解析 练习
HTML文档 1 import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; ...
- 【python】 判断纯ascii串
参考:http://stackoverflow.com/questions/3636928/test-if-a-python-string-is-printable print all(ord(c)& ...
- Visual Studio中把文件夹导入工程中
VS用到的功能还是太少,记录备忘. 有的时候需要把其他库的源码导入当前工程直接使用,而这个库是源码形式,又带很多目录的. 之前从没遇到过这种情况,自己的库目录自己新建,添加. 第三方库一般有单独的Pr ...
- Spring Security 04
转至:Elim的博客http://elim.iteye.com/blog/2161648 Filter Porxy DelegatingFilterProxy DelegationFilterProx ...
- java Semaphore信号灯
Semaphore实现的功能就类似2个公用电话,假如有10个人要打电话:那么只能2个人占有电话,8个需要等待.当2个人中 的任何一个人让开后,其中等待的另外8个人中又有一个人可以使用了等待的8个人中可 ...
- Python自学第二天学习之《字符串与数字》
一.基本数据类型: 数字:int类型,不可变类型 格式 : a=10 1.其他类型转换成int型 : b=“123” c=int(b) #转换类型 print(c)----- 123 print(ty ...
- Leetcode Lect3 时间复杂度/空间复杂度
时间复杂度 复杂度 可能对应的算法 备注 O(1) 位运算 常数级复杂度,一般面试中不会有 O(logn) 二分法,倍增法,快速幂算法,辗转相除法 O(n) 枚举法,双指针算法,单调栈算法,KMP ...
- spring(二):bean的生命周期
bean的生命周期指的是bean的创建——>初始化——>销毁的过程,该过程是由spring容器进行管理的 我们可以自定义bean初始化和销毁的方法:容器在bean进行到当前生命周期时,调用 ...
- JavaScript 中的 Function.prototype.bind() 方法
转载自:https://www.cnblogs.com/zztt/p/4122352.html Function.prototype.bind()方法 bind() 方法的主要作用就是将函数绑定至某个 ...
- webpack的理解、总结
weabpck的基础应用 https://blog.zhangjd.me/2016/06/19/webpack-your-bags/ https://juejin.im/post/5cc26dfef2 ...