Bagaimana cara menghitung properti objek dengan Python?

133

IC # kita melakukannya melalui refleksi. Dalam Javascript itu sederhana seperti:

for(var propertyName in objectName)
    var currentPropertyValue = objectName[propertyName];

Bagaimana cara melakukannya dengan Python?

Jader Dias
sumber
3
Harap perhatikan bahwa pertanyaan ini salah kaprah. Sebagian besar jawaban adalah tentang penghitungan anggota . Saya sedang mencari cara untuk menghitung properti , yaitu anggota kelas yang didekorasi @property.
Tomasz Gandor

Jawaban:

153
for property, value in vars(theObject).iteritems():
    print property, ": ", value

Ketahuilah bahwa dalam beberapa kasus yang jarang ada __slots__properti, kelas seperti itu seringkali tidak memiliki __dict__.

Georg Schölly
sumber
1
sekarang bagaimana cara mengubah nilainya? di Javascript Anda bisa melakukan: object [properti] = newValue. Bagaimana cara melakukannya dengan Python?
Jader Dias
39
gunakan setattr () sebagai gantinya.
Nelson
1
@Nelson Bisakah Anda menjelaskan mengapa itu pilihan yang lebih baik? Apakah hanya lebih pendek, atau ada pertimbangan tambahan?
WhyNotHugo
8
@Hugo: Pertama karena "pythonic", dengan kata lain itulah sintaks yang diharapkan sebagian besar komunitas. Sintaks lain kemungkinan tidak perlu memberikan jeda kepada siapa pun yang membaca kode Anda. Kedua, beberapa tipe mengimplementasikan setter __setattr__(). Menetapkan nilai secara langsung pada kamus melewati penyetel objek (dan / atau orang tuanya). Ini cukup umum dalam python bahwa lebih banyak hal daripada bertemu mata terjadi di latar belakang selama pengaturan atribut (misalnya sanitasi), menggunakan setattr()memastikan bahwa Anda tidak ketinggalan, atau dipaksa untuk menanganinya secara eksplisit sendiri.
Michael Ekoka
3
@ Hi-Angel Itu tidak bekerja. Namun, yang tidak berfungsi adalah konstelasi prakonsepsi dan asumsi yang Anda miliki tentang status sekitar versus anggota objek dinamis dengan Python. vars()hanya mengembalikan anggota statis (yaitu, atribut objek dan metode yang terdaftar dengan objek itu __dict__). Itu tidak mengembalikan anggota dinamis (yaitu, atribut dan metode objek didefinisikan secara dinamis oleh __getattr__()metode objek itu atau sihir yang serupa). Kemungkinan besar, file.ImplementationNameproperti yang Anda inginkan didefinisikan secara dinamis dan karenanya tidak tersedia untuk vars()atau dir().
Cecil Curry
69

Lihat inspect.getmembers(object[, predicate]).

Kembalikan semua anggota suatu objek dalam daftar pasangan (nama, nilai) yang diurutkan berdasarkan nama. Jika argumen predikat opsional disediakan, hanya anggota yang predikatnya mengembalikan nilai sebenarnya yang disertakan.

>>> [name for name,thing in inspect.getmembers([])]
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', 
'__delslice__',    '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', 
'__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', 
'__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__','__reduce_ex__', 
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', 
'__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 
'insert', 'pop', 'remove', 'reverse', 'sort']
>>> 
Gimel
sumber
Ya, jawaban ini luar biasa; tidak pernah menggunakan modul ini sebelumnya. getmembers () diimplementasikan dengan hanya berjalan hasil dir (objek), btw.
Nelson
Bisakah Anda menguraikan mengapa ini lebih baik daripada mengakses dict ? Dokumentasi Python kurang bermanfaat, terutama karena biasanya ia menggunakan istilah attributesalih-alih members(apakah ada perbedaan di antara keduanya?). Mereka bisa memperbaiki nama dengan Python 3.0 agar konsisten.
nikow
Ups, artinya __dict__, maaf.
nikow
4
@nikow: inspect.getmembers () dijamin akan tetap berfungsi meskipun detail internal berubah.
Georg Schölly
3
@NicholasKnight inspect.getmembers()membungkus dir()dengan manfaat samping (sebagian besar diabaikan) (A) termasuk atribut kelas dinamis dan atribut metaclass dan (B) tidak termasuk anggota yang tidak cocok dengan predikat yang lulus. Menguap, kan? inspect.getmembers()sesuai untuk pustaka pihak ketiga yang secara umum mendukung semua jenis objek yang mungkin. Namun, untuk kasus penggunaan standar, dir()cukup memadai.
Cecil Curry
66

dir()adalah cara sederhana. Lihat disini:

Panduan Untuk Introspeksi Python

