2009-03-16 15 views
37

Sto eseguendo il debug di alcuni Python che prendono come input un elenco di oggetti, ognuno con alcuni attributi.È possibile creare oggetti anonimi in Python?

Mi piacerebbe codificare alcuni valori di test, ad esempio un elenco di quattro oggetti il ​​cui attributo "foo" è impostato su un numero.

Esiste un modo più conciso di questo?

x1.foo = 1 
x2.foo = 2 
x3.foo = 3 
x4.foo = 4 
myfunc([x1, x2, x3, x4]) 

Idealmente, vorrei solo essere in grado di dire qualcosa del tipo:

myfunc([<foo=1>, <foo=2>, <foo=3>, <foo=4>]) 

(Ovviamente, che è fatta-up sintassi ma c'è qualcosa di simile che funziona davvero.?)

Nota: questo non verrà mai archiviato. È solo un codice di debug throwaway. Quindi non preoccuparti di leggibilità o manutenibilità.

risposta

36

Mi piace la soluzione di Tetha, ma è inutilmente complesso.

Ecco qualcosa di più semplice:

>>> class MicroMock(object): 
...  def __init__(self, **kwargs): 
...   self.__dict__.update(kwargs) 
... 
>>> def print_foo(x): 
...  print x.foo 
... 
>>> print_foo(MicroMock(foo=3)) 
3 
+0

Tuttavia, se si sta creando un intero gruppo di questi, è possibile risparmiare un po 'di tempo/memoria utilizzando il dizionario dato invece di crearne uno nuovo e copiare tutte le voci. Non * davvero * importa, però. –

+1

beh, potrei essere soggettivo, ma non vedo alcuna sostanziale semplificazione. Sì, usi __init__ e aggiorni, ma stai ancora giocando con __dict__. – Tetha

+1

Hai ragione, non c'è una semplificazione significativa. È solo più breve e non usa __new__, questo è tutto. – DzinX

15

Date un'occhiata a questo:


class MiniMock(object): 
    def __new__(cls, **attrs): 
     result = object.__new__(cls) 
     result.__dict__ = attrs 
     return result 

def print_foo(x): 
    print x.foo 

print_foo(MiniMock(foo=3)) 
4

non di classe:

def mock(**attrs): 
    r = lambda:0 
    r.__dict__ = attrs 
    return r 

def test(a, b, c, d): 
    print a.foo, b.foo, c.foo, d.foo 

test(*[mock(foo=i) for i in xrange(1,5)]) 
# or 
test(mock(foo=1), mock(foo=2), mock(foo=3), mock(foo=4)) 
3

altro trucco ovvio:

class foo1: x=3; y='y' 
class foo2: y=5; x=6 

print(foo1.x, foo2.y) 

Ma per il vostro caso d'uso esatto, chiamando una funzione con oggetti anonimi direttamente, non so alcun one-liner meno prolissa di

myfunc(type('', (object,), {'foo': 3},), type('', (object,), {'foo': 4})) 

brutto, fa il lavoro, ma non proprio.

2

Così breve, tale Python! Ò.ò

>>> Object = lambda **kwargs: type("Object",(), kwargs) 
>>> person = Object(name = "Bernhard", gender = "male", age = 42) 
>>> person.name 
'Bernhard' 
>>> 

EDIT: Bene bene, tecnicamente questo crea un oggetto di classe, non un oggetto oggetto. Ma si può trattare come un oggetto anonimo o modificare la prima linea aggiungendo un paio di parentesi per creare un'istanza subito:

>>> Object = lambda **kwargs: type("Object",(), kwargs)() 
1

Come di Python 3.3, c'è types.SimpleNamespace che fa esattamente ciò che si vuole:

myfunc([types.SimpleNamespace(foo=1), types.SimpleNamespace(foo=2), types.SimpleNamespace(foo=3), types.SimpleNamespace(foo=4)]) 

che è un po 'prolisso, ma è possibile pulirlo con un alias:

_ = types.SimpleNamespace 
myfunc([_(foo=1), _(foo=2), _(foo=3), _(foo=4)]) 

E ora che in realtà è abbastanza vicino alla sintassi immaginario la tua domanda.

+0

Credito a @RoadieRich per suggerire '_' come nome della classe in un commento precedente. –

Problemi correlati