Bir sınıfa dinamik olarak özellik nasıl eklenir?


215

Amaç, db sonuç kümesi gibi davranan bir sahte sınıf oluşturmaktır.

Örneğin, bir veritabanı sorgusu bir dict ifadesi kullanarak döndürürse {'ab':100, 'cd':200}, o zaman görmek istiyorum:

>>> dummy.ab
100

İlk başta belki bu şekilde yapabileceğimi düşündüm:

ks = ['ab', 'cd']
vs = [12, 34]
class C(dict):
    def __init__(self, ks, vs):
        for i, k in enumerate(ks):
            self[k] = vs[i]
            setattr(self, k, property(lambda x: vs[i], self.fn_readyonly))

    def fn_readonly(self, v)
        raise "It is ready only"

if __name__ == "__main__":
    c = C(ks, vs)
    print c.ab

ancak c.abbunun yerine bir özellik nesnesi döndürür.

setattrHattı değiştirmek k = property(lambda x: vs[i])hiç bir işe yaramaz .

Peki çalışma zamanında bir örnek özelliği oluşturmanın doğru yolu nedir?

PS: Yöntem nasıl kullanılır? Bölümünde sunulan alternatifin farkındayım.__getattribute__


2
Kodunuzda birkaç yazım hatası var: fn_readonly'nin tanımı a :ve __init__referansları self.fn_readyonly.
mhawke

Haklısın. Çalışma zamanında bir özellik oluşturma nedeninin altını çizmek için bu ayarlayıcı işlevini son dakikada ekledim.
Anthony Kong

Başlatmada özellikler oluşturmayla ilgili ana sorun, bazı durumlarda yardımcıları hemen aradım veya bir sorun olsaydı, yaptıkları gerçeğine rağmen var olmayan bir hata alırdım. Aşağıdaki çözümümde 2 sınıf oluşturuyorum. Bir Base / Parent (kaçınmak için bir çözüm bulmaya çalışıyorum) ve Base / Parent'ı genişleten ana nesne olarak. Daha sonra ana nesnede, başlatmadan, özellikleri, yardımcı işlevleri ve daha fazlasını oluşturan AccessorFunc oluşturucumu çağırıyorum.
Acecool

yani: sınıf Örnek Tabanı: geçiş; sınıf Örneği (ÖrnekBaz): __x = Erişimci (ÖrnekBaz, 'x', 'X', 123); --- bu özellik x altında bir özellik oluşturur ve X için GetX, SetX ve daha fazlasını kullanarak fonksiyonlar adlandırır. Bu nedenle, .x, verilerin iletileceği özelliğin kendisidir (self.x = 123; veya self.x aracılığıyla çıktı almak / almak). Saklanan RAW verileri için self._x kullandım, böylece saklanan verilerde ayarlanmadan varsayılan değerlerin atanmasına izin verdiğim için kolayca erişilebilir. yani _x Hiçbiri olabilir ve .x 123. ve .__ x dönebilir. Accessor
Acecool ile

İşte dinamik özellikler ve dinamik işlevler oluşturan temel sürüme bir bağlantı - dosyanın diğer sürümlere bir sürü bağlantısı vardır. Biri yardımcıları oluşturmak için bir işlev kullanan AccessorFunc sistemidir (biri işlevler için, biri özellikler için, diğeri her iki öğe için ayrı olarak - bu dosyadaki herhangi bir şeyde kod kısaltması kullanmaz) .. Bir şey eksikse, diğer dosyalar: dropbox.com/s/phnnuavssmzeqrr/dynamic_properties_simple.py?dl=0
Acecool

Yanıtlar:


333

Sanırım bu cevabı genişletmeliyim, şimdi daha yaşlı ve daha akıllıyım ve neler olduğunu biliyorum. Geç olsun güç olmasın.

Sen edebilir bir sınıf dinamik bir özellik ekleyin. Ama işin aslı bu: sınıfa eklemelisin .

>>> class Foo(object):
...     pass
... 
>>> foo = Foo()
>>> foo.a = 3
>>> Foo.b = property(lambda self: self.a + 1)
>>> foo.b
4

A propertyaslında tanımlayıcı olarak adlandırılan bir şeyin basit bir uygulamasıdır . Belirli bir sınıf için belirli bir öznitelik için özel işlem sağlayan bir nesnedir . Büyük bir ifağacı etkisiz hale getirmenin bir yolu gibi __getattribute__.

Ben sorduğumda foo.byukarıdaki örnekte, Python görür bsınıf uygular tanımlanan açıklayıcısı protokolü sadece bir ile bir nesne demektir -ki __get__, __set__ya __delete__yöntemle. Tanımlayıcı bu özniteliğin işlenmesi sorumluluğunu üstlendiğinden Python çağırır Foo.b.__get__(foo, Foo)ve dönüş değeri özniteliğin değeri olarak size geri gönderilir. Durumunda property, bu yöntemlerin her biri sadece aramaları fget, fsetya fdelsen geçirilenproperty yapıcı.

Tanımlayıcılar gerçekten Python'un tüm OO uygulamasının tesisatını ortaya çıkarmanın yoludur. Aslında, daha da yaygın olan başka bir tanımlayıcı türü var property.

>>> class Foo(object):
...     def bar(self):
...         pass
... 
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x7f2a439d5dd0>>
>>> Foo().bar.__get__
<method-wrapper '__get__' of instancemethod object at 0x7f2a43a8a5a0>

Mütevazi yöntem sadece bir başka tanımlayıcıdır. Onun __get__ilk argüman olarak çağıran örneğinde çiviler; aslında bunu yapar:

def __get__(self, instance, owner):
    return functools.partial(self.function, instance)

Her neyse, bu yüzden tanımlayıcıların sadece sınıflar üzerinde çalıştığından şüpheleniyorum: bunlar ilk etapta sınıflara güç veren şeylerin resmileştirilmesidir. Hatta kuralın istisnasıdır: bir sınıfa tanımlayıcılar atayabilirsiniz ve sınıflar kendileri için bir örnektir type! Aslında, okumaya çalışmak Foo.bhala çağırıyor property.__get__; tanımlayıcıların sınıf öznitelikleri olarak eriştiklerinde kendilerini döndürmeleri deyimseldir.

Bence neredeyse tüm Python'un OO sisteminin Python ile ifade edilebilmesi çok güzel. :)

Oh, ve eğer ilgileniyorsanız bir süre önce tanımlayıcılar hakkında bir wordy blog yazısı yazdım .


35
Add_property yöntemini eklemenize gerek yok. setattr (Foo, 'name', property (func))
Courtney D

8
"Ama işte bu yakalamak ..." sadece birkaç saat çalışmamı sağladı. Teşekkür ederim.
Matt Howell


1
@ myproperty.setter ne olacak? Dinamik olarak nasıl eklenir?
LRMAAX

Başlatılan bir nesneye özellik eklemenize gerek yoktur. Bunu yapmak yalnızca örneğe yapıştığı anlamına gelebilir, ancak bunu iki kez kontrol etmek zorunda kalacağım. Dinamik özelliklerimin yalnızca örnek olduğu benzer bir sorunla karşılaştığımı biliyorum, aynı zamanda statik bir kurulumla sonuçlandım ve nesneye olan istediğim şey bu yüzden gelecekteki başlatmalar onları kullanacaktı. Yazım aşağıdadır ve yardımcı işlevler ve her şeye kolayca erişmenin kolay yollarını oluşturur. özellik için .x, alıcı / ayarlayıcının kullandığı ham veriler için ._x (hiçbiri olabilir) ve erişimci nesnesi için .__ x.
Acecool

