Возможно ли создать анонимные объекты в Python?
Я отлаживаю некоторый 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>])
(Очевидно, что это составленный синтаксис. Но есть ли что-то подобное, что действительно работает?)
Примечание. Это никогда не будет проверено. Это всего лишь один отладочный код. Поэтому не беспокойтесь о удобочитаемости или ремонтопригодности.
Ответы
Ответ 1
Мне нравится решение Tetha, но оно излишне сложно.
Здесь что-то проще:
>>> class MicroMock(object):
... def __init__(self, **kwargs):
... self.__dict__.update(kwargs)
...
>>> def print_foo(x):
... print x.foo
...
>>> print_foo(MicroMock(foo=3))
3
Ответ 2
Я нашел это: http://www.hydrogen18.com/blog/python-anonymous-objects.html, и в моем ограниченном тестировании кажется, что он работает:
>>> obj = type('',(object,),{"foo": 1})()
>>> obj.foo
1
Ответ 3
Посмотрите на это:
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 classy:
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))
Ответ 5
Еще один очевидный взлом:
class foo1: x=3; y='y'
class foo2: y=5; x=6
print(foo1.x, foo2.y)
Но для вашего точного usecase, вызывающего функцию с анонимными объектами напрямую, я не знаю ни одного однострочного менее подробного, чем
myfunc(type('', (object,), {'foo': 3},), type('', (object,), {'foo': 4}))
Ужасно, выполняет ли это задание, но не совсем.
Ответ 6
Так коротко, такой Питон! Оо
>>> Object = lambda **kwargs: type("Object", (), kwargs)
Затем вы можете использовать Object
в качестве универсального конструктора объекта:
>>> person = Object(name = "Bernhard", gender = "male", age = 42)
>>> person.name
'Bernhard'
>>>
РЕДАКТИРОВАТЬ: Ну ладно, технически это создает объект класса, а не объект объекта. Но вы можете рассматривать его как анонимный объект или изменить первую строку, добавив пару скобок для немедленного создания экземпляра:
>>> Object = lambda **kwargs: type("Object", (), kwargs)()
Ответ 7
Начиная с 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)])
И теперь это фактически очень близко к вымышленному синтаксису в вашем вопросе.
Ответ 8
Возможно, вы можете использовать namedtuple для решения этой проблемы следующим образом:
from collections import namedtuple
Mock = namedtuple('Mock', ['foo'])
mock = Mock(foo=1)
mock.foo // 1
Ответ 9
anonymous_object = type('',(),{'name':'woody', 'age':'25'})()
anonymous_object.name
> 'woody'
Есть крутой способ, но трудно понять. Он использует type(), создает безымянный класс с параметрами инициализации по умолчанию, затем инициализирует его без каких-либо параметров и получает анонимный объект.
Ответ 10
Вот как я это сделал:
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'