Bir nesneyi nasıl oluşturabilir ve ona nasıl nitelik ekleyebilirim?


310

Python'da (başka bir nesnenin içinde) dinamik bir nesne oluşturmak ve sonra öznitelikler eklemek istiyorum.

Denedim:

obj = someobject
obj.a = object()
setattr(obj.a, 'somefield', 'somevalue')

ama bu işe yaramadı.

Herhangi bir fikir?

Düzenle:

forDeğerler listesi, örneğin döngüler bir döngü öznitelikleri ayarlıyorum

params = ['attr1', 'attr2', 'attr3']
obj = someobject
obj.a = object()

for p in params:
   obj.a.p # where p comes from for loop variable

Ben alacağı Yukarıdaki örnekte obj.a.attr1, obj.a.attr2, obj.a.attr3.

Bu setattrişlevi kullandım çünkü obj.a.NAMEbir fordöngüden nasıl yapılacağını bilmiyordum .

pYukarıdaki örnekte belirtilen değere dayalı olarak özelliği nasıl ayarlayabilirim ?


4
"İşe yaramadı" ile ne demek istiyorsun? Bir AttributeError istisnası oluşturduğunu varsayıyorum, değil mi?
Josh Wright

1
Evet. 'object' nesnesinin 'somefield' özelliği yoktur
John

6
Bunu neden yapıyorsun? Genel bir "nesne" nin gerçek bir anlamı yoktur . Yarattığınız şeyin anlamı nedir ? Neden uygun bir sınıf ya da adlandırılmış grup değil?
S.Lott

1
Örnek benim için minimal ve kafa karıştırıcı değil ya da neden bazılarıyla çalışmadığınızı a = object()ve ihtiyacınız olduğunu anlamıyorum obj.a = object(). Yine örnek hakkında konuşuyorum, gerçek kodunuzda bir nesnenin içindeki bir nesne yararlı olabilir.
kon psych

Yanıtlar:


215

Eski demet tarifimi kullanabilirsiniz , ancak bir "demet sınıfı" yapmak istemiyorsanız, Python'da çok basit bir tane var - tüm işlevlerin keyfi nitelikleri olabilir (lambda işlevleri dahil). Yani, aşağıdaki işler:

obj = someobject
obj.a = lambda: None
setattr(obj.a, 'somefield', 'somevalue')

Saygıdeğer tarifle karşılaştırıldığında netlik kaybının iyi olup olmadığı Bunchelbette size bırakacağım bir stil kararıdır.


25
@FogleBird, bahsettiğim gibi bir stil kararı. Kilise'nin lambda hesabında eğitilmiş bazı CS uzmanları, işlevlerin (lambdas) tüm verilerin temel türü (örneğin 23 tamsayı ile eşdeğer olarak görülebilir) olarak düşünülmesinde lambda: 23kullanılır lambda, bu nedenle bu amaçla s kullanan uzmanlar için muhtemelen "hack" gibi bir şey hissetmezdi. Şahsen, lambda Python'da çok sevmiyorum - ama bu çok kişisel bir mesele.
Alex Martelli

Ve bazı durumlarda, lambdakalıbın kullanım durumunuz için uygun olup olmadığını göz önünde bulundurmak , aslında veri olarak düşündüğünüz bir şeyin aslında zaten bir fonksiyona (veya her durumda bir fonktor) benzediğini fark etmenize neden olabilir.
Kyle Strand

5
@ naught101, bir fonksiyon olduğunu sizin itiraz dipsiz yani, Python bir nesne.
Alex Martelli

6
@ naught101, yeni bir türün (mevcut olanın yeniden kullanılması) yaratılmasından kaçınmayı zorlaştırmaz, basitleştirir. Günümüzde aslında from argparse import Namespacebaşka bir yerde yaşamasını diliyorum olsa da tercih edebilir * örneğin, collection) - yine mevcut olan bir türü tekrar kullanmak, sadece daha iyi olanı ve yine de yeni tip yaratımdan kaçınmak. Ama o zaman orada değildi :-).
Alex Martelli