57

Amaç, db sonuç kümesi gibi davranan bir sahte sınıf oluşturmaktır.

Peki, istediğiniz [b] kelimesini ab olarak yazabileceğiniz bir sözlüktür?

Bu kolay:

class atdict(dict):
    __getattr__= dict.__getitem__
    __setattr__= dict.__setitem__
    __delattr__= dict.__delitem__

1
daha genel bir kurulumda, bu sınırlı bir amaca hizmet eder. dikte çok düzeyli bir hiyerarşi varsa, örneğin d = {'a1': {'b': 'c'}, 'a2': ...}, o zaman d.a1 veya d.a2 yaparken, ' t do d.a1.b
Shreyas

1
Akılda tutulması gereken bir şey bu dict yöntemleri veya nitelikler aynı adı taşıyan özellikler için özellik değerlerini ayarlayarak izin verdiğini, ancak aynı şekilde tekrar değerleri almak izin vermez: d.items = 1, d.itemsdöner <built-in method items of atdict object at ...>. Hala yapabileceğini d["items"]veya kullanmak __getattribute__yerine __getattr__, ancak bu engeller Dict en yöntemlerin çoğu kullanılarak.
Marcono1234

Sadece munch kütüphanesini kullanın ! (çatal çatalı)
Brian Peterson

38

Öndeki namedtuplealanların tümünü önceden bildiğiniz için bu sorunu a ile çok daha basit bir şekilde çözebilirsiniz .

from collections import namedtuple

Foo = namedtuple('Foo', ['bar', 'quux'])

foo = Foo(bar=13, quux=74)
print foo.bar, foo.quux

foo2 = Foo()  # error

Kesinlikle kendi ayarlayıcınızı yazmanız gerekiyorsa, meta programlamayı sınıf düzeyinde yapmanız gerekir; property()örnekler üzerinde çalışmaz.


İyi fikir. Ne yazık ki şu anda python 2.4 ile sıkışıp kaldım.
Anthony Kong


2
Yazan adam, namedtuplesadık nesne yönelimli ilkeler olmayı pürüzsüz ve zarif hale getirdiği için bir ödülü hak ediyor.
Keith Pinson

4
Maalesef, en iyi ihtimalle, bu cevap yalnızca önceden salt okunur niteliklerden oluşan bir wanteda sınıfının bildiği özel durum için geçerlidir. Başka bir deyişle, çalışma zamanında bir sınıfa (salt okunur olanlar değil) genel özelliklerin nasıl ekleneceği konusunda daha geniş bir soruyu ele aldığını düşünmüyorum (ne de diğer "eklenti" yanıtı) yazar tarafından yayınlanan).
martineau

@martineau yani ... daha fazla argüman iletilsin property()mi? her iki yanıtta da salt okunur özelliklere özgü hiçbir şey yoktur.
Eevee

32

Bunun için bir mülk kullanmanıza gerek yoktur. __setattr__Onları salt okunur yapmak için geçersiz kılmanız yeterlidir .

class C(object):
    def __init__(self, keys, values):
        for (key, value) in zip(keys, values):
            self.__dict__[key] = value

    def __setattr__(self, name, value):
        raise Exception("It is read only!")

Tada.

>>> c = C('abc', [1,2,3])
>>> c.a
1
>>> c.b
2
>>> c.c
3
>>> c.d
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'd'
>>> c.d = 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __setattr__
Exception: It is read only!
>>> c.a = 'blah'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __setattr__
Exception: It is read only!

9

Dinamik olarak bir python sınıfına özellik nasıl eklenir?

Özellik eklemek istediğiniz bir nesneniz olduğunu varsayalım. Tipik olarak, ben tutarlı bir API korumak, böylece aşağı akış kullanımı olan kod bir özniteliğe erişimi yönetmeye başlamak gerektiğinde özelliklerini kullanmak istiyorum. Şimdi bunları genellikle nesnenin tanımlandığı kaynak koduna ekleyeceğim, ancak bu erişime sahip olmadığınızı veya işlevlerinizi gerçekten dinamik olarak programlı olarak seçmeniz gerektiğini varsayalım.

Sınıf oluşturun

İçin dokümantasyonaproperty dayalı bir örnek kullanarak , "gizli" özniteliğe sahip bir nesne sınıfı oluşturalım ve bunun bir örneğini oluşturalım:

class C(object):
    '''basic class'''
    _x = None

o = C()

Python'da bir şeyler yapmanın bariz bir yolu olmasını bekliyoruz. Ancak, bu durumda, iki yol göstereceğim: dekoratör gösterimi ile ve olmadan. İlk olarak, dekoratör notasyonu olmadan. Bu, alıcıların, ayarlayıcıların veya silicilerin dinamik ataması için daha yararlı olabilir.

Dinamik (diğer adıyla Maymun Düzeltme)

Sınıfımız için biraz yaratalım:

def getx(self):
    return self._x

def setx(self, value):
    self._x = value

def delx(self):
    del self._x

Ve şimdi bunları mülke tayin ediyoruz. Dinamik soruyu cevaplayarak fonksiyonlarımızı burada programlı olarak seçebileceğimizi unutmayın:

C.x = property(getx, setx, delx, "I'm the 'x' property.")

Ve kullanım:

>>> o.x = 'foo'
>>> o.x
'foo'
>>> del o.x
>>> print(o.x)
None
>>> help(C.x)
Help on property:

    I'm the 'x' property.

Dekoratörler

Biz dekoratör gösterimi ile yukarıda yaptığımız gibi aynı yapabiliriz, ama bu durumda, biz gereken o kadar programlı atama şekilde önemsiz değildir, yöntemleri hepsi aynı ismi (ve ben niteliği olarak bunu aynı tutarak öneriyoruz) yukarıdaki yöntemi kullanıyor:

@property
def x(self):
    '''I'm the 'x' property.'''
    return self._x

@x.setter
def x(self, value):
    self._x = value

@x.deleter
def x(self):
    del self._x

Ve özellik nesnesini sağlanan ayarlayıcıları ve silmeleriyle sınıfa atayın:

C.x = x

Ve kullanım:

>>> help(C.x)
Help on property:

    I'm the 'x' property.

>>> o.x
>>> o.x = 'foo'
>>> o.x
'foo'
>>> del o.x
>>> print(o.x)
None

5

Ben basit türleri oluşturulan bir sınıf fabrika oluşturmak için bu Stack Overflow yazı benzer bir soru sordum . Sonuç, sınıf fabrikasının çalışan bir versiyonuna sahip olan bu cevaptı . İşte cevabın bir pasajı:

def Struct(*args, **kwargs):
    def init(self, *iargs, **ikwargs):
        for k,v in kwargs.items():
            setattr(self, k, v)
        for i in range(len(iargs)):
            setattr(self, args[i], iargs[i])
        for k,v in ikwargs.items():
            setattr(self, k, v)

    name = kwargs.pop("name", "MyStruct")
    kwargs.update(dict((k, None) for k in args))
    return type(name, (object,), {'__init__': init, '__slots__': kwargs.keys()})

