Python'da örnek değişkenleri nasıl alınır?


120

Python'da tüm bir sınıfın örnek değişkenlerinin bir dizisini elde etmek için yerleşik bir yöntem var mı? Örneğin, bu koda sahipsem:

class hi:
  def __init__(self):
    self.ii = "foo"
    self.kk = "bar"

Bunu yapmanın bir yolu var mı:

>>> mystery_method(hi)
["ii", "kk"]

Düzenleme: Başlangıçta sınıf değişkenlerini hatalı olarak istemiştim.


Örneğiniz "örnek değişkenlerini" göstermektedir. Sınıf değişkenleri başka bir şeydir.
S.Lott

Yanıtlar:


143

Her nesnenin içinde __dict__tüm değişkenleri ve değerlerini içeren bir değişken vardır .

Bunu dene

>>> hi_obj = hi()
>>> hi_obj.__dict__.keys()

7
FWIW, inspect modülü size tüm örneklerin sahip olmadığı dikteye güvenmekten daha güvenilir bir yöntem sunar .
Thomas Wouters

1
Ne tür bir örnek dikte içermez ? Hiç karşılaşmadım.
Carl Meyer

3
İnt gibi belirli yerleşik türler. "X = 5" ve ardından "x .__ dict__" demeyi deneyin ve bir AttributeError
Eli Courtwright

6
Ayrıca, yuvaları kullanan her şey .
Thomas Wouters

2
Bir int'in sınıf örnek değişkenlerini neden denemek istersiniz? Bu bir sınıf bile değil (bu konuda yanılsam da).
Martin Sherburn

103

Vars () kullanın

class Foo(object):
    def __init__(self):
        self.a = 1
        self.b = 2

vars(Foo()) #==> {'a': 1, 'b': 2}
vars(Foo()).keys() #==> ['a', 'b']

6
+1 Şahsen bu sözdiziminin dikt kullanmaktan daha temiz olduğunu düşünüyorum , çünkü çift alt çizgilere sahip özniteliklerin Python sözdiziminde "özel" olması gerekiyor.
Martin W

3
@Martin: __methodözel, __method__özel bir yöntem, zorunlu olarak özel değildir; Özel yöntemlerin, yöntemlerden ziyade bir nesnenin yeteneklerini tanımladığını söylemek isterim.
u0b34a0f6ae

2
__method__oldukça çirkin ve bence bu isim, insanları kesinlikle gerekmedikçe kullanmaktan caydırmak için seçildi. Bu durumda, alternatif vars () 'a sahibiz.
Martin Sherburn

benim durumumda vars (ObjName) 'i çağırmayı denedim ve anahtarları verilen sınıfın / nesnenin metotları olan ancak init elemanlarının işareti olmayan bir sözlüğe sahip bir dict_proxy döndürür . Herhangi bir tahmin neden?
user228137

Çift Alt Çizgi Değişkenleri __str__, __method__normalde dilin kendisi içindir. Ne zaman ne olur str(something)?
Zizouz212

15

Normalde yalnızca bir sınıf verilen örnek niteliklerini, en azından sınıfı başlatmadan alamazsınız. Bununla birlikte, bir örnek verilen örnek niteliklerini veya bir sınıfa verilen sınıf niteliklerini alabilirsiniz. 'İnceleme' modülüne bakın. Örnek özniteliklerinin bir listesini alamazsınız çünkü örnekler gerçekten öznitelik olarak herhangi bir şeye sahip olabilir ve - sizin örneğinizde olduğu gibi - onları yaratmanın normal yolu, onlara __init__ yönteminde atamaktır.

Sınıfınızın örneklerin sahip olmasına izin verdiği sabit bir öznitelik listesi olan yuvalar kullanması bir istisnadır. Yuvalar http://www.python.org/2.2.3/descrintro.html'de açıklanmıştır , ancak yuvalarla ilgili çeşitli tuzaklar vardır; bellek düzenini etkilerler, bu nedenle çoklu kalıtım sorunlu olabilir ve kalıtım genel olarak yuvaları da hesaba katmalıdır.


Olumsuz oylama, "örnek özniteliklerinin listesini alamazsınız" tamamen yanlıştır: hem vars () hem de dict size tam olarak bunu verir.
Carl Meyer

2
"Olası tüm örnek özniteliklerinin bir listesini alamazsınız" demek istediğini varsayıyorum. Örneğin, ilk istendiğinde bir örnek değişkeni eklemek için genellikle tembel nesil ve @ özellik dekoratörünü kullanıyorum. Dict kullanmak size bu değişkeni var olduktan sonra anlatırdı ama önceden değil.
Eli Courtwright