1
Types modülünden SimpleNamespace ile ilgili olarak aşağıdaki "JF Sebastian" yanıtına bakınız. Python sürümünüz destekliyorsa, bu en iyi çözümdür (ve tam olarak SimpleNamespace'in ne için tasarlandığını)
Tim Richardson

334

Yerleşik objectörneği oluşturulmak ancak üzerinde ayarlanmış tüm özelliklerini sahip olamaz. (Keşke bu tam amaç için yapabilseydi.) __dict__Nitelikleri elinde tutamaz.

Genellikle sadece bunu yaparım:

class Object(object):
    pass

a = Object()
a.somefield = somevalue

Yapabildiğim zaman Object, ne tür veri koyduğuma bağlı olarak sınıfa daha anlamlı bir isim veriyorum.

Bazı insanlar farklı bir şey yaparlar, burada dictöznitelik erişiminin anahtarlara erişmesine izin veren bir alt sınıf kullanırlar . ( d.keyyerine d['key'])

Düzenleme : Sorunuza eklemek için kullanmak setattriyidir. Sadece kullanamazsınız setattrüzerinde object()örnekleri.

params = ['attr1', 'attr2', 'attr3']
for p in params:
    setattr(obj.a, p, value)

9
o olabilir sadece yapılmıştır yararlı bir kez herhangi bir şey için kullanılmaz, başlatılamaz. foo = object()çalışıyor, ancak bununla pek bir şey
yapamazsınız

Selam. Cevap için teşekkürler. Yukarıdaki sorunumu güncelledim. düzenlemeye bakın. bunun cevabını biliyor musun?
John

üzgünüm hala nesne üzerinde ayarlamak istiyorum. yukarıdaki güncellemeye bakın.
John

Cevabınızı gerçekten seviyorum ve sanırım gelecekte bu yöne yaslanacağım. Bu yazıdaki bu çok basit, anlaşılır ve okunabilir metodoloji dışında her şeyi kullandım. type....Kodumdaki metin kusması gibi, lambda kullanmak asla benim favorim değildi. Ancak bu fikir, nesneleri tutmak için nesneleri kullanmak için harikadır. Lambda'yı gördüğümde kodu daha okunaklı b / c bırakır. Teşekkürler.
Marc

harika bir cevap, değiştirdiğim tek şey Structdaha belirgin hale getirmek için sınıfın adı olarak kullanmaktı . Bana bir ton yazarak kurtardım ["ve "], Şerefe!
pragman

137

types.SimpleNamespacePython 3.3+ sürümünde sınıf var :

obj = someobject
obj.a = SimpleNamespace()
for p in params:
    setattr(obj.a, p, value)
# obj.a.attr1

collections.namedtuple, typing.NamedTupledeğişmez nesneler için kullanılabilir. PEP 557 - Veri Sınıfları değişken bir alternatif öneriyor.

Daha zengin bir işlevsellik için paketi deneyebilirsinizattrs . Örnek bir kullanıma bakın .


3
Python 2.7 ile çalışan bir şeye ihtiyacınız varsa, argparse.Namespacesınıfı da deneyebilirsiniz
RolKau

Katılıyorum - Burada bir dezavantaj olup olmadığını merak ediyorum, ama bu inanılmaz derecede kullanışlı bir python 3.3+ affordance.
ghukill

Lanet olsun! bu 2.7 kullanılabilir değil mi?
Roel

@Roel attrspaketi Python 2.7'yi destekliyor
jfs

Bu benim için unittest.mock'ten daha iyi bir çözüm gibi görünüyor; ikincisi biraz fazla ağır ve biraz daha dövülebilir. Bir sahte nesne ile, basitçe bir niteliğe atamak onun ortaya çıkmasına neden olur; SimpleNamespace buna direnecektir.
jdzions

32

Bu hedefe ulaşmanın birkaç yolu vardır. Temel olarak genişletilebilir bir nesneye ihtiyacınız vardır.

obj.a = type('Test', (object,), {})  
obj.a.b = 'fun'  

obj.b = lambda:None

class Test:
  pass
obj.c = Test()

14
obj.a = type('', (), {})
iman


21

Şimdi yapabilirsiniz (evilpie ile aynı cevap olup olmadığından emin değilim):

MyObject = type('MyObject', (object,), {})
obj = MyObject()
obj.value = 42

@ evilpie'nin cevabı, sizinki gibi değil, doğrudan MyObject (sınıf) üzerindeki öznitelikleri ayarlar.
jfs

18

Aşağıdaki kodu deneyin:

$ python
>>> class Container(object):
...     pass 
...
>>> x = Container()
>>> x.a = 10
>>> x.b = 20
>>> x.banana = 100
>>> x.a, x.b, x.banana
(10, 20, 100)
>>> dir(x)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__',     '__sizeof__', 
'__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'banana']

1
Bunun ne yaptığını daha fazla açıklayabilir misiniz? kod bu sorunu çözmek için yararlı olabilir, ancak açıklanması bir sorundan çok daha fazlasını yapabilir.
DeadChex

1
@DeadChex Açıkça nesne özelliklerine sahip boş bir sınıf olan yeni bir Sınıf (nesne) oluşturur ve nitelikleri sınıf içinde saklar. Bu, daha fazla modül kurmaktan veya lambdalara güvenmekten daha iyidir.
m3nda

2
Bunun neden daha fazla oyu olmadığından emin değilim. Bunu temel bir kap sınıfı için kullanmamanın bir nedeni var mı? Python 2.7, 2.6 ve 3.4'te iyi çalışıyor gibi görünüyor
user5359531

17

Ayrıca bir sınıf nesnesini doğrudan da kullanabilirsiniz; bir ad alanı oluşturur:

class a: pass
a.somefield1 = 'somevalue1'
setattr(a, 'somefield2', 'somevalue2')

9

olarak docs demek :

Not : objectyok değil bir var __dict__yapabilirsiniz kadar değil atama keyfi nitelikleri örneğine, objectsınıfa.

Sadece kukla sınıf örneği kullanabilirsiniz.


2

Bu çözümler test sırasında çok faydalıdır. Herkesin cevapları üzerine inşa Python 2.7.9 (statik yöntem olmadan bir TypeError olsun (bağlı olmayan yöntem ...):

In [11]: auth = type('', (), {})
In [12]: auth.func = staticmethod(lambda i: i * 2)
In [13]: auth.func(2)
Out[13]: 4

1

Hangi nesneleri kullanıyorsunuz? Sadece bir örnek sınıf ile denedim ve iyi çalıştı:

class MyClass:
  i = 123456
  def f(self):
    return "hello world"

b = MyClass()
b.c = MyClass()
setattr(b.c, 'test', 123)
b.c.test

Ve 123cevap aldım .

Bu başarısızlığı gördüğüm tek durum, setattryerleşik bir nesnede deniyorsanız .

Güncelleme: Yorumdan bu bir tekrar: Python'daki nesneye neden özellikler ekleyemiyorsunuz?


bc, tanımlanmış bir sınıfa değil () nesnesine ayarlandı
John

0

Günün geç saatlerinde geliyor ama burada bir uygulamada bazı yararlı yolları tutan bir nesne ile benim pennyworth ama getattr ve nokta gösterimi ile erişebileceğiniz bir bilgi sorgusu istediğiniz herhangi bir şey için uyarlayabilirsiniz (Bu sorunun gerçekten ilgili olduğunu düşünüyorum):

import os

def x_path(path_name):
    return getattr(x_path, path_name)

x_path.root = '/home/x'
for name in ['repository', 'caches', 'projects']:
    setattr(x_path, name, os.path.join(x_path.root, name))

Bu harika çünkü şimdi:

In [1]: x_path.projects
Out[1]: '/home/x/projects'

In [2]: x_path('caches')
Out[2]: '/home/x/caches'

Dolayısıyla bu, yukarıdaki yanıtlar gibi işlev nesnesini kullanır, ancak değerleri almak için işlevi kullanır ( tercih ediyorsanız (getattr, x_path, 'repository')değil , yine de kullanabilirsiniz x_path('repository')).


0

Yuvalanmış nesneyi oluşturmadan önce tüm öznitelikleri ve değerleri birlikte belirleyip toplayabilirsek, oluşturma konusunda sözlük bağımsız değişkeni alan yeni bir sınıf oluşturabiliriz.

# python 2.7

class NestedObject():
    def __init__(self, initial_attrs):
        for key in initial_attrs:
            setattr(self, key, initial_attrs[key])

obj = someobject
attributes = { 'attr1': 'val1', 'attr2': 'val2', 'attr3': 'val3' }
obj.a = NestedObject(attributes)
>>> obj.a.attr1
'val1'
>>> obj.a.attr2
'val2'
>>> obj.a.attr3
'val3'

Anahtar kelime bağımsız değişkenlerine de izin verebiliriz. Bu gönderiye bakın .

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


obj.a = NestedObject(attr1='val1', attr2='val2', attr3= 'val3')

-2
di = {}
for x in range(20):
    name = '_id%s' % x
    di[name] = type(name, (object), {})
    setattr(di[name], "attr", "value")

-2

Başka şekilde görüyorum, bu şekilde:

import maya.cmds

def getData(objets=None, attrs=None):
    di = {}
    for obj in objets:
        name = str(obj)
        di[name]=[]
        for at in attrs:
            di[name].append(cmds.getAttr(name+'.'+at)[0])
    return di

acns=cmds.ls('L_vest_*_',type='aimConstraint')
attrs=['offset','aimVector','upVector','worldUpVector']

getData(acns,attrs)

attr adını bu di [ad] .append sonuna ekleyebilirsiniz ([at, cmds.getAttr (ad + '.' + at) [0]]))
Pablo Emmanuel De Leo

1
Bu çok büyük bir standart dışı bağımlılık eklerken bir basit class a: passgerekli tüm gücü verir.
Alexis Paques
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.