为什么要在一个类中定义''uunew\'

2024-05-15 18:55:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我认为你可以在一个类中定义'__init__'或'__new__',但是为什么都定义在django.utils.datastructures.py。在

我的代码:

class a(object):
    def __init__(self):
        print  'aaa'
    def __new__(self):
        print 'sss'

a()#print 'sss'

class b:
    def __init__(self):
        print  'aaa'
    def __new__(self):
        print 'sss'
b()#print 'aaa'

在数据结构.py公司名称:

^{pr2}$

以及在什么情况下SortedDict.__init__将被调用。在

谢谢


Tags: django代码pyselfnew定义objectinit
3条回答

我唯一的猜测是,在这种情况下,他们(这个类的作者)希望keyOrder列表在调用SortedDict.__init__之前就存在于类中。在

注意SortedDict在其__init__中调用super(),这通常会转到dict.__init__,这可能会调用{}等来开始添加项。SortedDict.__setitem__期望.keyOrder属性存在,问题就在这里(因为.keyOrder通常是在调用super()之后才创建的)可能这只是子类化{}的问题,因为我的本能本能反应是在调用super()之前初始化{}。在

__new__中的代码也可用于允许SortedDict在菱形继承结构中进行子类化,在这种结构中,在调用第一个__setitem__之前,SortedDict.__init__不被调用。Django在支持从2.3以上的各种python版本时必须面对各种各样的问题;在某些版本中,这些代码可能是完全不必要的,而在其他版本中则是需要的。在


定义__new____init__有一个共同的用途:访问可能被其实例版本掩盖的类属性,而不必执行type(self)或{}(在元类的存在中,这甚至可能不是正确的事情)。在

例如:

class MyClass(object):
    creation_counter = 0

    def __new__(cls, *args, **kwargs):
        cls.creation_counter += 1
        return super(MyClass, cls).__new__(cls)

    def __init__(self):
         print "I am the %dth myclass to be created!" % self.creation_counter

最后,__new__实际上可以返回一个包装器的实例或一个完全不同于您所想实例化的类的实例。这用于提供类似元类的特性,而不需要真正的元类。在

__new__和{}做的事情完全不同。方法__init__启动一个类的新实例——它是一个构造函数。__new__是一个更微妙的东西——它可以改变参数,事实上,改变启动对象的类。例如,以下代码:

class Meters(object):
    def __new__(cls, value):
        return int(value / 3.28083)

如果调用Meters(6),实际上不会创建Meters的实例,而是int的实例。您可能会想知道为什么这是有用的;它实际上对元类至关重要,元类是一个公认的晦涩(但功能强大)的特性。在

您将注意到,在python2.x中,只有继承自object的类才能利用__new__,如上面的代码所示。在

您在django中展示的使用__new__似乎是为了保持SortedDict对象的合理方法解析顺序。不过,我承认,很难说为什么__new__是必要的。标准的Python风格建议除非有必要,否则不要使用它(一如既往,最好的类设计是您首先使用的工具)。在

您可以定义__new____init__中的一个或两个。在

__new__必须返回一个对象——它可以是一个新的对象(通常该任务被委派给type.__new__)、一个现有的对象(实现singleton,“回收”池中的实例,等等),甚至是一个而不是类的实例。如果__new__返回类的一个实例(新的或现有的),__init__然后被调用;如果__new__返回的对象不是类的实例,那么__init__将被调用而不是。在

__init__传递一个类实例作为它的第一个项(在相同的状态下,__new__返回了它,即通常为“空”),并且必须根据需要修改它以使其准备好使用(通常通过添加属性)。在

一般来说,最好使用__init__来完成所有它能做的事情——并且__new__,如果留下了{}不能做的事情,那么就用这个“额外的东西”。在

因此,如果在__init__中可以做一些有用的事情,那么通常会定义这两者,但不是类实例化时希望发生的所有事情。在

例如,考虑一个类的子类int,但也有一个foo槽,并且您希望它用int的初始值设定项和{}的初始值设定项实例化。由于int是不可变的,因此该部分必须发生在__new__中,因此可以用迂腐的方式编写:

>>> class x(int):
...   def __new__(cls, i, foo):
...     self = int.__new__(cls, i)
...     return self
...   def __init__(self, i, foo):
...     self.foo = foo
...   __slots__ = 'foo',
... 
>>> a = x(23, 'bah')
>>> print a
23
>>> print a.foo
bah
>>> 

实际上,对于这样一个简单的例子,没有人会介意您是否丢失了__init__,而只是将self.foo = foo移动到{}。但是,如果初始化足够丰富和复杂到可以最好地放在__init__中,那么这个想法值得记住。在

相关问题 更多 >