在__new __中使用object .__ new__的缺点是什么?

时间:2016-09-15 15:54:20

标签: python

编写异常类,我遇到了这个错误:

TypeError: object.__new__(A) is not safe, use Exception.__new__()

这里发布了类似的问题: TypeError: object.__new__(int) is not safe, use int.__new__()。因此,__new__已被弃用,原因如下:

[Python-Dev] __new__ deprecation

  

Guido van Rossum

     

"该消息意味着它所说的内容。 :-)没有必要打电话   object.__new__()包含多个类参数,以及任何代码   这样做只是将那些args倾倒在一个黑洞中。"

但我得到的3.3中的警告"并不安全"很可怕我试着理解使用object.__new__的含义,让我们考虑这个例子:

>>> class A(Exception):
...     def __new__(cls, *args):
...             return object.__new__(A)
...
>>> A()
TypeError: object.__new__(A) is not safe, use Exception.__new__()

悲惨地失败。另一个例子:

>>> class A(object):
...     def __new__(cls, *args):
...             return object.__new__(A)
...
>>>
>>> A()
<__main__.A object at 0x0000000002F2E278>

工作正常。虽然object是一个内置类,就其角色而言就像Exception一样,但它们共享内置类的特性。现在使用Exception,第一个示例会引发TypeError,但是object会引发object.__new__

(a)在第一个示例中使用TypeError:...is not safe...使Python引发错误(__new__)有什么缺点?

(b)在调用#include "font.h" void console_putc(char ch){ volatile unsigned* serialport = (unsigned*) 0x16000000; volatile unsigned* serialflags = (unsigned*) 0x16000018; while( *serialflags & 32 ) ; *serialport = ch; } struct PL110MMIO { unsigned haxis; //offset 0: horizontal axis unsigned vaxis; //offset 4: vertical axis unsigned polarity; //offset 8: clock+polarity unsigned lineend; //offset 12: line end unsigned baseaddr1; //offset 16: upper panel base address unsigned baseaddr2; //offset 20: lower panel base address unsigned intmask; //offset 24: interrupt mask unsigned params; //offset 28: panel parameters }; #define WIDTH 800 #define HEIGHT 600 #define framebuffer ((volatile unsigned short*) (((0x07ffffff - WIDTH*HEIGHT*2))&~0xf)) //0x200000; #define pl110 ( (volatile struct PL110MMIO*)0xc0000000 ) void console_init(){ //To get screen width w: 0x3f1f3f00 | (w/4-4) //ex: 640 = 0x3f1f3f9c pl110->haxis = 0x3f1f3f00 | (WIDTH/ 4-4); //To get screen height v: 0x80b600 | (v-1) //Ex: 480 = 0x80b61df pl110->vaxis = 0x80b6000 | (HEIGHT-1) ; pl110->polarity = 0x067f3800; pl110->baseaddr1 = (unsigned) framebuffer; //value bpp //0x1821 1 //0x1823 2 //0x1825 4 //0x1827 8 //0x1829 16 //0x182b 24 pl110->params = 0x1829; } void set_pixel(int x, int y, unsigned short color){ framebuffer[ y*WIDTH+x ] = color; } //input: r,g,b in range 0...255 //output: 16 bit color with 565 weighting #define COLOR16(r,g,b) ( ((b&0xf8)<<8) | ((g & 0xfc)<<3) | ((r&0xf8)>>3) ) void console_box( int x, int y, int w, int h ){ int i; unsigned short color = COLOR16( 0,128,255 ); for(i=0;i<w;++i){ set_pixel(x+i,y,color); set_pixel(x+i,y+h,color); } for(i=0;i<h;++i){ set_pixel(x,y+i,color); set_pixel(x+w,y+i,color); } } void console_set_pixel(int x, int y, unsigned short color){ framebuffer[ y*WIDTH+x ] = color; } void console_draw_character(int x, int y, unsigned short color, char c){ int i,j; for(i=0;i<CHAR_HEIGHT;++i){ for(j=0;j<CHAR_WIDTH;++j){ if( font_data[(int)c][i] & (MASK_VALUE >> j) ) framebuffer[ (y+i)*WIDTH + (x+j) ] = color; } } } 之前,Python执行了哪些检查?或者:在第一个示例中,Python引发错误的条件是什么?

2 个答案:

答案 0 :(得分:4)

调用object.__new__没有问题,但是在调用Exception.__new__时出现问题。

Exception类的设计方式是必须调用它的__new__,所以如果没有这样做就会抱怨。

有一个问题,为什么只有内置类才会发生这种情况。事实上,Python对每个被编程的类都做到了。

以下是自定义类中相同机制的简化穷人实现:

class A(object):
    def __new__(cls):
        rtn = object.__new__(cls)
        rtn.new_called = True
        return rtn

    def __init__(self):
        assert getattr(self,'new_called',False), \
            "object.__new__ is unsafe, use A.__new__"

class B(A):
    def __new__(cls):
        return object.__new__(cls)

现在:

>>> A()
<__main__.A object at 0x00000000025CFF98>

>>> B()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in __init__
AssertionError: object.__new__ is unsafe, use A.__new__

作为旁注,这个问题的例子实际上有两个错误:

>>> class A(Exception):
...     def __new__(cls, *args):
...             return object.__new__(A)

首先是在__new__上调用object,因此忽略了Exception.__new__

另一方面,同样严重的是A传递给__new__而不是cls,这阻碍了从A继承的所有类。

见这个例子:

class A(object):
    def __new__(cls):
        return object.__new__(A)  # The same erroneous line, without Exception

class B(A):
    pass

现在B()没有创建B的实例:

>>> B()
<__main__.A object at 0x00000000025D30B8>

答案 1 :(得分:0)

调用object.__new__(A)会返回A的实例,但如果已定义,则不会调用Exception.__new__()