>>> Person = Struct('fname', 'age')
>>> person1 = Person('Kevin', 25)
>>> person2 = Person(age=42, fname='Terry')
>>> person1.age += 10
>>> person2.age -= 10
>>> person1.fname, person1.age, person2.fname, person2.age
('Kevin', 35, 'Terry', 32)
>>>

Amacınız olan varsayılan değerleri oluşturmak için bunun bazı varyasyonlarını kullanabilirsiniz (bu soruda bununla ilgilenen bir cevap da vardır).


4

Soruyu tamamen anladığımdan emin değilim, ancak çalışma zamanında örnek özelliklerini __dict__sınıfınızın yerleşikiyle değiştirebilirsiniz :

class C(object):
    def __init__(self, ks, vs):
        self.__dict__ = dict(zip(ks, vs))


if __name__ == "__main__":
    ks = ['ab', 'cd']
    vs = [12, 34]
    c = C(ks, vs)
    print(c.ab) # 12

Aslında sorum, çalışma zamanında yeni bir mülk oluşturmanın mümkün olup olmadığını öğrenmek. Fikir birliği negatif görünüyor. Öneriniz kesinlikle basit ve pratiktir. ( Dict kullanan diğer cevaplarla aynı )
Anthony Kong

Basit bir cevap da şöyle olurdu:self.__dict__[key] = value
Allan Karlson

4

Arama motorlarından gelenler için, dinamik özellikler hakkında konuşurken aradığım iki şey :

class Foo:
    def __init__(self):
        # we can dynamically have access to the properties dict using __dict__
        self.__dict__['foo'] = 'bar'

assert Foo().foo == 'bar'


# or we can use __getattr__ and __setattr__ to execute code on set/get
class Bar:
    def __init__(self):
        self._data = {}
    def __getattr__(self, key):
        return self._data[key]
    def __setattr__(self, key, value):
        self._data[key] = value

bar = Bar()
bar.foo = 'bar'
assert bar.foo == 'bar'

__dict__ dinamik olarak oluşturulan özellikler koymak istiyorsanız iyidir. __getattr__veritabanını sorgulamak gibi yalnızca değer gerektiğinde bir şeyler yapmak iyidir. Set / get combo, sınıfta depolanan verilere erişimi kolaylaştırmak için iyidir (yukarıdaki örnekte olduğu gibi).

Yalnızca bir dinamik özellik istiyorsanız, property () yerleşik işlevine bir göz atın .


4

property()Özellikler veri tanımlayıcıları olduğu için çalışma zamanında bir örneğe yeni ekleyemezsiniz . Bunun yerine, dinamik olarak yeni bir sınıf oluşturmanız veya __getattribute__örneklerde veri tanımlayıcılarını işlemek için aşırı yüklemeniz gerekir .


Bu yanlış. Özelliği sınıfa ekleyebilir ve daha sonra yönteme erişebilirsiniz.
Ahmed

2

Bunu başarmanın en iyi yolu tanımlamaktır __slots__. Bu şekilde örneklerinizin yeni özellikleri olamaz.

ks = ['ab', 'cd']
vs = [12, 34]

class C(dict):
    __slots__ = []
    def __init__(self, ks, vs): self.update(zip(ks, vs))
    def __getattr__(self, key): return self[key]

if __name__ == "__main__":
    c = C(ks, vs)
    print c.ab

Yazdırır 12

    c.ab = 33

Bu şunu verir: AttributeError: 'C' object has no attribute 'ab'


2

İstenen etkiye nasıl ulaşılacağı başka bir örnek

class Foo(object):

    _bar = None

    @property
    def bar(self):
        return self._bar

    @bar.setter
    def bar(self, value):
        self._bar = value

    def __init__(self, dyn_property_name):
        setattr(Foo, dyn_property_name, Foo.bar)

Şimdi şu gibi şeyler yapabiliriz:

>>> foo = Foo('baz')
>>> foo.baz = 5
>>> foo.bar
5
>>> foo.baz
5

2

İşte bir çözüm:

  • Özellik adlarının dize olarak belirtilmesine izin verir , böylece programınızda listelenenlerin tümü yerine bazı dış veri kaynaklarından gelebilirler.
  • Her nesne oluşturulduğunda yerine sınıf tanımlandığında özellikleri ekler .

Sınıf tanımlandıktan sonra bunu dinamik olarak bir özellik eklemek için yaparsınız:

setattr(SomeClass, 'propertyName', property(getter, setter))

İşte Python 3'te test edilen tam bir örnek:

#!/usr/bin/env python3

class Foo():
  pass

def get_x(self):
  return 3

def set_x(self, value):
  print("set x on %s to %d" % (self, value))

setattr(Foo, 'x', property(get_x, set_x))

foo1 = Foo()
foo1.x = 12
print(foo1.x)

1

Bir sözlük nesnesi kullanarak sınıf niteliklerini güncellemek için aşağıdaki kodu kullanabilirsiniz:

class ExampleClass():
    def __init__(self, argv):
        for key, val in argv.items():
            self.__dict__[key] = val

if __name__ == '__main__':
    argv = {'intro': 'Hello World!'}
    instance = ExampleClass(argv)
    print instance.intro

1

Bu OP'nin istediklerinden biraz farklı, ama çalışan bir çözüm bulana kadar beynimi salladım, bu yüzden bir sonraki adam / gal için buraya koyuyorum

Dinamik ayarlayıcıları ve alıcıları belirtmek için bir yola ihtiyacım vardı.

class X:
    def __init__(self, a=0, b=0, c=0):
        self.a = a
        self.b = b
        self.c = c

    @classmethod
    def _make_properties(cls, field_name, inc):
        _inc = inc

        def _get_properties(self):
            if not hasattr(self, '_%s_inc' % field_name):
                setattr(self, '_%s_inc' % field_name, _inc)
                inc = _inc
            else:
                inc = getattr(self, '_%s_inc' % field_name)

            return getattr(self, field_name) + inc

        def _set_properties(self, value):
            setattr(self, '_%s_inc' % field_name, value)

        return property(_get_properties, _set_properties)

Önceden alanlarımı biliyorum böylece benim özellikleri oluşturmak için gidiyorum. Not: bunu PER örneğini yapamazsınız, bu özellikler sınıfta var olacak !!!

for inc, field in enumerate(['a', 'b', 'c']):
    setattr(X, '%s_summed' % field, X._make_properties(field, inc))

Şimdi hepsini test edelim ..

x = X()
assert x.a == 0
assert x.b == 0
assert x.c == 0

assert x.a_summed == 0  # enumerate() set inc to 0 + 0 = 0
assert x.b_summed == 1  # enumerate() set inc to 1 + 0 = 1
assert x.c_summed == 2  # enumerate() set inc to 2 + 0 = 2

# we set the variables to something
x.a = 1
x.b = 2
x.c = 3

assert x.a_summed == 1  # enumerate() set inc to 0 + 1 = 1
assert x.b_summed == 3  # enumerate() set inc to 1 + 2 = 3
assert x.c_summed == 5  # enumerate() set inc to 2 + 3 = 5

# we're changing the inc now
x.a_summed = 1 
x.b_summed = 3 
x.c_summed = 5

assert x.a_summed == 2  # we set inc to 1 + the property was 1 = 2
assert x.b_summed == 5  # we set inc to 3 + the property was 2 = 5
assert x.c_summed == 8  # we set inc to 5 + the property was 3 = 8

