Можно ли создавать анонимные объекты в Python? - PullRequest
45 голосов
/ 17 марта 2009

Я отлаживаю некоторый Python, который принимает в качестве входных данных список объектов, каждый с некоторыми атрибутами.

Я бы хотел жестко закодировать некоторые тестовые значения - скажем, список из четырех объектов, для атрибута "foo" которых задано некоторое число.

Есть ли более краткий способ, чем этот?

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

В идеале я бы хотел сказать что-то вроде:

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

(Очевидно, это выдуманный синтаксис. Но есть ли что-то похожее, что действительно работает?)

Примечание: это никогда не будет проверено. Это просто какой-то одноразовый отладочный код. Так что не беспокойтесь о удобочитаемости или удобстве обслуживания.

Ответы [ 10 ]

40 голосов
/ 17 марта 2009

Мне нравится решение Теты, но оно излишне сложное.

Вот что-то попроще:

>>> class MicroMock(object):
...     def __init__(self, **kwargs):
...         self.__dict__.update(kwargs)
...
>>> def print_foo(x):
...     print x.foo
...
>>> print_foo(MicroMock(foo=3))
3
39 голосов
/ 07 апреля 2015

Я нашел это: http://www.hydrogen18.com/blog/python-anonymous-objects.html, и в моем ограниченном тестировании кажется, что это работает:

>>> obj = type('',(object,),{"foo": 1})()
>>> obj.foo
1
16 голосов
/ 17 марта 2009

Посмотрите на это:


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))
5 голосов
/ 15 марта 2017

Так коротко, такой Питон! O.o

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

Тогда вы можете использовать Object в качестве универсального конструктора объекта:

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

РЕДАКТИРОВАТЬ: Хорошо, технически это создает объект класса, а не объект объекта. Но вы можете рассматривать его как анонимный объект или изменить первую строку, добавив пару скобок для немедленного создания экземпляра:

>>> Object = lambda **kwargs: type("Object", (), kwargs)()
4 голосов
/ 29 марта 2018

Может быть, вы можете использовать namedtuple , чтобы решить это следующим образом:

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

mock = Mock(foo=1)
mock.foo  // 1
4 голосов
/ 19 июля 2017

Начиная с Python 3.3, есть types.SimpleNamespace , который делает именно то, что вы хотите:

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

Это немного словесно, но вы можете очистить его псевдонимом:

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

А теперь это довольно близко к вымышленному синтаксису в вашем вопросе.

4 голосов
/ 28 января 2016

Еще один очевидный взлом:

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

print(foo1.x, foo2.y)

Но для вашего точного варианта использования, вызывающего функцию с анонимными объектами напрямую, я не знаю ни одного однострочного, менее подробного, чем

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

Безобразно, делает работу, но не совсем.

4 голосов
/ 17 июля 2013

Не классный:

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))
0 голосов
/ 16 апреля 2019

Вот как я это сделал:

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'
0 голосов
/ 30 августа 2018
anonymous_object = type('',(),{'name':'woody', 'age':'25'})()
anonymous_object.name
> 'woody'

Есть крутой способ, но его трудно понять. Он использует type () для создания безымянного класса с параметрами инициализации по умолчанию, затем инициализируйте его без каких-либо параметров и получите анонимный объект.

...