web-gelistirme-sc.com

Python'da nesne özniteliklerini yinele

Birkaç niteliği ve yöntemi olan bir python nesnem var. Nesne özellikleri üzerinde yineleme yapmak istiyorum. 

class my_python_obj(object):
    attr1='a'
    attr2='b'
    attr3='c'

    def method1(self, etc, etc):
        #Statements

Tüm nesnelerin niteliklerini ve bunların geçerli değerlerini içeren bir sözlük oluşturmak istiyorum, ancak bunu dinamik bir şekilde yapmak istiyorum (eğer daha sonra başka bir özellik eklersem işlevimi güncellemeyi hatırlamak zorunda kalmam).

Php değişkenlerinde anahtar olarak kullanılabilir, ancak python içindeki nesneler tanımlanamaz ve bunun için nokta gösterimini kullanırsam, varımın ismiyle yeni bir öznitelik yaratır, bu benim niyetim değil.

Sadece işleri netleştirmek için:

def to_dict(self):
    '''this is what I already have'''
    d={}
    d["attr1"]= self.attr1
    d["attr2"]= self.attr2
    d["attr3"]= self.attr3
    return d

·

def to_dict(self):
    '''this is what I want to do'''
    d={}
    for v in my_python_obj.attributes:
        d[v] = self.v
    return d

Güncelleme: Özniteliklerle sadece bu nesnenin değişkenlerini kastediyorum, yöntemleri değil.

109
Pablo Mescher

Örneğin bir sınıfınız olduğunu varsayalım

>>> class Cls(object):
...     foo = 1
...     bar = 'hello'
...     def func(self):
...         return 'call me'
...
>>> obj = Cls()

nesne üzerindeki dir işlevini çağırmak, o nesnenin python özel özellikleri de dahil olmak üzere tüm özelliklerini geri verir. Bazı nesne nitelikleri, yöntemler gibi çağrılabilir olmasına rağmen.

>>> dir(obj)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'foo', 'func']

Bir liste anlama özelliğini kullanarak özel yöntemleri her zaman filtreleyebilirsiniz.

>>> [a for a in dir(obj) if not a.startswith('__')]
['bar', 'foo', 'func']

veya harita/filtreleri tercih ediyorsanız.

>>> filter(lambda a: not a.startswith('__'), dir(obj))
['bar', 'foo', 'func']

Yöntemleri filtrelemek istiyorsanız, yerleşik callable öğesini kontrol olarak kullanabilirsiniz.

>>> [a for a in dir(obj) if not a.startswith('__') and not callable(getattr(obj,a))]
['bar', 'foo']

Ayrıca, sınıfınız ve ebeveyni kullanarak arasındaki farkı da inceleyebilirsiniz.

>>> set(dir(Cls)) - set(dir(object))
set(['__module__', 'bar', 'func', '__dict__', 'foo', '__weakref__'])
172
Meitham

genel olarak class dizininize bir __iter__ yöntemi koyun ve object özniteliklerini yineleyin veya bu mixin sınıfını sınıfınıza yerleştirin.

class IterMixin(object):
    def __iter__(self):
        for attr, value in self.__dict__.iteritems():
            yield attr, value

Senin sınıfın:

>>> class YourClass(IterMixin): pass
...
>>> yc = YourClass()
>>> yc.one = range(15)
>>> yc.two = 'test'
>>> dict(yc)
{'one': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], 'two': 'test'}
42
SmartElectron

Python içindeki nesneler özniteliklerini (işlevler dahil) __dict__ adlı bir dikte saklar. Nitelikleri doğrudan erişmek için bunu (ancak genellikle kullanmamalısınız) kullanabilirsiniz. Yalnızca bir liste istiyorsanız, dir(obj) öğesini çağırabilirsiniz; bu, daha sonra getattr öğesine iletebileceğiniz tüm öznitelik adlarıyla yinelenebilir olan döndürür.