Kafa karıştırıcı mı? Evet, üzgünüm anlamlı gerçek dünya örnekleri bulamadım. Ayrıca, bu yürekli ışık için değil.


Doğru hatırlıyorsam, tüm testlerim sırasında STATIC tipi özellik / dinamik olarak eklenen g / setter oluşturmak için bir yol buldum. Öncekilerimin hepsinden geçmek zorunda kalırdım - ancak tüm örnekler arasında paylaşılan bir şey ekleyebilmek kesinlikle mümkündür. Örnek başına bir işlemde oluşturmaya gelince ... Eminim ki bir örnek başka bir şeyin sahip olmadığı bir şeye sahip olur. Doğrulamak zorundayım, ama böyle bir şeyle de karşılaştım (ilk denemelerimde, işlevlerin yaratılmasına neden olan bir hata yaptım, ancak tüm örneklerin bir kusur nedeniyle bunlara sahip olmadığı)
Acecool

Ayrıca, bu bir bilgi deposu olduğu için olası her çözüm açıktır. Farklı insanların bir soruna çözüm üretmenin farklı yollarını görmek de heyecan verici. Benim çözümüm LOT yapıyor, bunu paylaşmak için daha basit bir şeye indirdiniz. Ben de benim daha küçük bir varyantı yaptım - bu konuda bir yerde olmalı - ve ben sadece bu benim yayınladığım olmadığını fark ettim: -) ...
Acecool

0

Bu işe yarıyor gibi görünüyor (ama aşağıya bakınız):

class data(dict,object):
    def __init__(self,*args,**argd):
        dict.__init__(self,*args,**argd)
        self.__dict__.update(self)
    def __setattr__(self,name,value):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be set"%(name,self.__class__.__name__)
    def __delattr__(self,name):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be deleted"%(name,self.__class__.__name__)

Daha karmaşık davranışlara ihtiyacınız varsa, yanıtınızı düzenlemekten çekinmeyin.

Düzenle

Aşağıdakiler büyük veri kümeleri için muhtemelen bellekte daha verimli olacaktır:

class data(dict,object):
    def __init__(self,*args,**argd):
        dict.__init__(self,*args,**argd)
    def __getattr__(self,name):
        return self[name]
    def __setattr__(self,name,value):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be set"%(name,self.__class__.__name__)
    def __delattr__(self,name):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be deleted"%(name,self.__class__.__name__)

0

Sorunuzun ana yönünü cevaplamak için, bir diksiyondan değiştirilemez bir veri kaynağı olarak salt okunur bir özellik istiyorsunuz:

Amaç, db sonuç kümesi gibi davranan bir sahte sınıf oluşturmaktır.

Yani, örneğin, bir dict ifade kullanarak bir veritabanı sorgusu döner, eğer {'ab':100, 'cd':200}, o zaman olurdu görmek

>>> dummy.ab
100

Sadece bunu başarmak namedtupleiçin bir collectionsmodülün nasıl kullanılacağını göstereceğim :

import collections

data = {'ab':100, 'cd':200}

def maketuple(d):
    '''given a dict, return a namedtuple'''
    Tup = collections.namedtuple('TupName', d.keys()) # iterkeys in Python2
    return Tup(**d)

dummy = maketuple(data)
dummy.ab

İadeler 100


0
class atdict(dict):
  def __init__(self, value, **kwargs):
    super().__init__(**kwargs)
    self.__dict = value

  def __getattr__(self, name):
    for key in self.__dict:
      if type(self.__dict[key]) is list:
        for idx, item in enumerate(self.__dict[key]):
          if type(item) is dict:
            self.__dict[key][idx] = atdict(item)
      if type(self.__dict[key]) is dict:
        self.__dict[key] = atdict(self.__dict[key])
    return self.__dict[name]



d1 = atdict({'a' : {'b': [{'c': 1}, 2]}})

print(d1.a.b[0].c)

Ve çıktı:

>> 1

0

Fikri kjfletch'ten genişletme

# This is my humble contribution, extending the idea to serialize
# data from and to tuples, comparison operations and allowing functions
# as default values.

def Struct(*args, **kwargs):
    FUNCTIONS = (types.BuiltinFunctionType, types.BuiltinMethodType, \
                 types.FunctionType, types.MethodType)
    def init(self, *iargs, **ikwargs):
        """Asume that unamed args are placed in the same order than
        astuple() yields (currently alphabetic order)
        """
        kw = list(self.__slots__)

        # set the unnamed args
        for i in range(len(iargs)):
            k = kw.pop(0)
            setattr(self, k, iargs[i])

        # set the named args
        for k, v in ikwargs.items():
            setattr(self, k, v)
            kw.remove(k)

        # set default values
        for k in kw:
            v = kwargs[k]
            if isinstance(v, FUNCTIONS):
                v = v()
            setattr(self, k, v)

    def astuple(self):
        return tuple([getattr(self, k) for k in self.__slots__])

    def __str__(self):
        data = ['{}={}'.format(k, getattr(self, k)) for k in self.__slots__]
        return '<{}: {}>'.format(self.__class__.__name__, ', '.join(data))

    def __repr__(self):
        return str(self)

    def __eq__(self, other):
        return self.astuple() == other.astuple()

    name = kwargs.pop("__name__", "MyStruct")
    slots = list(args)
    slots.extend(kwargs.keys())
    # set non-specific default values to None
    kwargs.update(dict((k, None) for k in args))

    return type(name, (object,), {
        '__init__': init,
        '__slots__': tuple(slots),
        'astuple': astuple,
        '__str__': __str__,
        '__repr__': __repr__,
        '__eq__': __eq__,
    })


Event = Struct('user', 'cmd', \
               'arg1', 'arg2',  \
               date=time.time, \
               __name__='Event')

aa = Event('pepe', 77)
print(aa)
raw = aa.astuple()

bb = Event(*raw)
print(bb)

if aa == bb:
    print('Are equals')

cc = Event(cmd='foo')
print(cc)

Çıktı:

<Event: user=pepe, cmd=77, arg1=None, arg2=None, date=1550051398.3651814>
<Event: user=pepe, cmd=77, arg1=None, arg2=None, date=1550051398.3651814>
Are equals
<Event: user=None, cmd=foo, arg1=None, arg2=None, date=1550051403.7938335>

0

Birçok cevap verilmesine rağmen, memnun olduğum bir cevap bulamadım. propertyDinamik dava için iş yapan kendi çözümümü buldum . Orijinal soruyu cevaplayacak kaynak:

#!/usr/local/bin/python3

INITS = { 'ab': 100, 'cd': 200 }

class DP(dict):
  def __init__(self):
    super().__init__()
    for k,v in INITS.items():
        self[k] = v 

def _dict_set(dp, key, value):
  dp[key] = value

for item in INITS.keys():
  setattr(
    DP,
    item,
    lambda key: property(
      lambda self: self[key], lambda self, value: _dict_set(self, key, value)
    )(item)
  )

a = DP()
print(a)  # {'ab': 100, 'cd': 200}
a.ab = 'ab100'
a.cd = False
print(a.ab, a.cd) # ab100 False

0

Benim için çalışan bir şey şudur:

class C:
    def __init__(self):
        self._x=None

    def g(self):
        return self._x

    def s(self, x):
        self._x = x

    def d(self):
        del self._x

    def s2(self,x):
        self._x=x+x

    x=property(g,s,d)


c = C()
c.x="a"
print(c.x)

