我要问的问题似乎是Python使用__new__和__init__的重复?但是无论如何,我还不清楚到底是什么__new__和__init__它之间的实际区别.
在你急于告诉我__new__是用于创建对象并且__init__用于初始化对象之前,让我说清楚:我明白了. 事实上,这种区别对我来说是很自然的,因为我在C++中有经验,我们有新的贴图,它同样将对象分配与初始化分开.
在Python的C API教程解释它是这样的:
新成员负责创建(而不是初始化)该类型的对象.它在Python中作为
__new__()方法公开.... 实现新方法的一个原因是确保实例变量的初始值.
所以,是的 - 我得到了什么__new__,但尽管如此,我仍然不明白为什么它在Python中有用.给出的示例说,__new__如果要"确保实例变量的初始值" ,这可能很有用.那么,这究竟是什么意思__init__呢?
在C API教程中,显示了一个示例,其中创建了一个新类型(称为"Noddy"),并__new__定义了Type的函数.Noddy类型包含一个名为的字符串成员first,并且此字符串成员初始化为空字符串,如下所示:
static PyObject * Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
.....
self->first = PyString_FromString("");
if (self->first == NULL)
{
Py_DECREF(self);
return NULL;
}
.....
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果没有__new__此处定义的方法,我们必须使用PyType_GenericNew,它只是将所有实例变量成员初始化为NULL.因此,该__new__方法的唯一好处是实例变量将以空字符串开头,而不是NULL. 但是为什么这个有用,因为如果我们关心确保我们的实例变量被初始化为某个默认值,我们可以在 …
我正在学习Python和到目前为止,我可以告诉低于约的事情__new__和__init__:
__new__ 用于创建对象__init__ 用于对象初始化__new__被调用之前__init__为__new__返回一个新的实例,并__init__随后调用初始化内部状态.__new__对于不可变对象是有益的,因为它们一旦被分配就无法更改.所以我们可以返回具有新状态的新实例.__new__和__init__为两个可变对象,因为它的内部状态可以改变.但我现在还有另外一个问题.
a = MyClass("hello","world"),如何传递这些参数?我的意思是我应该如何构造类__init__,__new__因为它们是不同的,并且除了默认的第一个参数之外都接受任意参数.self关键字在名称方面可以改为别的吗?但我想知道cls在名称方面可能会改变其他东西,因为它只是一个参数名称?我做了一些实验,如下:
>>> class MyClass(tuple):
def __new__(tuple):
return [1,2,3]
Run Code Online (Sandbox Code Playgroud)
我在下面做了:
>>> a = MyClass()
>>> a
[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)
虽然我说我想回来tuple,但这段代码运行正常并且还给了我[1,2,3].我知道在__new__调用函数后,我们将第一个参数作为我们想要接收的类型传递.我们说的是New功能对吗?我不知道除绑定类型以外的其他语言返回类型?
我也做了其他事情:
>>> issubclass(MyClass,list)
False
>>> issubclass(MyClass,tuple)
True
>>> isinstance(a,MyClass)
False
>>> isinstance(a,tuple)
False
>>> isinstance(a,list) …Run Code Online (Sandbox Code Playgroud) 在Python中,__new__用于初始化不可变类型,__init__通常初始化可变类型.如果__init__从语言中删除,那么就不能再轻松完成了什么?
例如,
class A:
def __init__(self, *, x, **kwargs):
super().__init__(**kwargs)
self.x = x
class B(A):
def __init__(self, y=2, **kwargs):
super().__init__(**kwargs)
self.y = y
Run Code Online (Sandbox Code Playgroud)
可以__new__像这样重写:
class A_N:
def __new__(cls, *, x, **kwargs):
obj = super().__new__(cls, **kwargs)
obj.x = x
return obj
class B_N(A_N):
def __new__(cls, y=2, **kwargs):
obj = super().__new__(cls, **kwargs)
obj.y = y
return obj
Run Code Online (Sandbox Code Playgroud)
澄清问题范围:这不是关于如何使用__init__和__new__使用它们或它们之间有什么区别的问题.这是一个关于如果__init__从语言中删除会发生什么的问题.什么事情会破裂?有什么事情会变得更难或不可能吗?
我了解都__init__和__new__工作.我想知道是否有什么__init__可以做到的__new__不可以?
即可以使用__init__以下模式替换:
class MySubclass(object):
def __new__(cls, *args, **kwargs):
self = super(MySubclass, cls).__new__(cls, *args, **kwargs)
// Do __init__ stuff here
return self
Run Code Online (Sandbox Code Playgroud)
我问,因为我想让Python OO的这个方面更适合我.
以下代码有什么问题(在Python 2.7.1下):
class TestFailed(BaseException):
def __new__(self, m):
self.message = m
def __str__(self):
return self.message
try:
raise TestFailed('Oops')
except TestFailed as x:
print x
Run Code Online (Sandbox Code Playgroud)
当我运行它时,我得到:
Traceback (most recent call last):
File "x.py", line 9, in <module>
raise TestFailed('Oops')
TypeError: exceptions must be old-style classes or derived from BaseException, not NoneType
Run Code Online (Sandbox Code Playgroud)
但它看起来TestFailed确实来自于BaseException.
我想给一个子类一些额外的属性,而不必显式调用一个新方法.那么有没有一种方法可以为继承的类提供一个__init__不会覆盖__init__父类方法的类型方法?
我编写下面的代码纯粹是为了说明我的问题(因此属性的命名很差等).
class initialclass():
def __init__(self):
self.attr1 = 'one'
self.attr2 = 'two'
class inheritedclass(initialclass):
def __new__(self):
self.attr3 = 'three'
def somemethod(self):
print 'the method'
a = inheritedclass()
for each in a.__dict__:
print each
#I would like the output to be:
attr1
attr2
attr3
Run Code Online (Sandbox Code Playgroud)
谢谢
class Num:
def __init__(self,num):
self.n = num
Run Code Online (Sandbox Code Playgroud)
我读到该__init__方法返回None.当我执行时a=Num(5),Num(5)将调用类的__init__方法.但是如果__init__ 返回None则a应该引用nothing.But 而是a引用NumClass 的对象.它是如何发生的?那么__init__返回None还是类的对象?
注意:使用Python的flyweight实现的一部分
import weakref
class CarModel:
_models = weakref.WeakValueDictionary()
def __new__(cls, model_name, *args, **kwargs):
model = cls._models.get(model_name)
if not model:
model = super().__new__(cls)
cls._models[model_name] = model
return model
def __init__(self, model_name, air=False):
if not hasattr(self, "initted"):
self.model_name = model_name
self.air = air
self.initted=True
Run Code Online (Sandbox Code Playgroud)
问题1>什么super()意思?这是否意味着父类CarModel?
问题2>我也很难理解该功能的__new__工作原理?具体来说,以下行.
model = super().__new__(cls)
Run Code Online (Sandbox Code Playgroud)
说明__new__:
构造函数被调用
__new__而不是__init__,并且只接受一个参数,即正在构造的类(在构造对象之前调用它,因此没有自参数).它还必须返回新创建的对象.
假设我们有一个类'Parent',由于某种原因已__new__定义,并且继承了它的类'Child'.(在我的情况下,我试图继承我无法修改的第三方课程)
class Parent:
def __new__(cls, arg):
# ... something important is done here with arg
Run Code Online (Sandbox Code Playgroud)
我的尝试是:
class Child(Parent):
def __init__(self, myArg, argForSuperclass):
Parent.__new__(argForSuperclass)
self.field = myArg
Run Code Online (Sandbox Code Playgroud)
但同时
p = Parent("argForSuperclass")
Run Code Online (Sandbox Code Playgroud)
按预期工作
c = Child("myArg", "argForSuperclass")
Run Code Online (Sandbox Code Playgroud)
失败,因为'Child'试图调用__new__它从'Parent'而不是它自己的__init__方法继承的方法.
为了获得预期的行为,我必须在"儿童"中进行哪些更改?
我正在创建一些类来处理各种类型的文件共享(nfs,afp,s3,本地磁盘)等文件名.我得到一个用户输入一个标识数据源(即"nfs://192.168.1.3"或"s3://mybucket/data")等的字符串.
我从具有公共代码的基类继承特定文件系统.我困惑的地方是对象创建.我所拥有的是以下内容:
import os
class FileSystem(object):
class NoAccess(Exception):
pass
def __new__(cls,path):
if cls is FileSystem:
if path.upper().startswith('NFS://'):
return super(FileSystem,cls).__new__(Nfs)
else:
return super(FileSystem,cls).__new__(LocalDrive)
else:
return super(FileSystem,cls).__new__(cls,path)
def count_files(self):
raise NotImplementedError
class Nfs(FileSystem):
def __init__ (self,path):
pass
def count_files(self):
pass
class LocalDrive(FileSystem):
def __init__(self,path):
if not os.access(path, os.R_OK):
raise FileSystem.NoAccess('Cannot read directory')
self.path = path
def count_files(self):
return len([x for x in os.listdir(self.path) if os.path.isfile(os.path.join(self.path, x))])
data1 = FileSystem('nfs://192.168.1.18')
data2 = FileSystem('/var/log')
print type(data1)
print type(data2)
print data2.count_files() …Run Code Online (Sandbox Code Playgroud)