Bununla birlikte, değişkenlerin isimleri ile herhangi bir şey yapmaya ihtiyaç duymak genellikle kötü bir tasarımdır. Neden onları koleksiyonda tutmuyorsun?

class Foo(object):
    def __init__(self, **values):
        self.special_values = values

Daha sonra for key in obj.special_values: ile tuşları tekrar edebilirsiniz.

3
Daenyth

Zaten bazı cevaplarda/yorumlarda belirtildiği gibi, Python nesneleri zaten kendi niteliklerinin sözlüğünü saklar (yöntemler dahil değildir). Bu, __dict__ olarak erişilebilir, ancak daha iyi yöntem vars kullanmaktır (çıktı aynıdır). Bu sözlüğü değiştirmenin örnek üzerindeki öznitelikleri değiştireceğini unutmayın! Bu yararlı olabilir, ancak bu sözlüğü nasıl kullandığınıza dikkat etmeniz gerektiği anlamına da gelir. İşte hızlı bir örnek:

class A():
    def __init__(self, x=3, y=2, z=5):
        self.x = x
        self._y = y
        self.__z__ = z

    def f(self):
        pass

a = A()
print(vars(a))
# {'x': 3, '_y': 2, '__z__': 5}
# all of the attributes of `a` but no methods!

# note how the dictionary is always up-to-date
a.x = 10
print(vars(a))
# {'x': 10, '_y': 2, '__z__': 5}

# modifying the dictionary modifies the instance attribute
vars(a)["_y"] = 20
print(vars(a))
# {'x': 10, '_y': 20, '__z__': 5}

dir(a) işlevini kullanmak tamamen kötü değilse bile bu soruna yaklaşır. Sınıfın ve yöntemleri özniteliklerini (__init__ gibi özel yöntemler de dahil olmak üzere) tüm özniteliklerini yinelemeniz gerektiğinde iyidir. Bununla birlikte, bu istediğin gibi görünmüyor ve hatta kabul edilen cevap yöntemleri kaldırmak ve sadece öznitelikleri bırakmak için bazı kırılgan filtreler uygulayarak kötü sonuç veriyor; Bunun, yukarıda tanımlanan A sınıfı için nasıl başarısız olacağını görebilirsiniz.

(__dict__ kullanımı birkaç yanıtta yapıldı, ancak hepsi doğrudan kullanmak yerine gereksiz yöntemler tanımladılar. Yalnızca yorumvars kullanmanızı önerir.

2
Nathan
class someclass:
        x=1
        y=2
        z=3
        def __init__(self):
           self.current_idx = 0
           self.items = ["x","y","z"]
        def next(self):
            if self.current_idx < len(self.items):
                self.current_idx += 1
                k = self.items[self.current_idx-1]
                return (k,getattr(self,k))
            else:
                raise StopIteration
        def __iter__(self):
           return self

o zaman sadece yinelenebilir olarak adlandır

s=someclass()
for k,v in s:
    print k,"=",v
2
Joran Beasley

Python 3.6 için

class SomeClass:

    def attr_list(self, should_print=False):

        items = self.__dict__.items()
        if should_print:
            [print(f"attribute: {k}    value: {v}") for k, v in items]

        return items
1
Rubber Duck

Buna doğru cevap, yapmamalısın. Bu tür bir şey istiyorsanız ya sadece bir dict kullanın ya da açıkça bazı kaplara nitelikler eklemeniz gerekir. Dekoratörler hakkında bilgi edinerek bunu otomatikleştirebilirsiniz.

Özellikle, bu arada, örneğinizdeki method1 bir nitelik kadar iyidir.

1
Julian

Python 3.6 için

class SomeClass:

    def attr_list1(self, should_print=False):

        for k in self.__dict__.keys():
            v = self.__dict__.__getitem__(k)
            if should_print:
                print(f"attr: {k}    value: {v}")

    def attr_list(self, should_print=False):

        b = [(k, v) for k, v in self.__dict__.items()]
        if should_print:
            [print(f"attr: {a[0]}    value: {a[1]}") for a in b]
        return b
0
Rubber Duck