C.x=property(C.g, C.s2)
C.x=C.x.deleter(C.d)
c2 = C()
c2.x="a"
print(c2.x)

Çıktı

a
aa

-1

Son zamanlarda benzer bir sorunla karşılaştım, kullandığım çözüm, kullanmasını istediğim özellikler __getattr__ve __setattr__diğer her şey orijinallere aktarılıyor.

class C(object):
    def __init__(self, properties):
        self.existing = "Still Here"
        self.properties = properties

    def __getattr__(self, name):
        if "properties" in self.__dict__ and name in self.properties:
            return self.properties[name] # Or call a function, etc
        return self.__dict__[name]

    def __setattr__(self, name, value):
        if "properties" in self.__dict__ and name in self.properties:
            self.properties[name] = value
        else:
            self.__dict__[name] = value

if __name__ == "__main__":
    my_properties = {'a':1, 'b':2, 'c':3}
    c = C(my_properties)
    assert c.a == 1
    assert c.existing == "Still Here"
    c.b = 10
    assert c.properties['b'] == 10

Bunu inceledim, ancak teknik olarak alıcı ve ayarlayıcı yardımcılarınızdaki bir listeden geçiyorsunuz. Bu nedenle, her çağrı daha yavaş olur çünkü ilk önce doğrudan erişmek yerine listeden ararsınız. Python sizin için otomatik olarak haritalamadığı sürece; olabilir, ama bunu kesin olarak bilmek için henüz kıyaslamadım, ama denemeden önce benim için bir endişe. İkincisi, bunu yaparak yardımcıları başka bir şekilde tanımlamanız gerekir. Veri türlerini ve / veya değerleri, büyük bir sözlük veya fazladan fazla satır kullanmadan da kilitleyemezsiniz.
Acecool

ie: Ya sistemi kullanan tüm çocuklarımı genişlettiğim ya da her şeye s / getattr magic fonksiyonları eklemem ve sistemi her seferinde çoğaltmam gereken bir temel sınıf oluşturmalıydım. Özellik bildirimi ayrıca bunları tek yönlü olarak ayarlamanız gerektiği anlamına gelir ve verilerin atanmasına ve diğer yardımcılara izin vermek veya önlemek için veri türü ve / veya değer koruması gibi listelediğim gibi ek desteklerden herhangi birini istiyorsanız , sonra bunları kodlamanız gerekir. Verilmiş, sistemi davranışa benzer hale getirebilirsiniz, ancak biraz farklı ve daha hantal beyan ettiğiniz yerde sonuçlanır.
Ocak'ta Acecool

-1

Programlı olarak özellik nesnesi oluşturmak için basit bir örnek.

#!/usr/bin/python3

class Counter:
    def __init__(self):
        cls = self.__class__
        self._count = 0
        cls.count = self.count_ref()

    def count_get(self):
        print(f'count_get: {self._count}')
        return self._count

    def count_set(self, value):
        self._count = value
        print(f'count_set: {self._count}')

    def count_del(self):
        print(f'count_del: {self._count}')

    def count_ref(self):
        cls = self.__class__
        return property(fget=cls.count_get, fset=cls.count_set, fdel=cls.count_del)

counter = Counter()

counter.count
for i in range(5):
    counter.count = i
del counter.count

'''
output
======
count_get: 0
count_set: 0
count_set: 1
count_set: 2
count_set: 3
count_set: 4
count_del: 4
'''

-2

Bir özelliği dinamik olarak eklemenin tek yolu yeni mülkünüzle yeni bir sınıf ve örneği oluşturmaktır.

class Holder: p = property(lambda x: vs[i], self.fn_readonly)
setattr(self, k, Holder().p)

1
bu işe yaramıyor gibi görünüyor. mülkün kendisini değil, mülkün sonucunu atar.
mjallday

Bu yanlış. Sınıfı başlatmak zorunda kalmadan sistemime dinamik özellikler ekliyorum. X = Örnek () olmasını başlatın, ardından özelliği x öğesine ekleyin.
Acecool

Koduma bakarsanız, sınıf SampleBase: pass, sonra sınıf Sample (SampleBase): ... kullandığınızı göreceksiniz, sonra daha sonra adı var olduğundan ve Sample bu uzantıyı genişlettiğinden, özelliklerini SampleBase'e ekliyorum. her şeye erişimi vardır. Erişimci nesnelerine doğrudan erişebilmek için erişimci yardımcısı için __ var, Hiçbiri olabilecek depolanmış (ham) veri için _ kullanıyorum ve alıcıdan geçen gerçek özellik için alt çizgi yok. Dinamik olarak eklenen bir işlevi kullanarak getter işlevini çağırabilir veya özelliği kullanabilirsiniz. İlk inisiyasyon olmadan hepsi.
Acecool

Not: Bundan bahsetmiştim - ama tanımımın tanımı referansın ad alanında mevcut olduğu anlamına gelir - yani: sınıf Örnek (Nesne): geçiş ... Var, ancak başlatılmadı. Başlatma, blah = Örnek (); şimdi nesne 'kopyalandı' ve inşa edildi, sonra filan olarak referans olarak saklandı. --- Bunu yaparsanız, dinamik olarak eklenen işlevler / özellikler yalnızca örnekte olmalıdır - işlevler mevcut olsa bile, bununla ilgili sorunum yoktu, yapmadığını söyleyen bir hata aldım. Engelleme hatası oluşturma işlemini durdurdu veya zaman uyumsuz yürütme.
Ocak'ta Acecool

Birkaç not daha: Dinamik olarak özellikler oluşturmak mümkündür ve yalnızca örnek başına var olacak şekilde çalışır. Ayrıca bunları nesne için var olacak şekilde yapabilirsiniz (çoğu durumda istediğiniz şeydir). Ve eklenen öğelerin 'statik', yani aynı referanslar ve döndürülen değerlerin tüm örneklerde paylaşıldığı durumlar vardır - bir alanda güncelleme yaparsanız, hepsi aynı olur ..
Acecool

-6

Sağlanan cevapların birçoğu mülk başına çok fazla satır gerektirir, yani / ve / veya - birden fazla mülk için gerekli tekrarlama nedeniyle çirkin veya sıkıcı bir uygulama olarak düşündüğüm, vb. artık ya da çok fazla amaca hizmet etmedikçe basitleştirilemez.

Kısacası: Tamamlanmış çalışmalarda, 2 satır kod tekrarlarsam, genellikle tek satır yardımcı işlevine dönüştürürüm ve benzeri ... (start_x, start_y, end_x, end_y) gibi matematik veya tek değişkenleri (x, y, w, h) yani x, y, x + w, y + h (bazen min / maks gerektiren veya w / h negatifse ve uygulama hoşlanmıyorsa, x / y ve abs w / h. vs ..).

Dahili alıcıları / ayarlayıcıları geçersiz kılmak gitmek için iyi bir yoldur, ancak sorun her sınıf için bunu yapmanız ya da sınıfı bu tabana vurgulmanız ... Bu benim için işe yaramıyor miras, çocuk düğümleri vb.İçin çocukları / ebeveynleri seçmekte serbesttir.

Verileri girmek için bir Dict veri türü kullanmadan soruya cevap veren bir çözüm oluşturdum.

