2012-09-30 2 views
13

Al aprender sobre el modelo de datos de Python, estoy jugando con la creación de objetos a partir de objetos existentes usando el método __new__. He aquí algunos ejemplos que crean nuevos objetos de varios tipos:Objetos de Python de objetos existentes usando __new__

x = 2;  print type(x).__new__(x.__class__) 
x = {}; print type(x).__new__(x.__class__) 
x = [1,2]; print type(x).__new__(x.__class__) 
x = 2.34; print type(x).__new__(x.__class__) 
x = '13'; print type(x).__new__(x.__class__) 
x = 1.0j; print type(x).__new__(x.__class__) 
x = True; print type(x).__new__(x.__class__) 
x = (1,2); print type(x).__new__(x.__class__) 

Sin embargo, los siguientes tres experimentos me dan errores:

x = None;   print type(x).__new__(x.__class__) 
x = lambda z: z**2; print type(x).__new__(x.__class__) 
x = object;   print type(x).__new__(x.__class__) 

Los errores son (respectivamente):

TypeError: object.__new__(NoneType) is not safe, use NoneType.__new__() 
TypeError: Required argument 'code' (pos 1) not found 
TypeError: type() takes 1 or 3 arguments 

¿Por qué estos tres ejemplos no funcionan? (Nota: para el ejemplo lambda, parece que tengo que pasar un fragmento de código cuando invoco el método __new__, pero no sé cómo hacerlo). Estoy usando Python 2.6.

Tenga en cuenta que esta no es necesariamente la forma en que desearía crear nuevos objetos en código real, pero mi propósito no es práctico, más bien, es comprender cómo funcionan los métodos de objetos de bajo nivel.

+1

Y qué exactamente el error dice que será beneficioso para nosotros .. –

+0

Mensajes agregados Rohit Gracias por la sugerencia. – rlandster

Respuesta

14

No es nada demasiado especial, es solo que para algunos tipos hay un objeto predeterminado "vacío" de ese tipo, mientras que para otros no. Sus ejemplos de trabajo son básicamente equivalentes a:

int() 
dict() 
list() 
float() 
str() 
complex() 
tuple() 

. . . todo lo cual funciona Sus últimos tres ejemplos básicamente intentan crear nuevas instancias de NoneType, function y type.

  1. NoneType falla por un único motivo, porque None es un singleton --- el tipo NoneType solo puede tener una sola instancia, es decir, el objeto None. (El mensaje de error específico que recibe es un poco extraño, pero si lo hace types.NoneType() obtendrá un mensaje más directo que dice "No se pueden crear instancias NoneType".)
  2. function falla porque, como vio, se requiere una argumento, y usted no proporciona uno. Lo que necesitaría es un objeto de código, que podría obtener de una función existente o de la función compile. (También requiere un argumento globals, que puede ser simplemente un dict.)
  3. type falla porque no proporcionó suficientes argumentos. Puede hacer type(foo) para obtener el tipo de foo o type(name, bases, dict) para crear un tipo nuevo (es decir, una clase).

Observe incidentalmente que en su último ejemplo está tomando el tipo de object, que a su vez es un tipo. Si hace x = object() en su lugar (haciendo que x sea un objeto individual en lugar de un tipo de objeto), entonces funcionará y creará un objeto "en blanco".

Lo que hay que recordar es que llamar al __new__ no es realmente tan mágico. Es justo lo que sucede cuando intentas crear una instancia del tipo directamente haciendo someType(). Si ese tipo requiere argumentos, la llamada al __new__ fallará, al igual que cualquier otra llamada de función fallará si no le da los argumentos correctos, porque type(x).__new__ es simplemente una función como cualquier otra función.Puede ver esto con una clase definida por el usuario:

>>> class Foo(object): 
...  pass 
>>> x = Foo();   print type(x).__new__(x.__class__) 
<__main__.Foo object at 0x00EB0370> 
>>> class Foo(object): 
...  def __init__(self, someArg): 
...   pass 
>>> class Foo(object): 
...  def __new__(cls, someArg): 
...   return super(Foo, cls).__new__(cls) 
>>> x = Foo(2);   print type(x).__new__(x.__class__) 
Traceback (most recent call last): 
    File "<pyshell#32>", line 1, in <module> 
    x = Foo(2);   print type(x).__new__(x.__class__) 
TypeError: __new__() takes exactly 2 arguments (1 given) 

Tuve éxito en el primer caso, porque mi clase no requería argumentos; falló en la segunda clase, porque la segunda clase requiere argumentos.

El __new__ no falla por ningún motivo secreto; simplemente falla porque el tipo que intentas instanciar requiere argumentos para construir una instancia. (El caso None es el único que es diferente aquí, que falla por una razón especial, porque None es un objeto especial en Python.)

+0

Muy claramente explicado +1 – JamesSwift