Bagaimana cara mendapatkan variabel instan dengan Python?

120

Apakah ada metode built-in dengan Python untuk mendapatkan array dari semua variabel instance kelas? Misalnya, jika saya memiliki kode ini:

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

Apakah ada cara bagi saya untuk melakukan ini:

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

Sunting: Saya awalnya telah meminta variabel kelas secara keliru.

Chris Bunch
sumber
Contoh Anda menunjukkan "variabel instan". Variabel kelas adalah hal lain.
S. Lott

Jawaban:

143

Setiap objek memiliki __dict__variabel yang berisi semua variabel dan nilainya di dalamnya.

Coba ini

>>> hi_obj = hi()
>>> hi_obj.__dict__.keys()
cnu
sumber
7
FWIW, modul inspeksi memberi Anda metode yang lebih andal daripada mengandalkan dict , yang tidak dimiliki semua instance.
Thomas Wouters
1
Contoh macam apa yang tidak memiliki dict ? Saya belum pernah bertemu satu pun.
Carl Meyer
3
Jenis bawaan tertentu, seperti int. Coba ucapkan "x = 5" lalu "x .__ dict__" dan Anda akan mendapatkan AttributeError
Eli Courtwright
6
Juga, apapun yang menggunakan slot .
Thomas Wouters
2
Mengapa Anda ingin mencoba dan mendapatkan variabel instance kelas dari sebuah int? Ini bahkan bukan kelas (meskipun saya bisa salah dalam hal itu).
Martin Sherburn
103

Gunakan vars ()

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

vars(Foo()) #==> {'a': 1, 'b': 2}
vars(Foo()).keys() #==> ['a', 'b']
Jeremy Cantrell
sumber
6
+1 Saya pribadi berpikir sintaks ini lebih bersih daripada menggunakan dict , karena atribut dengan garis bawah ganda seharusnya menjadi "pribadi" dalam sintaks Python.
Martin W
3
@Martin: __methodbersifat pribadi, __method__merupakan metode khusus, tidak harus pribadi; Saya ingin mengatakan metode khusus mendefinisikan kemampuan objek daripada metode.
u0b34a0f6ae
2
__method__cukup jelek, dan saya pikir mereka dinamai seperti itu untuk mencoba dan menghalangi orang dari menggunakannya kecuali benar-benar diperlukan. Dalam hal ini kami memiliki alternatif vars ().
Martin Sherburn
dalam kasus saya, saya mencoba memanggil vars (ObjName) dan mengembalikan dict_proxy dengan kamus yang kuncinya adalah metode kelas / objek yang diberikan, tetapi tidak ada tanda elemen init . Ada tebakan kenapa?
pengguna228137
Variabel Garis Bawah Ganda __str__, __method__untuk bahasa itu sendiri biasanya. Apa yang terjadi saat Anda str(something)?
Zizouz212
15

Anda biasanya tidak bisa mendapatkan atribut instance yang diberikan hanya sebuah kelas, setidaknya tidak tanpa membuat instance kelas tersebut. Anda bisa mendapatkan atribut instance jika diberi instance, atau atribut kelas yang diberikan kelas. Lihat modul 'inspect'. Anda tidak bisa mendapatkan daftar atribut instance karena instance benar-benar dapat memiliki apa saja sebagai atribut, dan - seperti dalam contoh Anda - cara normal untuk membuatnya adalah dengan menetapkannya di metode __init__.

Pengecualiannya adalah jika kelas Anda menggunakan slot, yang merupakan daftar tetap atribut yang diizinkan oleh kelas untuk dimiliki oleh instance. Slot dijelaskan di http://www.python.org/2.2.3/descrintro.html , tetapi ada berbagai kendala dengan slot; mereka mempengaruhi tata letak memori, sehingga beberapa warisan mungkin bermasalah, dan warisan secara umum harus memperhitungkan slot juga.

Thomas Wouters
sumber
Downvoting karena "Anda tidak bisa mendapatkan daftar atribut instance" adalah salah: baik vars () dan dict memberi Anda hal itu.
Carl Meyer
2
Saya berasumsi yang dia maksud adalah "Anda tidak bisa mendapatkan daftar semua kemungkinan atribut contoh". Misalnya, saya sering menggunakan lazy generation dan @property decorator untuk menambahkan variabel instance saat pertama kali diminta. Menggunakan dict akan memberi tahu Anda tentang variabel ini setelah ada tetapi tidak sebelumnya.
Eli Courtwright
5
Saya tidak memberi suara negatif, dan harap perhatikan apa yang sebenarnya saya katakan: Anda tidak bisa mendapatkan daftar atribut contoh yang diberikan hanya sebuah kelas , yang coba dilakukan oleh kode yang menyertai pertanyaan.
Thomas Wouters
2
@Carl: Harap didik diri Anda sendiri sebelum menulis komentar palsu dan downvoting berdasarkan kurangnya pengetahuan Anda.
nikow
14

Metode Vars () dan dict akan bekerja untuk contoh yang diposting OP, tetapi metode tersebut tidak akan berfungsi untuk objek yang didefinisikan "secara longgar" seperti:

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

Untuk mencetak semua atribut non-callable, Anda dapat menggunakan fungsi berikut:

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
tanda
sumber
5
exec('print object.%s\n\n') % iharus ditulis sebagaiprint getattr(object, i)
user102008
11

Anda juga dapat menguji apakah suatu objek memiliki variabel tertentu dengan:

>>> hi_obj = hi()
>>> hasattr(hi_obj, "some attribute")
daniel
sumber
6

Contoh Anda menunjukkan "variabel instan", bukan variabel kelas yang sebenarnya.

Cari hi_obj.__class__.__dict__.items()variabel kelas, bersama dengan anggota kelas lainnya seperti fungsi anggota dan modul yang memuatnya.

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

Variabel kelas dibagikan oleh semua instance kelas.

S. Lott
sumber
6

Menyarankan

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

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

Dengan kata lain, ini pada dasarnya hanya membungkus __dict__

daniel
sumber
5

Meskipun bukan merupakan jawaban langsung untuk pertanyaan OP, ada cara yang cukup bagus untuk mengetahui variabel apa saja yang ada dalam lingkup suatu fungsi. lihat kode ini:

>>> 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')
>>> 

Atribut func_code memiliki semua jenis hal menarik di dalamnya. Ini memungkinkan Anda melakukan beberapa hal keren. Berikut adalah contoh bagaimana saya telah menggunakan ini:

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'
tim.tadh
sumber
2

dibangun di atas jawaban dmark untuk mendapatkan yang berikut, yang berguna jika Anda menginginkan persamaan sprintf dan semoga akan membantu seseorang ...

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
Ethan Joffe
sumber
0

Terkadang Anda ingin memfilter daftar berdasarkan vars publik / pribadi. Misalnya

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('_')]
hi2meuk
sumber