2009-03-16 22 views
37

Estoy depurando algo de Python que toma, como entrada, una lista de objetos, cada uno con algunos atributos.¿Es posible crear objetos anónimos en Python?

Me gustaría codificar algunos valores de prueba, digamos, una lista de cuatro objetos cuyo atributo "foo" se establece en algún número.

¿Hay una manera más concisa que esto?

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

Idealmente, sólo me gustaría ser capaz de decir algo como:

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

(Obviamente, que se realiza en marcha la sintaxis pero ¿hay algo similar que realmente funciona.?)

Nota: Esto nunca se registrará. Es solo un código de depuración desechable. Así que no se preocupe por la legibilidad o mantenimiento.

Respuesta

36

me gusta la solución de Tetha, pero es innecesariamente complejo.

Aquí es algo más simple:

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

Sin embargo, si está creando un montón de estos, puede ahorrar algo de tiempo/memoria usando el diccionario dado en lugar de crear uno nuevo y copiar todas las entradas. Sin embargo, * realmente * no importa. –

+1

bueno, podría ser subjetivo, pero no veo una simplificación sustancial. Sí, usas __init__ y actualización, pero aún estás jugando con __dict__. – Tetha

+1

Tienes razón, no hay una simplificación significativa. Es más corto y no usa __new__, eso es todo. – DzinX

15

Tener un vistazo a esto:


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

no con clase:

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

Otro truco obvio:

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

print(foo1.x, foo2.y) 

Pero para su usecase exacta, llamar a una función con objetos anónimos directamente, yo no conozco a ninguna sola línea menos detallado que

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

feo, hace el trabajo, pero no realmente.

2

¡Tan breve, tal Python! O.o

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

EDIT: Bien, técnicamente esto crea un objeto de clase, no un objeto objeto. Pero se puede tratar como un objeto anónimo o modificar la primera línea añadiendo un par de paréntesis para crear una instancia de inmediato:

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

A partir de Python 3.3, hay types.SimpleNamespace que hace exactamente lo que quiere:

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

eso es un poco prolijo, pero que se puede limpiar con un alias:

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

Y ahora que en realidad es bastante cerca de la sintaxis de ficción en tu pregunta.

+0

Crédito a @RoadieRich por sugerir '_' como el nombre de clase en un comentario anterior. –

Cuestiones relacionadas