Çözümüm, özellikleri eklemek istediğiniz sınıf için bir temel sınıf oluşturmak için sınıfınızın üzerine 2 ekstra satır eklemenizi, ardından 1 satır başına ve verileri kontrol etmek için geri arama ekleme, veri değişiklikleri olduğunda sizi bilgilendirme seçeneğiniz var. , değere ve / veya veri türüne göre ayarlanabilecek verileri ve çok daha fazlasını kısıtlayın.

Ayrıca _object.x, _object.x = değer, _object.GetX (), _object.SetX (değer) kullanma seçeneğiniz de vardır ve bunlar aynı şekilde işlenir.

Ayrıca, değerler sınıf örneğine atanan yalnızca statik olmayan verilerdir, ancak gerçek özellik sınıfa atanır, yani tekrarlamak istemediğiniz, tekrarlanması gerekmez ... varsayılan varsayılan değeri geçersiz kılma seçeneği olmasına rağmen, alıcı her seferinde ihtiyaç duymayacak şekilde varsayılan bir değer atayabilir ve başka bir seçenek de vardır, böylece alıcı varsayılan getirileri geçersiz kılarak ham depolanan değeri döndürür (not: bu yöntem ham değerin yalnızca bir değer atandığında atanmış olduğu anlamına gelir; aksi takdirde Yok - değer Sıfırlandığında, Yok, vb. atar.)

Çok sayıda yardımcı işlev de vardır - eklenen ilk özellik, örnek değerlerine başvurmak için sınıfa 2 veya daha fazla yardımcı ekler ... Tekrarlanan ResetAccessors (_key, ..) varargs (tümü, ilk adlandırılmış argümanlar kullanılarak tekrarlanabilir) ) ve SetAccessors (_key, _value) ile ana sınıfa verimlilikte yardımcı olmak için daha fazla ekleme seçeneği - planlananlar: erişimcileri bir arada gruplamanın bir yolu, bu nedenle her seferinde birkaç kez sıfırlama eğilimindeyseniz , her seferinde adlandırılmış tuşları tekrarlamak yerine bir gruba atayabilir ve grubu sıfırlayabilirsiniz.

Örnek / ham saklanan değer sınıfta saklanır . , sınıf. özelliğin statik değişkenlerini / değerlerini / işlevlerini tutan Accessor Sınıfına başvurur. _sınıf. ayar / alma vb. sırasında örnek sınıfı aracılığıyla erişildiğinde çağrılan özelliğin kendisidir.

Accessor _class .__ sınıfa işaret eder, ancak dahili olduğu için sınıfta atanması gerekir, bu yüzden atamak için __Name = AccessorFunc (...) kullanmayı seçtim, birçok isteğe bağlı özellik başına tek bir satır kullanılacak argümanlar (tanımlanması ve bakımı daha kolay ve verimli oldukları için anahtarlı varargs kullanarak) ...

Ayrıca, belirtildiği gibi, bazıları erişimci işlev bilgilerini kullanan çok sayıda işlev oluşturuyorum, bu yüzden çağrılmaya gerek yok (şu anda biraz rahatsız edici olduğu için - şu anda _class kullanmanız gerekiyor. .FunctionName (_class_instance) , args) - Bu bit maratonunu çalıştıran işlevleri ekleyerek veya nesneye erişimcileri ekleyerek ve kendini kullanarak (bunu belirtmek için adlandırılır) değeri değerlendirmek için örnek başvurusunu almak için yığın / iz kullanarak dolaştım örnek ve kendinize, AccessorFunc sınıf başvurusuna ve işlev tanımları içindeki diğer bilgilere erişimi korumak içindir).

Tamamen bitmedi, ama harika bir ayak tutun. Not: Özellikleri oluşturmak için __Name = AccessorFunc (...) kullanmıyorsanız, init işlevi içinde tanımlasam da __ tuşuna erişemezsiniz. Bunu yaparsanız, hiçbir sorun yoktur.

Ayrıca: Ad ve Anahtarın farklı olduğunu unutmayın ... Ad, İşlev Adı Oluşturma'da kullanılan 'resmi' ve anahtar veri depolama ve erişim içindir. yani _class.x küçük harf x anahtar ise, isim X büyük harf olur, böylece GetX () biraz tuhaf görünen Getx () yerine işlevdir. bu self.x'in çalışmasına ve uygun görünmesine izin verir, aynı zamanda GetX () 'e de izin verir ve uygun görünmesine izin verir.

Anahtar / ad aynı ve göstermek için farklı ile ayarlanmış bir örnek sınıf var. verilerin çıktısını almak için çok sayıda yardımcı işlev oluşturuldu (Not: Bunların hepsi tamamlanmadı), böylece neler olup bittiğini görebilirsiniz.

: X, name: X tuşlarını kullanarak geçerli işlev listesi şu şekilde çıktı verir:

Bu hiçbir şekilde kapsamlı bir liste değildir - gönderme sırasında bunu yapmayan birkaç kişi vardır ...

_instance.SetAccessors( _key, _value [ , _key, _value ] .. )                   Instance Class Helper Function: Allows assigning many keys / values on a single line - useful for initial setup, or to minimize lines.    In short: Calls this.Set<Name>( _value ) for each _key / _value pairing.
_instance.ResetAccessors( _key [ , _key ] .. )                                 Instance Class Helper Function: Allows resetting many key stored values to None on a single line.                                           In short: Calls this.Reset<Name>() for each name provided.


Note: Functions below may list self.Get / Set / Name( _args ) - self is meant as the class instance reference in the cases below - coded as this in AccessorFuncBase Class.

this.GetX( _default_override = None, _ignore_defaults = False )                 GET:            Returns    IF ISSET: STORED_VALUE .. IF IGNORE_DEFAULTS: None  .. IF PROVIDED: DEFAULT_OVERRIDE ELSE: DEFAULT_VALUE       100
this.GetXRaw( )                                                                 RAW:            Returns    STORED_VALUE                                                                                                     100
this.IsXSet( )                                                                  ISSET:          Returns    ( STORED_VALUE != None )                                                                                         True

this.GetXToString( )                                                            GETSTR:         Returns    str( GET )                                                                                                       100
this.GetXLen( _default_override = None, _ignore_defaults = False )              LEN:            Returns    len( GET )                                                                                                       3
this.GetXLenToString( _default_override = None, _ignore_defaults = False )      LENSTR:         Returns    str( len( GET ) )                                                                                                3
this.GetXDefaultValue( )                                                        DEFAULT:        Returns    DEFAULT_VALUE                                                                                                    1111

