web-dev-qa-db-ja.com

Pythonで匿名オブジェクトを作成することは可能ですか?

私はいくつかのPythonをデバッグしています。これは、いくつかの属性を持つオブジェクトのリストを入力として受け取ります。

テスト値をハードコーディングしたいのですが、たとえば、 "foo"属性がいくつかの値に設定されている4つのオブジェクトのリストを考えてみましょう。

これより簡潔な方法はありますか?

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

(明らかに、それは架空の構文ですが、実際に機能する同様のものはありますか?)

注:これはチェックインされません。単なる使い捨てのデバッグコードです。したがって、可読性や保守性について心配する必要はありません。

47
mike

私はテサのソリューションが好きですが、それは不必要に複雑です。

ここにもっと簡単なものがあります:

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

私はこれを見つけました: http://www.hydrogen18.com/blog/python-anonymous-objects.html 、そして私の限られたテストではそれはうまくいくようです:

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

これを見てください:


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

とても簡単です、そのようなPython! O.o

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

次に、Objectを汎用オブジェクトコンストラクタとして使用できます。

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

編集:まあ、大丈夫、技術的にはこれはオブジェクトオブジェクトではなくクラスオブジェクトを作成します。しかし、それを匿名オブジェクトのように扱うことも、1組の括弧を追加して最初の行を変更し、インスタンスをすぐに作成することもできます。

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

別の明らかなハック:

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

醜い、仕事をしますが、実際にはしません。

5
vlad-ardelean

たぶん namedtuple を使用してこれを次のように解決できます:

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

mock = Mock(foo=1)
mock.foo  // 1
4
Huachao

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
W. Marshall

上品ではない:

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))
4
Rabih Kodeih
anonymous_object = type('',(),{'name':'woody', 'age':'25'})()
anonymous_object.name
> 'woody'

クールな方法がありますが、理解するのは難しいです。 type()を使用して、デフォルトのinit paramsで名前のないクラスを作成します。次に、paramなしでinitし、匿名オブジェクトを取得します。

1
woody

これは私がそれをした方法です:

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