5
Olumsuz oy vermedim ve lütfen gerçekte ne dediğime dikkat edin: sadece bir sınıf verilen örnek özniteliklerinin bir listesini alamazsınız , bu soruya eşlik eden kodun yapmaya çalıştığı şeydir.
Thomas Wouters

2
@Carl: Lütfen yanlış yorumlar yazmadan ve bilgisizliğinizden dolayı olumsuz oy kullanmadan önce kendinizi eğitin.
nikow

14

Hem Vars () hem de dict yöntemleri, OP'nin yayınladığı örnek için çalışacaktır, ancak bunlar "gevşek" tanımlanmış nesneler için çalışmayacaktır:

class foo:
  a = 'foo'
  b = 'bar'

Çağrılamayan tüm öznitelikleri yazdırmak için aşağıdaki işlevi kullanabilirsiniz:

def printVars(object):
    for i in [v for v in dir(object) if not callable(getattr(object,v))]:
        print '\n%s:' % i
        exec('print object.%s\n\n') % i

5
exec('print object.%s\n\n') % işu şekilde yazılmalıdırprint getattr(object, i)
user102008

11

Ayrıca, bir nesnenin belirli bir değişkeni olup olmadığını test edebilirsiniz:

>>> hi_obj = hi()
>>> hasattr(hi_obj, "some attribute")

6

Örneğiniz gerçekten sınıf değişkenlerini değil, "örnek değişkenlerini" gösteriyor.

hi_obj.__class__.__dict__.items()Üye işlevler ve kapsayıcı modül gibi diğer sınıf üyeleriyle birlikte sınıf değişkenlerini arayın .

class Hi( object ):
    class_var = ( 23, 'skidoo' ) # class variable
    def __init__( self ):
        self.ii = "foo" # instance variable
        self.jj = "bar"

Sınıf değişkenleri, sınıfın tüm örnekleri tarafından paylaşılır.


6

Önermek

>>> print vars.__doc__
vars([object]) -> dictionary

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.

Başka bir deyişle, esasen __dict__


5

OP sorusuna doğrudan bir cevap olmasa da, bir fonksiyonda hangi değişkenlerin kapsam içinde olduğunu bulmanın oldukça tatlı bir yolu vardır. bu koda bir göz atın:

>>> def f(x, y):
    z = x**2 + y**2
    sqrt_z = z**.5
    return sqrt_z

>>> f.func_code.co_varnames
('x', 'y', 'z', 'sqrt_z')
>>> 

Func_code özniteliğinde her türden ilginç şey vardır. Bazı harika şeyler yapmanıza izin verir. İşte bunu nasıl kullandığımın bir örneği:

def exec_command(self, cmd, msg, sig):

    def message(msg):
        a = self.link.process(self.link.recieved_message(msg))
        self.exec_command(*a)

    def error(msg):
        self.printer.printInfo(msg)

    def set_usrlist(msg):
        self.client.connected_users = msg

    def chatmessage(msg):
        self.printer.printInfo(msg)

    if not locals().has_key(cmd): return
    cmd = locals()[cmd]

    try:
        if 'sig' in cmd.func_code.co_varnames and \
                       'msg' in cmd.func_code.co_varnames: 
            cmd(msg, sig)
        elif 'msg' in cmd.func_code.co_varnames: 
            cmd(msg)
        else:
            cmd()
    except Exception, e:
        print '\n-----------ERROR-----------'
        print 'error: ', e
        print 'Error proccessing: ', cmd.__name__
        print 'Message: ', msg
        print 'Sig: ', sig
        print '-----------ERROR-----------\n'

2

Aşağıdakileri elde etmek için dmark'ın cevabı üzerine inşa edilmiştir; bu, sprintf eşdeğeri istiyorsanız yararlıdır ve umarım birine yardımcı olur ...

def sprint(object):
    result = ''
    for i in [v for v in dir(object) if not callable(getattr(object, v)) and v[0] != '_']:
        result += '\n%s:' % i + str(getattr(object, i, ''))
    return result

0

Bazen listeyi genel / özel değişkenlere göre filtrelemek istersiniz. Örneğin

def pub_vars(self):
    """Gives the variable names of our instance we want to expose
    """
    return [k for k in vars(self) if not k.startswith('_')]
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.