Являются ли объектные литералы Pythonic? - PullRequest
38 голосов
/ 26 июля 2010

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?

Ответы [ 7 ]

66 голосов
/ 26 июля 2010

Почему бы просто не использовать словарь?

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

print p
print p['name']
print p['age']
39 голосов
/ 26 июля 2010

Рассматривали ли вы использование именованного кортежа ?

Использование диктовки

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

лямбда-эквивалент будет

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

но лично я считаю глупым давать имена «анонимным» функциям

9 голосов
/ 26 июля 2010

С 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
2 голосов
/ 26 июля 2010

Для большинства случаев достаточно простого словаря.

Если вы ищете 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.

2 голосов
/ 26 июля 2010

Я не вижу ничего плохого в создании "анонимных" классов / экземпляров. Часто очень удобно создавать такой с простым вызовом функции в одной строке кода. Я лично использую что-то вроде этого:

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__.

Я не знаю, питон это или нет, но иногда это ускоряет процесс, и для меня это достаточно веская причина использовать его (иногда).

2 голосов
/ 26 июля 2010

Я думаю, что объектные литералы имеют смысл в JavaScript по двум причинам:

  1. В JavaScript объекты являются единственным способом создания «вещи» со свойствами строкового индекса. В Python, как отмечено в другом ответе, тип словаря делает это.

  2. Система объектов JavaScript основана на прототипах. В JavaScript нет такого понятия, как класс (хотя он появится в будущей версии) - объекты имеют объекты-прототипы вместо классов. Таким образом, естественно создать объект «из ничего», через литерал, потому что все объекты требуют только встроенный корневой объект в качестве прототипа. В Python у каждого объекта есть класс - вы как бы ожидаете использовать объекты для вещей, в которых у вас будет несколько экземпляров, а не только для одноразовых.

Таким образом, нет, объектные литералы не являются Pythonic, но они являются JavaScripthonic.

2 голосов
/ 26 июля 2010

Из Python IAQ :

Начиная с Python 2.3, вы можете использовать синтаксис

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

, который достаточно хорош, насколько яЯ обеспокоен.До Python 2.3 я использовал однострочную функцию

def Dict(**dict): return dict
...