2012-09-30 23 views
13

Nell'apprendere a conoscere il modello di dati di Python, sto giocando con la creazione di oggetti da oggetti esistenti usando il metodo __new__. Ecco alcuni esempi che creano nuovi oggetti di vario tipo:Oggetti Python da oggetti esistenti 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__) 

Tuttavia, i seguenti tre esperimenti mi danno errori:

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__) 

Gli errori sono (rispettivamente):

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 

Perché questi tre esempi non funzionano? (Nota: per l'esempio lambda sembra che devo passare un frammento di codice quando invoco il metodo __new__ ma non so come farlo.) Sto usando Python 2.6.

Si noti che mi rendo conto che questo non è necessariamente il modo in cui si desidera creare nuovi oggetti in codice reale, ma il mio scopo non è pratico, piuttosto, è capire come funzionano i metodi a basso livello degli oggetti.

+1

E quale errore esattamente dice che sarà vantaggioso per noi .. –

+0

Aggiunti messaggi , Rohit. Grazie per il suggerimento. – rlandster

risposta

14

Non è niente di troppo speciale, è solo che per alcuni tipi c'è un oggetto "vuoto" predefinito di quel tipo, mentre per gli altri non lo è. I tuoi esempi di lavoro sono sostanzialmente equivalenti a:

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

. . . tutto ciò che funziona. I tuoi ultimi tre esempi stanno fondamentalmente cercando di creare nuove istanze di NoneType, function e type.

  1. NessunoTipo ha esito negativo per un motivo univoco, perché Nessuno è un singleton --- il tipo NoneType può avere sempre un'istanza, ovvero l'oggetto Nessuno. (Il messaggio di errore specifico che ottieni è un po 'strano, ma se fai types.NoneType() riceverai un messaggio più diretto che dice "Impossibile creare istanze NoneType".)
  2. function fallisce perché, come hai visto, richiede un argomento, e tu non ne fornisci uno. Quello di cui hai bisogno è un oggetto codice, che potresti ottenere da una funzione esistente o dalla funzione compile. (Richiede anche un argomento globals, che può essere solo un ditt.)
  3. type non riesce perché non hai dato argomenti sufficienti. È possibile eseguire type(foo) per ottenere il tipo di foo o type(name, bases, dict) per creare un nuovo tipo (ad esempio una classe).

Si noti inoltre che nel proprio ultimo esempio si sta prendendo il tipo di object, che è di per sé un tipo. Se invece fai x = object() (facendo in modo che x sia un singolo oggetto piuttosto che il tipo di oggetto), funzionerà e creerà un oggetto "vuoto".

La cosa da ricordare è che chiamare __new__ non è proprio così magico. È proprio quello che succede quando provi direttamente a istanziare il tipo facendo someType(). Se quel tipo richiede argomenti, la chiamata __new__ fallirà, proprio come qualsiasi altra chiamata di funzione fallirà se non gli si forniscono gli argomenti giusti, perché type(x).__new__ è solo una funzione come qualsiasi altra funzione.Potete vederlo con una classe definita dall'utente:

>>> 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) 

Successo nel primo caso, perché la mia classe non richiedeva argomenti; non è riuscito nella seconda classe, perché la seconda classe richiede argomenti.

Il __new__ non fallisce per nessuna ragione segreta; fallisce semplicemente perché il tipo che stai cercando di istanziare richiede degli argomenti per costruire un'istanza. (Il caso None è l'unico che è diverso qui, che non funziona per un motivo speciale, perché None è un oggetto speciale in Python.)

+0

Molto chiaramente spiegato +1 – JamesSwift

Problemi correlati