Python'daki sözlükten nitelikleri ayarla


Yanıtlar:


172

Elbette, bunun gibi bir şey:

class Employee(object):
    def __init__(self, initial_data):
        for key in initial_data:
            setattr(self, key, initial_data[key])

Güncelleme

Brent Nash'in önerdiği gibi, anahtar kelime argümanlarına da izin vererek bunu daha esnek hale getirebilirsiniz:

class Employee(object):
    def __init__(self, *initial_data, **kwargs):
        for dictionary in initial_data:
            for key in dictionary:
                setattr(self, key, dictionary[key])
        for key in kwargs:
            setattr(self, key, kwargs[key])

O zaman şöyle diyebilirsiniz:

e = Employee({"name": "abc", "age": 32})

veya bunun gibi:

e = Employee(name="abc", age=32)

hatta bunun gibi:

employee_template = {"role": "minion"}
e = Employee(employee_template, name="abc", age=32)

4
İlk verileri def __init__(self,**initial_data)iletirken anahtar kelime argümanları da yapabilen bir init yöntemine sahip olmanın ek avantajını elde ederseniz (örneğin "e = Employee (name = 'Oscar')" veya sadece bir sözlüğe (örn. "E = Employee ( ** dikte) ").
Brent Kod Yazıyor

2
Her iki sunan Employee(some_dict)ve Employee(**some_dict)API'leri tutarsızdır. Hangisi daha iyi ise temin edilmelidir.
Mike Graham

4
Size ARG varsayılan ayarlarsanız ()yerine None, bunu öylesine gibi yapabilirdi: def __init__(self, iterable=(), **kwargs): self.__dict__.update(iterable, **kwargs).
Matt Anderson

4
Bunun eski bir soru olduğunu biliyorum, ancak sadece liste anlama ile iki satırda yapılabileceğini eklemek istiyorum, örneğin:[[setattr(self,key,d[key]) for key in d] for d in some_dict]
TZ

2
Bunun neden basit bir şekilde python'a dahil edilmediğini bilmek isterim. Bunu python GeoIP2 API fırlatmalarının üstesinden gelmek için kullanıyorum AddressNotFoundError(bu durumda düzeltilmiş verileri patlatmak yerine geri döndürmek için) - PHP'de ( (object) ['x' => 'y']) bu kadar kolay bir şeyin Python'da çok fazla
hile

47

Nitelikleri bu şekilde ayarlamak, neredeyse kesinlikle bir sorunu çözmenin en iyi yolu değildir. Ya:

  1. Tüm alanların önceden ne olması gerektiğini biliyorsunuz. Bu durumda, tüm nitelikleri açıkça ayarlayabilirsiniz. Bu benzeyecekti

    class Employee(object):
        def __init__(self, name, last_name, age):
            self.name = name
            self.last_name = last_name
            self.age = age
    
    d = {'name': 'Oscar', 'last_name': 'Reyes', 'age':32 }
    e = Employee(**d) 
    
    print e.name # Oscar 
    print e.age + 10 # 42 

    veya

  2. Tüm alanların önceden ne olması gerektiğini bilmiyorsunuz. Bu durumda, bir nesnenin ad alanını kirletmek yerine verileri bir dikte olarak depolamalısınız. Öznitelikler statik erişim içindir. Bu dava şöyle görünecekti

    class Employee(object):
        def __init__(self, data):
            self.data = data
    
    d = {'name': 'Oscar', 'last_name': 'Reyes', 'age':32 }
    e = Employee(d) 
    
    print e.data['name'] # Oscar 
    print e.data['age'] + 10 # 42 

Temel olarak durum 1'e eşdeğer olan başka bir çözüm, a kullanmaktır collections.namedtuple. Bunu nasıl uygulayacağınıza dair van'ın cevabına bakın.


Ya senaryo iki uç noktanız arasında bir yerde ise? Bu tam olarak bunun için kullanım durumudur ve şu anda AFAICT bunu KURU ve pitonik bir şekilde yapmanın bir yolu yoktur.
DylanYoung

15

__dict__İle bir nesnenin özniteliklerine erişebilir ve üzerinde güncelleme yöntemini çağırabilirsiniz:

>>> class Employee(object):
...     def __init__(self, _dict):
...         self.__dict__.update(_dict)
... 


>>> dict = { 'name': 'Oscar', 'lastName': 'Reyes', 'age':32 }

>>> e = Employee(dict)

>>> e.name
'Oscar'

>>> e.age
32

3
__dict__bir uygulama eseridir ve kullanılmamalıdır. Ayrıca bu, sınıf üzerinde tanımlayıcıların varlığını da göz ardı eder.
Ignacio Vazquez-Abrams

1
@Ignacio "uygulama eseri" ile ne demek istiyorsun? Neyin farkında olmamalıyız? Veya farklı platformlarda bulunmayabileceğini? (ör. Windows'ta Python ve Linux'ta Python) Kabul edilebilir bir cevap ne olabilir?
OscarRyz

12
__dict__dilin belgelenmiş bir parçasıdır, bir uygulama yapısı değildir.
Dave Kirby

3
Kullanarak setattrerişim için tercih edilir __dict__, doğrudan. __dict__Orada olmamanıza veya kullanırken istediğiniz şeyi yapmamaya yol açabilecek pek çok şeyi aklınızda tutmalısınız __dict__, ama setattraslında yapmakla neredeyse aynıdır foo.bar = baz.
Mike Graham

1
@DaveKirby: Genel kullanımı __dict__tavsiye edilmiyor gibi görünüyor : docs.python.org/tutorial/classes.html#id2
equaeghe

11

Neden öznitelik adlarını bir sözlüğün anahtarı olarak kullanmıyorsunuz?

class StructMyDict(dict):

     def __getattr__(self, name):
         try:
             return self[name]
         except KeyError as e:
             raise AttributeError(e)

     def __setattr__(self, name, value):
         self[name] = value

Adlandırılmış bağımsız değişkenler, bir tuple listesi veya bir sözlük veya bireysel öznitelik atamaları ile başlatabilirsiniz, örneğin:

nautical = StructMyDict(left = "Port", right = "Starboard") # named args

nautical2 = StructMyDict({"left":"Port","right":"Starboard"}) # dictionary

nautical3 = StructMyDict([("left","Port"),("right","Starboard")]) # tuples list

nautical4 = StructMyDict()  # fields TBD
nautical4.left = "Port"
nautical4.right = "Starboard"

for x in [nautical, nautical2, nautical3, nautical4]:
    print "%s <--> %s" % (x.left,x.right)

Alternatif olarak, öznitelik hatasını yükseltmek yerine bilinmeyen değerler için Yok döndürebilirsiniz. (Web2py depolama sınıfında kullanılan bir numara)


7

Bence settattrgerçekten desteğe ihtiyacınız varsa , cevabı kullanmanın yoludict .

Ancak Employeenesne, .namedict sözdizimi ( ['name']) yerine nokta sözdizimi ( ) ile erişebileceğiniz bir yapıysa , adlandırılmıştuple'ı şu şekilde kullanabilirsiniz :

from collections import namedtuple

Employee = namedtuple('Employee', 'name age')
e = Employee('noname01', 6)
print e
#>> Employee(name='noname01', age=6)

# create Employee from dictionary
d = {'name': 'noname02', 'age': 7}
e = Employee(**d)
print e
#>> Employee(name='noname02', age=7)
print e._asdict()
#>> {'age': 7, 'name': 'noname02'}

Sen var _asdict()erişmek için sözlük olarak tüm özellikleri yöntemi, ancak edemez , sadece inşaat sırasında, ileride ek özellikler eklemek.


6

örnek olarak söyle

class A():
    def __init__(self):
        self.x=7
        self.y=8
        self.z="name"

öznitelikleri bir kerede ayarlamak istiyorsanız

d = {'x':100,'y':300,'z':"blah"}
a = A()
a.__dict__.update(d)

1
kolaylık sağlamak için anahtar / değer a.__dict__.update(x=100, y=300, z="blah")
çiftleri

1

bir dict kullanmaya benzer şekilde, kwargs'ı şu şekilde kullanabilirsiniz:

class Person:
   def __init__(self, **kwargs):
       self.properties = kwargs

   def get_property(self, key):
       return self.properties.get(key, None)

   def main():
       timmy = Person(color = 'red')
       print(timmy.get_property('color')) #prints 'red'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.