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?
Рассматривали ли вы использование именованного кортежа ?
Использование вашей нотации диктовки
>>> 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)
, но лично я считаю глупым давать имена «анонимным» функциям
Почему бы просто не использовать словарь?
p = {'name': 'John Smith', 'age': 23}
print p
print p['name']
print p['age']
В большинстве случаев достаточно простого словаря.
Если вы ищете API, аналогичный тому, который вы указали для буквального случая, вы все равно можете использовать словари и просто переопределить специальную функцию __ getattr __
:
class CustomDict(dict):
def __getattr__(self, name):
return self[name]
p = CustomDict(user='James', location='Earth')
print p.user
print p.location
Примечание : Оставить в Однако имейте в виду, что, в отличие от namedtuples, поля не проверяются, и вы отвечаете за то, чтобы ваши аргументы были разумными. Такие аргументы, как p ['def'] = 'something'
допускаются внутри словаря, но вы не сможете получить к ним доступ через p.def
.
Из Python IAQ :
Начиная с Python 2.3 вы можете использовать синтаксис
dict ( а = 1, б = 2, с = 3, ди = 4)
, что, на мой взгляд, достаточно хорошо. До Python 2.3 я использовал однострочную функцию
def Dict (** dict): return dict
Я думаю, что объектные литералы имеют смысл в JavaScript по двум причинам:
В JavaScript объекты - это единственный способ создать «вещь» со свойствами строкового индекса. В Python, как отмечено в другом ответе, это делает тип словаря.
Объектная система JavaScript основана на прототипах. В JavaScript нет такой вещи, как класс (хотя он появится в будущей версии) - объекты имеют объекты-прототипы вместо классов. Таким образом, естественно создавать объект «из ничего» с помощью литерала, потому что всем объектам требуется только встроенный корневой объект в качестве прототипа. В Python у каждого объекта есть класс - от вас вроде как ожидается, что вы будете использовать объекты для вещей, где у вас будет несколько экземпляров, а не только для разовых.
Таким образом, нет, объектные литералы не являются Pythonic, но они являются JavaScripthonic.
Я не вижу ничего плохого в создании «анонимных» классов / экземпляров. Часто бывает очень удобно создать его с простым вызовом функции в одной строке кода. Я лично использую что-то вроде этого:
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 __
.
Я не знаю, питонический он или нет, но иногда он ускоряет работу, и для меня это достаточно веская причина для его использования (иногда).
Из 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