Domanda

Sto eseguendo il debug di alcuni Python che accetta, come input, un elenco di oggetti, ciascuno con alcuni attributi.

Vorrei codificare alcuni valori di test - diciamo, un elenco di quattro oggetti il ??cui " foo " l'attributo è impostato su un numero.

C'è 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 poter dire qualcosa del tipo:

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

(Ovviamente, questa è sintassi inventata. Ma c'è qualcosa di simile che funziona davvero?)

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

È stato utile?

Soluzione

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

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

Altri suggerimenti

Ho trovato questo: http://www.hydrogen18.com/blog/ python-anonymous-objects.html e nei miei test limitati sembra che funzioni:

>>> obj = type('',(object,),{"foo": 1})()
>>> obj.foo
1

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

Così breve, come Python! Ò.ò

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

Quindi puoi usare Object come costruttore generico di oggetti:

>>> person = Object(name = "Bernhard", gender = "male", age = 42)
>>> person.name
'Bernhard'
>>>

EDIT: Bene, tecnicamente questo crea un oggetto di classe, non un oggetto oggetto. Ma puoi trattarlo come un oggetto anonimo o modificare la prima riga aggiungendo una parentesi per creare immediatamente un'istanza:

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

Un altro trucco evidente:

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

print(foo1.x, foo2.y)

Ma per il tuo esatto caso di utilizzo, chiamando direttamente una funzione con oggetti anonimi, non conosco una linea meno dettagliata di

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

Brutto, fa il lavoro, ma non proprio.

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

A partire da Python 3.3, ci sono types.SimpleNamespace fa esattamente quello che vuoi:

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

È un po 'prolisso, ma puoi ripulirlo con un alias:

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

E ora è abbastanza vicino alla sintassi immaginaria nella tua domanda.

Forse puoi usare namedtuple per risolvere questo problema come seguenti:

from collections import namedtuple
Mock = namedtuple('Mock', ['foo'])

mock = Mock(foo=1)
mock.foo  // 1
anonymous_object = type('',(),{'name':'woody', 'age':'25'})()
anonymous_object.name
> 'woody'

C'è un modo interessante ma difficile da capire. Usa type () crea una classe senza nome con parametri di default init, quindi iniziarlo senza alcun parametro e ottenere l'oggetto anonimo.

Ecco come l'ho fatto:

from mock import patch
import requests

class MockResponse:

    def __init__(self, text, status_code):
        self.text = text
        self.status_code = status_code


class TestSomething(unittest.TestCase):

    @patch('requests.get',return_value=MockResponse('the result',200))
    def test_some_request(self, *args, **kwargs):
        response = requests.get('some.url.com')
        assert response.text=='the result'
        assert response.status_code=='200'
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top