51

JavaScript 有对象字面量,例如

var p = {
  name: "John Smith",
  age:  23
}

.NET 有匿名类型,例如

var p = new { Name = "John Smith", Age = 23}; // C#

类似的东西可以在 Python 中通过(ab)使用命名参数来模拟:

class literal(object):
    def __init__(self, **kwargs):
        for (k,v) in kwargs.iteritems():
            self.__setattr__(k, v)
    def __repr__(self):
        return 'literal(%s)' % ', '.join('%s = %r' % i for i in sorted(self.__dict__.iteritems()))
    def __str__(self):
        return repr(self)

用法:

p = literal(name = "John Smith", age = 23)
print p       # prints: literal(age = 23, name = 'John Smith')
print p.name  # prints: John Smith

但是这种代码是否被认为是 Pythonic 的?

4

8 回答 8

73

为什么不直接使用字典?

p = {'name': 'John Smith', 'age': 23}

print p
print p['name']
print p['age']
于 2010-07-26T13:39:40.860 回答
43

您是否考虑过使用命名元组

使用你的听写符号

>>> from collections import namedtuple
>>> L = namedtuple('literal', 'name age')(**{'name': 'John Smith', 'age': 23})

或关键字参数

>>> L = namedtuple('literal', 'name age')(name='John Smith', age=23)
>>> L
literal(name='John Smith', age=23)
>>> L.name
'John Smith'
>>> L.age
23

可以很容易地将这种行为包装到一个函数中

def literal(**kw):
    return namedtuple('literal', kw)(**kw)

等效的 lambda 将是

literal = lambda **kw: namedtuple('literal', kw)(**kw)

但我个人认为给“匿名”函数起名字是愚蠢的

于 2010-07-26T13:46:09.833 回答
14

ActiveState

class Bunch:
    def __init__(self, **kwds):
        self.__dict__.update(kwds)

# that's it!  Now, you can create a Bunch
# whenever you want to group a few variables:

point = Bunch(datum=y, squared=y*y, coord=x)

# and of course you can read/write the named
# attributes you just created, add others, del
# some of them, etc, etc:
if point.squared > threshold:
    point.isok = 1
于 2010-07-26T14:22:59.960 回答
3

我认为创建“匿名”类/实例没有任何问题。在一行代码中通过简单的函数调用创建一个通常非常方便。我个人使用这样的东西:

def make_class( *args, **attributes ):
    """With fixed inability of using 'name' and 'bases' attributes ;)"""
    if len(args) == 2:
        name, bases = args
    elif len(args) == 1:
        name, bases = args[0], (object, )
    elif not args:
        name, bases = "AnonymousClass", (object, )
    return type( name, bases, attributes )

obj = make_class( something = "some value" )()
print obj.something

对于创建虚拟对象,它工作得很好。Namedtuple 可以,但它是不可变的,这有时会带来不便。字典是……嗯,字典,但在某些情况下,你必须通过__getattr__定义的东西,而不是__getitem__.

我不知道它是否是 pythonic,但它有时会加快速度,对我来说,使用它(有时)是足够好的理由。

于 2010-07-26T17:10:47.417 回答
2

我想说你实现的解决方案看起来很 Pythonic;话虽如此,types.SimpleNamespace在此处记录)已经包含此功能:

from types import SimpleNamespace
p = SimpleNamespace(name = "John Smith", age = 23)
print(p)
于 2021-03-08T08:50:19.933 回答
1

来自Python IAQ

从 Python 2.3 开始,您可以使用语法

dict(a=1, b=2, c=3, dee=4)

就我而言,这已经足够好了。在 Python 2.3 之前我使用了单行函数

def Dict(**dict): return dict
于 2010-07-26T15:03:25.380 回答
1

我认为对象字面量在 JavaScript 中很有意义,原因有两个:

  1. 在 JavaScript 中,对象是创建具有字符串索引属性的“事物”的唯一方法。在 Python 中,正如另一个答案中所述,字典类型就是这样做的。

  2. JavaScript 的对象系统是基于原型的。JavaScript 中没有类之类的东西(尽管它会在未来的版本中出现)——对象有原型对象而不是类。因此,通过文字“从无到有”创建对象是很自然的,因为所有对象只需要内置的根对象作为原型。在 Python 中,每个对象都有一个类——你应该将对象用于具有多个实例的事物,而不仅仅是一次性的。

因此,不,对象文字不是 Pythonic,但它们是 JavaScripthonic。

于 2010-07-26T15:17:08.363 回答
1

大多数情况下,一个简单的字典就足够了。

如果您正在寻找与您为文字大小写指定的 API 类似的 API,您仍然可以使用字典并简单地覆盖特殊__getattr__功能:

class CustomDict(dict):
    def __getattr__(self, name):
        return self[name]

p = CustomDict(user='James', location='Earth')
print p.user
print p.location

注意:请记住,尽管与命名元组相反,字段没有经过验证,并且您负责确保您的参数是理智的。字典中允许使用诸如此类的参数,p['def'] = 'something'但您将无法通过p.def.

于 2010-07-26T17:11:59.413 回答