是否可以在Python中创建匿名对象?

时间:2009-03-16 21:50:46

标签: python anonymous-types

我正在调试一些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>])

(显然,这是伪造的语法。但是有类似的东西真的有效吗?)

注意:永远不会签入。这只是一些一次性的调试代码。所以不要担心可读性或可维护性。

13 个答案:

答案 0 :(得分:39)

我喜欢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

答案 1 :(得分:39)

我发现了这个:http://www.hydrogen18.com/blog/python-anonymous-objects.html,在我的有限测试中看起来似乎有效:

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

答案 2 :(得分:16)

看看这个:


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

答案 3 :(得分:5)

如此简短,这样的Python! 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 :(得分:4)

非优雅:

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 :(得分:4)

另一个明显的黑客攻击:

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

丑陋,做到了,但不是真的。

答案 6 :(得分:4)

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

现在,这实际上非常接近你问题中虚构的语法。

答案 7 :(得分:4)

也许您可以使用namedtuple解决此问题,如下所示:

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

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

答案 8 :(得分:1)

我将使用lambda

url : "<?php echo site_url('Single_test/All_presc1/'. $id . '/'. $cid ) ?>",

答案 9 :(得分:0)

anonymous_object = type('',(),{'name':'woody', 'age':'25'})()
anonymous_object.name
> 'woody'

有一个很酷的方法,但很难理解。 它使用type()创建一个具有默认初始化参数的未命名类, 然后在没有任何参数的情况下将其初始化并获取匿名对象。

答案 10 :(得分:0)

这是我的方法:

00007ffe

答案 11 :(得分:0)

如果您使用的是 Python 3.7 或更高版本,您可以使用 named tuples 来增强创建的对象的不变性、文档字符串和方便的元组方法:

from collections import namedtuple

PyObj = lambda **kwargs: namedtuple('PyObj', kwargs.keys())._make(kwargs.values())

o = PyObj(foo = 1)
print(o)
# prints: PyObj(foo=1)
o.foo
# returns: 1
o.foo = 0
# exception:
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# AttributeError: can't set attribute

print(PyObj(foo = 1, bar = 'baz'))
# prints: PyObj(foo=1, bar='baz')

需要 Python 3.7+ 才能确保键和值的顺序相同。

但是,如果属性列表是预定义的,你可以直接使用namedtuple,正如Huachao建议的那样,不需要定义PyObj函数,你可以在v2中使用它.7.

from collections import namedtuple
foo = namedtuple('Foo', 'foo')

myfunc = lambda l: [x.foo * 10 for x in l]
myfunc([foo(1), foo(2), foo(3), foo(4)])
# returns [10, 20, 30, 40]

另外,它看起来更像您正在寻找的语法。

答案 12 :(得分:0)

是的,我非常想念 JavaScript 中直接的匿名对象,尤其是在函数返回值中,你可以直接说

function george() { 
    return {fred:6, jim:9}; 
}
x = george();
y = x.fred;

您可以使用字典来获得相同的效果,但是所有这些方括号和单引号看起来都很混乱。所以我现在执行以下操作:

def fred():
    class rv:
        x=0
    rv.y = 6
    return rv

def jim():
    class rv:
        x=0
    rv.y = 9
    return rv
a = fred()
b = jim()
print(a.y, b.y, id(a.y), id(b.y))

拥有一个全局类 RV 感觉更好,并实例化它以获得相同的效果,但这样函数就没有外部依赖了。