EBGreen
sumber
2
Sesuatu yang perlu dicatat dari Python docs, karena dir () disediakan terutama sebagai kenyamanan untuk digunakan pada prompt interaktif, ia mencoba untuk memasok satu set nama yang menarik lebih dari itu mencoba untuk memasok serangkaian nama yang didefinisikan secara ketat atau konsisten, dan perilakunya yang terperinci dapat berubah antar rilis. Misalnya, atribut metaclass tidak ada dalam daftar hasil ketika argumennya adalah kelas.
skyler
1
jawaban ini adalah yang terbaik ketika melakukan pekerjaan awal pada cli.
15 tahun python (bukan pekerjaan penuh waktu) dan saya masih lupa dir()terima kasih.
Abhishek Dujari
14

The __dict__properti dari objek adalah kamus semua properti lainnya yang ditetapkan. Perhatikan bahwa kelas Python dapat mengesampingkan getattr dan membuat hal-hal yang terlihat seperti properti tetapi tidak ada di dalamnya__dict__ . Ada juga fungsi builtin vars()dan dir()yang berbeda dalam cara yang halus. Dan __slots__dapat menggantikan __dict__di beberapa kelas yang tidak biasa.

Objek rumit dengan Python. __dict__adalah tempat yang tepat untuk memulai pemrograman gaya refleksi. dir()adalah tempat untuk memulai jika Anda mencari-cari di shell interaktif.

Nelson
sumber
print vars.__doc__menunjukkan bahwa With an argument, equivalent to object.__dict__Jadi apa perbedaan yang halus itu?
sancho.s ReinstateMonicaCellio
11

georg versi yang lebih pendek

print vars(theObject)
Nicolas Rojo
sumber
10

Jika Anda mencari refleksi dari semua properti, jawaban di atas sangat bagus.

Jika Anda hanya mencari untuk mendapatkan kunci kamus (yang berbeda dari 'objek' dengan Python), gunakan

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']
MrE
sumber
1
meskipun itu jawaban saya, saya tidak berpikir itu harus menjadi jawaban yang diterima: kunci dari suatu objek berbeda dari properti dari instance objek dari kelas. Mereka diakses secara berbeda ( obj['key']vs. obj.property) dan pertanyaannya adalah tentang properti objek. Saya meletakkan jawaban saya di sini karena ada kebingungan yang mudah antara keduanya.
MrE
Saya sebenarnya menyarankan untuk menghapus jawaban ini.
Ente
Seperti yang dinyatakan di atas, orang yang berasal dari Javascript atau C # misalnya mudah bingung oleh terminologi karena tidak ada perbedaan antara 2 konsep tersebut. Orang-orang yang belajar python dan mencoba mengakses kunci sangat mungkin mencari 'properti' dan berakhir di sini, maka dari itu saya pikir itu milik.
MrE
dan Anda benar, tetapi luput intinya: dalam bahasa lain (ambil JS) tidak ada perbedaan antara objek dan kamus. OP berasal dari C # yang mengajukan pertanyaan. Jawaban ini, walaupun salah, mendapat 11 upvotes, bukti bahwa orang-orang yang mendarat di sini merasakan manfaatnya, meskipun secara teknis bukan jawaban yang tepat (seperti yang saya tunjukkan) untuk pertanyaan ketika melihatnya dalam istilah python yang ketat. Saya akan mengedit untuk membuatnya lebih jelas.
MrE
5

Ini sepenuhnya tercakup oleh jawaban lain, tetapi saya akan membuatnya eksplisit. Objek mungkin memiliki atribut kelas dan atribut instance statis dan dinamis.

class foo:
    classy = 1
    @property
    def dyno(self):
        return 1
    def __init__(self):
        self.stasis = 2

    def fx(self):
        return 3

stasisbersifat statis, dynodinamis (lih. dekorator properti) dan classymerupakan atribut kelas. Jika kita hanya melakukan __dict__atau varskita hanya akan mendapatkan yang statis.

o = foo()
print(o.__dict__) #{'stasis': 2}
print(vars(o)) #{'stasis': 2}

Jadi jika kita mau yang lain __dict__akan mendapatkan segalanya (dan banyak lagi). Ini termasuk metode dan atribut sihir dan metode terikat normal. Jadi mari kita hindari itu:

d = {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}
print(d) #{'stasis': 2, 'classy': 1, 'dyno': 1}

Yang typedipanggil dengan metode yang didekorasi dengan properti (atribut dinamis) akan memberi Anda jenis nilai yang dikembalikan, bukan method. Untuk membuktikan ini, mari kita rekatkan:

import json
print(json.dumps(d)) #{"stasis": 2, "classy": 1, "dyno": 1}

Seandainya itu metode yang pasti akan crash.

TL; DR. coba panggil extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}ketiganya, tetapi jangan metode atau sihir.

Matteo Ferla
sumber