this.GetXAccessor( )                                                            ACCESSOR:       Returns    ACCESSOR_REF ( self.__<key> )                                                                                    [ AccessorFuncBase ] Key: x : Class ID: 2231452344344 : self ID: 2231448283848        Default: 1111       Allowed Types: {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"}     Allowed Values: None
this.GetXAllowedTypes( )                                                        ALLOWED_TYPES:  Returns    Allowed Data-Types                                                                                               {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"}
this.GetXAllowedValues( )                                                       ALLOWED_VALUES: Returns    Allowed Values                                                                                                   None

this.GetXHelpers( )                                                             HELPERS:        Returns    Helper Functions String List - ie what you're reading now...                                                     THESE ROWS OF TEXT
this.GetXKeyOutput( )                                                           Returns information about this Name / Key                                                                                                   ROWS OF TEXT
this.GetXGetterOutput( )                                                        Returns information about this Name / Key                                                                                                   ROWS OF TEXT

this.SetX( _value )                                                             SET:            STORED_VALUE Setter - ie Redirect to __<Key>.Set                                                                            N / A
this.ResetX( )                                                                  RESET:          Resets STORED_VALUE to None                                                                                                 N / A

this.HasXGetterPrefix( )                                                        Returns Whether or Not this key has a Getter Prefix...                                                                                      True
this.GetXGetterPrefix( )                                                        Returns Getter Prefix...                                                                                                                    Get

this.GetXName( )                                                                Returns Accessor Name - Typically Formal / Title-Case                                                                                       X
this.GetXKey( )                                                                 Returns Accessor Property Key - Typically Lower-Case                                                                                        x
this.GetXAccessorKey( )                                                         Returns Accessor Key - This is to access internal functions, and static data...                                                             __x
this.GetXDataKey( )                                                             Returns Accessor Data-Storage Key - This is the location where the class instance value is stored..                                         _x

Çıkarılan verilerin bazıları:

Bu, demo sınıfı kullanılarak oluşturulmuş yepyeni bir sınıf için, adından başka herhangi bir veri atanmamış (bu nedenle çıktı olabilir) ki bu da kullandığım değişken adı ...

_foo         --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016

    Key       Getter Value        | Raw Key   Raw / Stored Value       | Get Default Value             Default Value            | Get Allowed Types             Allowed Types                                                              | Get Allowed Values            Allowed Values                                                                                                                                                                                                                   |

    Name:     _foo                | _Name:    _foo                     | __Name.DefaultValue( ):       AccessorFuncDemoClass    | __Name.GetAllowedTypes( )     <class 'str'>                                                              | __Name.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    x:        1111                | _x:       None                     | __x.DefaultValue( ):          1111                     | __x.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __x.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    y:        2222                | _y:       None                     | __y.DefaultValue( ):          2222                     | __y.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __y.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    z:        3333                | _z:       None                     | __z.DefaultValue( ):          3333                     | __z.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __z.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Blah:     <class 'int'>       | _Blah:    None                     | __Blah.DefaultValue( ):       <class 'int'>            | __Blah.GetAllowedTypes( )     <class 'str'>                                                              | __Blah.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Width:    1                   | _Width:   None                     | __Width.DefaultValue( ):      1                        | __Width.GetAllowedTypes( )    (<class 'int'>, <class 'bool'>)                                            | __Width.GetAllowedValues( )   Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Height:   0                   | _Height:  None                     | __Height.DefaultValue( ):     0                        | __Height.GetAllowedTypes( )   <class 'int'>                                                              | __Height.GetAllowedValues( )  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |
    Depth:    2                   | _Depth:   None                     | __Depth.DefaultValue( ):      2                        | __Depth.GetAllowedTypes( )    Saved Value Restricted to Authorized Values ONLY                           | __Depth.GetAllowedValues( )   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |


this.IsNameSet( ):    True      this.GetName( ):     _foo                     this.GetNameRaw( ):    _foo                     this.GetNameDefaultValue( ):    AccessorFuncDemoClass    this.GetNameLen( ):    4    this.HasNameGetterPrefix( ):    <class 'str'>                                this.GetNameGetterPrefix( ):    None
this.IsXSet( ):       False     this.GetX( ):        1111                     this.GetXRaw( ):       None                     this.GetXDefaultValue( ):       1111                     this.GetXLen( ):       4    this.HasXGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetXGetterPrefix( ):       None
this.IsYSet( ):       False     this.GetY( ):        2222                     this.GetYRaw( ):       None                     this.GetYDefaultValue( ):       2222                     this.GetYLen( ):       4    this.HasYGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetYGetterPrefix( ):       None
this.IsZSet( ):       False     this.GetZ( ):        3333                     this.GetZRaw( ):       None                     this.GetZDefaultValue( ):       3333                     this.GetZLen( ):       4    this.HasZGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetZGetterPrefix( ):       None
this.IsBlahSet( ):    False     this.GetBlah( ):     <class 'int'>            this.GetBlahRaw( ):    None                     this.GetBlahDefaultValue( ):    <class 'int'>            this.GetBlahLen( ):    13   this.HasBlahGetterPrefix( ):    <class 'str'>                                this.GetBlahGetterPrefix( ):    None
this.IsWidthSet( ):   False     this.GetWidth( ):    1                        this.GetWidthRaw( ):   None                     this.GetWidthDefaultValue( ):   1                        this.GetWidthLen( ):   1    this.HasWidthGetterPrefix( ):   (<class 'int'>, <class 'bool'>)              this.GetWidthGetterPrefix( ):   None
this.IsDepthSet( ):   False     this.GetDepth( ):    2                        this.GetDepthRaw( ):   None                     this.GetDepthDefaultValue( ):   2                        this.GetDepthLen( ):   1    this.HasDepthGetterPrefix( ):   None                                         this.GetDepthGetterPrefix( ):   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ):  False     this.GetHeight( ):   0                        this.GetHeightRaw( ):  None                     this.GetHeightDefaultValue( ):  0                        this.GetHeightLen( ):  1    this.HasHeightGetterPrefix( ):  <class 'int'>                                this.GetHeightGetterPrefix( ):  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

Ve bu, _foo özelliklerinin (ad hariç) tüm değerlerini aynı sırayla atadıktan sonra yapılır: 'string', 1.0, True, 9, 10, False

this.IsNameSet( ):    True      this.GetName( ):     _foo                     this.GetNameRaw( ):    _foo                     this.GetNameDefaultValue( ):    AccessorFuncDemoClass    this.GetNameLen( ):    4    this.HasNameGetterPrefix( ):    <class 'str'>                                this.GetNameGetterPrefix( ):    None
this.IsXSet( ):       True      this.GetX( ):        10                       this.GetXRaw( ):       10                       this.GetXDefaultValue( ):       1111                     this.GetXLen( ):       2    this.HasXGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetXGetterPrefix( ):       None
this.IsYSet( ):       True      this.GetY( ):        10                       this.GetYRaw( ):       10                       this.GetYDefaultValue( ):       2222                     this.GetYLen( ):       2    this.HasYGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetYGetterPrefix( ):       None
this.IsZSet( ):       True      this.GetZ( ):        10                       this.GetZRaw( ):       10                       this.GetZDefaultValue( ):       3333                     this.GetZLen( ):       2    this.HasZGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetZGetterPrefix( ):       None
this.IsBlahSet( ):    True      this.GetBlah( ):     string Blah              this.GetBlahRaw( ):    string Blah              this.GetBlahDefaultValue( ):    <class 'int'>            this.GetBlahLen( ):    11   this.HasBlahGetterPrefix( ):    <class 'str'>                                this.GetBlahGetterPrefix( ):    None
this.IsWidthSet( ):   True      this.GetWidth( ):    False                    this.GetWidthRaw( ):   False                    this.GetWidthDefaultValue( ):   1                        this.GetWidthLen( ):   5    this.HasWidthGetterPrefix( ):   (<class 'int'>, <class 'bool'>)              this.GetWidthGetterPrefix( ):   None
this.IsDepthSet( ):   True      this.GetDepth( ):    9                        this.GetDepthRaw( ):   9                        this.GetDepthDefaultValue( ):   2                        this.GetDepthLen( ):   1    this.HasDepthGetterPrefix( ):   None                                         this.GetDepthGetterPrefix( ):   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ):  True      this.GetHeight( ):   9                        this.GetHeightRaw( ):  9                        this.GetHeightDefaultValue( ):  0                        this.GetHeightLen( ):  1    this.HasHeightGetterPrefix( ):  <class 'int'>                                this.GetHeightGetterPrefix( ):  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

