2010-07-26 20 views
30

JavaScript zawiera literały obiektowe, np.Czy literały obiektowe są Pythoniczne?

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

i .NET ma typy anonimowe, np.

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

Coś podobnego może być emulowane w Pythonie przez (AB) z wykorzystaniem wymienionych argumentów:

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) 

Zastosowanie:

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

Ale jest to rodzaj kodu uznane za pythonowy?

+1

"pythonic", lubię to słowo! –

+3

Pętla 'for' w twoim' __init__' może być zamieniona na 'self .__ dict__ = kw'' –

Odpowiedz

34

Czy rozważałeś użycie named tuple?

Korzystanie z notacji DICT

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

lub argumenty słów kluczowych

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

Możliwe jest owinąć to zachowanie do funkcji dość łatwo

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

równowartość lambda byłoby

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

ale osobiście myślę, że to głupie nazwy nadając "anonimowi" Funkcje

+0

Co powiesz na PyRec? (http://www.valuedlessons.com/2009/10/introducing-pyrec-cure-to-bane-of-init.html) – Plumenator

+0

Tak, przyjrzałem się nazwanej krotce, ale czy nie narusza ona DRY zasada? Konstruowanie obiektu wymaga dwukrotnego określenia nazw każdego pola. Oczywiście można to obejść: literal = lambda ** kwargs: namedtuple ("literal", ".join (kwargs.keys())) (** kwargs); p = literal (name = 'John Smith', wiek = 23) (kod nie testowany, nie mam Py2.6 na mojej maszynie) – ShinNoNoir

+1

@ShinNoNoir, tworzenie funkcji fabrycznej jest trochę łatwiejsze niż twoja sugestia, ponieważ 'namedtuple' jest dość elastyczny o drugim parametrze –

59

Dlaczego po prostu nie używać słownika?

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

print p 
print p['name'] 
print p['age'] 
+8

Możesz także użyć funkcji' dict': 'p = dict (name = 'John Smith', age = 23)' –

+0

Cóż, tak, dyktatury są mniej więcej równoważne. Sugestia Tomasza jest również dobrym alternatywnym sposobem ich konstruowania. Mimo to, dostęp do "pól" dyktatury nie jest tak miły jak w moim przykładzie kodu, chociaż jest to tylko mała niedogodność składniowa. – ShinNoNoir

+2

Chociaż zgadzam się, myślę, że w pracy istnieje filozoficzna różnica. Dominującą filozofią w Pythonie jest to, że jeśli potrzebujesz obiektu z '.name' i' .age', powinieneś jawnie utworzyć ten obiekt, ze wszystkimi jego konstruktorami, itd. –

7

Od 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

Z Python IAQ:

Jak Pythona 2.3 można użyć składnia:

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

co jest wystarczająco dobre, o ile mi wiadomo. Przed Pythonie 2.3 użyłem funkcji jednej linii

def Dict(**dict): return dict 
1

myślę literały obiektowe sensu w JavaScript z dwóch powodów:

  1. W JavaScript, obiekty są jedynym sposobem, aby stworzyć „coś "Z właściwościami indeksu łańcuchowego. W Pythonie, jak zauważono w innej odpowiedzi, typ słownika to robi.

  2. System obiektowy JavaScript jest oparty na prototypach. W JavaScript nie ma czegoś takiego jak klasa (choć pojawia się w przyszłej wersji) - obiekty mają obiekty prototypowe zamiast klas. Zatem naturalne jest tworzenie obiektu "z niczego" poprzez literał, ponieważ wszystkie obiekty wymagają tylko wbudowanego obiektu root jako prototypu.W Pythonie każdy obiekt ma klasę - możesz oczekiwać, że użyjesz obiektów do rzeczy, w których miałbyś wiele instancji, a nie tylko jednorazowych.

Zatem nie, literały obiektowe nie są pythonowy, ale są one JavaScripthonic.

+0

Może JavaScriptonic? :-) – Plumenator

+3

Nie, to napój gazowany często mieszany z DOM Gin. –

+2

Nie zgadzam się - w JavaScript istnieje tylko jeden sposób na stworzenie obiektu podobnego do dyktatury, ale dostęp do niego można uzyskać na wiele sposobów - za pomocą składni "obj.prop" i "obj [" prop "] - co jest dość fajny pomysł, który można zaimplementować w Pythonie, jeśli ktoś tego chce (odpowiedź Unode poniżej). Ponadto - klasy są również obiektami (w Pythonie), więc używanie ich jako jednorazowych kontenerów dla atrybutów może być przydatne od czasu do czasu (gdy mamy do czynienia z API, które chce mieć "__getattr__" zaimplementowane przy czymś przekazanym). – cji

2

Nie widzę niczego złego w tworzeniu "anonimowych" klas/wystąpień. Często jest bardzo wygodnie tworzyć z prostym wywołaniem funkcji w jednym wierszu kodu. Osobiście używam czegoś takiego:

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 

Do tworzenia obiektów obojętnych działa dobrze. Namedtuple jest w porządku, ale jest niezmienny, co czasami może być niewygodne. A słownik to ... no cóż, słownik, ale zdarzają się sytuacje, kiedy trzeba podać coś z __getattr__ zdefiniowanym, zamiast __getitem__.

Nie wiem, czy to pyton, czy nie, ale czasami przyspiesza to i dla mnie jest wystarczająco dobry powód, aby go używać (czasami).

+0

Interesujące podejście, z wyjątkiem 'make_class', faktycznie konstruuje obiekt. Istnieje również problem polegający na tym, że nie możesz mieć atrybutu o nazwie 'name' w swoim podejściu. (Ale zauważam, że mam podobny problem w mojej "literalnej" klasie ... nie mogę mieć atrybutu o nazwie 'self'). – ShinNoNoir

+2

Właściwie jest to "obiekt klasy" - tutaj jest tworzony instancja: make_class (...)() '. Myślę? A co do kolizji nazw - Prawda. – cji

1

Dla większości przypadków powinien wystarczyć prosty słownik.

Jeśli szukasz podobnym API do jednego wskazanego przez dosłownym przypadku, nadal można korzystać ze słowników i po prostu zastąpić specjalną __getattr__ funkcję:

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

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

Uwaga: Należy pamiętać jednak, w przeciwieństwie do nazwanych, pola nie są sprawdzane, a Ty jesteś odpowiedzialny za upewnienie się, że twoje argumenty są rozsądne. Argumenty takie jak p['def'] = 'something' są tolerowane w słowniku, ale nie będzie można uzyskać do nich dostępu poprzez p.def.

Powiązane problemy