_foo         --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016

    Key       Getter Value        | Raw Key   Raw / Stored Value       | Get Default Value             Default Value            | Get Allowed Types             Allowed Types                                                              | Get Allowed Values            Allowed Values                                                                                                                                                                                                                   |

    Name:     _foo                | _Name:    _foo                     | __Name.DefaultValue( ):       AccessorFuncDemoClass    | __Name.GetAllowedTypes( )     <class 'str'>                                                              | __Name.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    x:        10                  | _x:       10                       | __x.DefaultValue( ):          1111                     | __x.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __x.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    y:        10                  | _y:       10                       | __y.DefaultValue( ):          2222                     | __y.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __y.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    z:        10                  | _z:       10                       | __z.DefaultValue( ):          3333                     | __z.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __z.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Blah:     string Blah         | _Blah:    string Blah              | __Blah.DefaultValue( ):       <class 'int'>            | __Blah.GetAllowedTypes( )     <class 'str'>                                                              | __Blah.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Width:    False               | _Width:   False                    | __Width.DefaultValue( ):      1                        | __Width.GetAllowedTypes( )    (<class 'int'>, <class 'bool'>)                                            | __Width.GetAllowedValues( )   Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Height:   9                   | _Height:  9                        | __Height.DefaultValue( ):     0                        | __Height.GetAllowedTypes( )   <class 'int'>                                                              | __Height.GetAllowedValues( )  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |
    Depth:    9                   | _Depth:   9                        | __Depth.DefaultValue( ):      2                        | __Depth.GetAllowedTypes( )    Saved Value Restricted to Authorized Values ONLY                           | __Depth.GetAllowedValues( )   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |

Kısıtlı veri türleri veya değer kısıtlamaları nedeniyle bazı verilerin atanmadığını unutmayın - bu tasarım gereğidir. Ayarlayıcı, hatalı veri türlerinin veya değerlerin varsayılan değer olarak atanmasını bile engeller (varsayılan değer koruma davranışını geçersiz kılmadıkça)

Örnekler ve açıklamalar sonra yer yoktu çünkü kod burada yayınlanmadı ... Ayrıca değişecektir çünkü.

Lütfen Dikkat: bu gönderi sırasında dosya dağınık - bu değişecek. Ancak, Sublime Text'de çalıştırır ve derlerseniz veya Python'dan çalıştırırsanız, bir ton bilgi derleyip tükürür - AccessorDB kısmı yapılmaz (Print Getters ve GetKeyOutput yardımcısını güncellemek için kullanılır) bir Örnek işlevine değiştirilmenin yanı sıra, muhtemelen tek bir işleve yerleştirilir ve yeniden adlandırılır - işlevlerini arayın ..)

Sonraki: Çalıştırılması için her şey gerekli değildir - alttaki yorumlanmış birçok şey hata ayıklama için daha fazla bilgi içindir - indirdiğinizde orada olmayabilir. Eğer öyleyse, daha fazla bilgi almak için rahatsız edip yeniden derleyebilmelisiniz.

MyClassBase: pass, MyClass (MyClassBase) ihtiyacı için bir geçici çözüm arıyorum: ... - bir çözüm biliyorsanız - post it.

Sınıfta gerekli olan tek şey __ satırlarıdır - str init olduğu gibi hata ayıklamak içindir - Demo Sınıfından kaldırılabilirler, ancak aşağıdaki satırlardan bazılarını yorumlamanız veya kaldırmanız gerekecektir (_foo / 2/3 ) ..

Üstteki String, Dict ve Util sınıfları Python kütüphanemin bir parçasıdır - tam değildir. Kütüphaneden ihtiyacım olan birkaç şeyi kopyaladım ve birkaç tane yeni kitap oluşturdum. Tam kod, tüm kitaplığa bağlanır ve güncellenmiş çağrılar sağlayarak ve kodu kaldırır (aslında, kalan tek kod Demo Sınıfı ve baskı ifadeleri olacaktır - AccessorFunc sistemi kitaplığa taşınacaktır). ..

Dosyanın bir parçası:

##
## MyClass Test AccessorFunc Implementation for Dynamic 1-line Parameters
##
class AccessorFuncDemoClassBase( ):
    pass
class AccessorFuncDemoClass( AccessorFuncDemoClassBase ):
    __Name      = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Name',      default = 'AccessorFuncDemoClass',  allowed_types = ( TYPE_STRING ),                    allowed_values = VALUE_ANY,                 documentation = 'Name Docs',        getter_prefix = 'Get',  key = 'Name',       allow_erroneous_default = False,    options = { } )
    __x         = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'X',         default = 1111,                     allowed_types = ( TYPE_INTEGER, TYPE_FLOAT ),       allowed_values = VALUE_ANY,                 documentation = 'X Docs',           getter_prefix = 'Get',  key = 'x',          allow_erroneous_default = False,    options = { } )
    __Height    = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Height',    default = 0,                        allowed_types = TYPE_INTEGER,                       allowed_values = VALUE_SINGLE_DIGITS,       documentation = 'Height Docs',      getter_prefix = 'Get',  key = 'Height',     allow_erroneous_default = False,    options = { } )

Bu güzellik, AccessorFuncs / geri çağrılar / veri türü / değer zorlaması, vb. İle dinamik olarak eklenen özelliklere sahip yeni sınıflar oluşturmayı inanılmaz derecede kolaylaştırır.

Şimdilik, bağlantı şudur (Bu bağlantı, belgedeki değişiklikleri yansıtmalıdır.): Https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0

Ayrıca: Yüce Metin kullanmıyorsanız, Notepad ++, Atom, Visual Code ve diğerleri üzerinde tavsiye ederim, çünkü uygun iş parçacığı uygulamaları çok, çok daha hızlı hale getiriyor ... Ben de IDE benzeri bir kod üzerinde çalışıyorum bunun için harita sistemi - bir göz atın: https://bitbucket.org/Acecool/acecoolcodemappingsystem/src/master/ (Önce Paket Yöneticisine Repo Ekle, sonra Eklentiyi Yükle - 1.0.0 sürümü hazır olduğunda, ekleyeceğim ana eklenti listesine ...)

Umarım bu çözüm yardımcı olur ... ve her zamanki gibi:

Çalıştığı için doğru yapmaz - Josh 'Acecool' Moser


Kod dosyasını açmanıza gerek kalmadan sınıfın neye benzediğini hızlı bir şekilde eklemek istedim, ancak yorumlar bunu desteklemiyor gibi görünüyor ..
Acecool

Görünüşe göre bu kafa karıştırıcı bir sürü nefret alıyor. Tam olarak OP'nin istediği şeyi yapar - bir nesneye dinamik olarak özellikler eklemek. Ayrıca, dahil edilmesi gerekmeyen yardımcı işlevler ekler - belki de bu yüzden nefret alıyor - ve geliştiricinin alıcıdan işlenen özelliğe (.x) erişmenin kolay bir yoluna sahip olmasını sağlar. .x varsayılan değeri veya başka bir şey döndürdüğünde Yok olabilen (._x) ham değeri ve yardımcıları kullanmak, bir şeyleri değiştirmek vb. için erişimciye erişmenin bir yolu olabilir. (
..x
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.