Cara mengetahui apakah suatu objek memiliki atribut dalam Python

1635

Apakah ada cara di Python untuk menentukan apakah suatu objek memiliki beberapa atribut? Sebagai contoh:

>>> a = SomeClass()
>>> a.someProperty = value
>>> a.property
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: SomeClass instance has no attribute 'property'

Bagaimana Anda tahu apakah amemiliki atribut propertysebelum menggunakannya?

Lucas Gabriel Sánchez
sumber

Jawaban:

2343

Coba hasattr():

if hasattr(a, 'property'):
    a.property

EDIT: Lihat jawaban zweiterlinde di bawah ini, yang menawarkan saran bagus tentang meminta maaf! Pendekatan yang sangat pythonic!

Praktik umum dalam python adalah bahwa, jika properti kemungkinan besar ada di sana sebagian besar waktu, cukup panggil dan biarkan perkecualian merambat, atau menjebaknya dengan blok coba / kecuali. Ini kemungkinan akan lebih cepat daripada hasattr. Jika properti cenderung tidak ada di sebagian besar waktu, atau Anda tidak yakin, menggunakan hasattrmungkin akan lebih cepat daripada berulang kali jatuh ke blok pengecualian.

Jarret Hardie
sumber
19
Tampaknya berfungsi untuk memeriksa fungsi-fungsi di namespace juga, misalnya: import string hasattr(string, "lower")
riviera
15
hasattrpersis sama dengan menggunakan try/ except AttributeError: docstring dari hasattr (dalam Python 2.7) mengatakan bahwa ia menggunakan getattr tangkapan tangan pengecualian.
Jeff Tratner
8
@ JeffTratner: hasattrsayangnya tidak persis sama dengan try: ... except AttributeError:di Python 2.x karena hasattrakan menangkap semua pengecualian . Silakan lihat jawaban saya untuk contoh dan solusi sederhana.
Martin Geisler
632

Seperti Jarret Hardie menjawab, hasattrakan melakukan trik. Saya ingin menambahkan, bahwa banyak di komunitas Python merekomendasikan strategi "lebih mudah untuk meminta pengampunan daripada izin" (EAFP) daripada "lihat sebelum Anda melompat" (LBYL). Lihat referensi ini:

EAFP vs LBYL (adalah Re: Sedikit kecewa sejauh ini)
EAFP vs LBYL @Code Like a Pythonista: Idiomatic Python

yaitu:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

... lebih disukai daripada:

if hasattr(a, 'property'):
    doStuff(a.property)
else:
    otherStuff()
zweiterlinde
sumber
259
Tapi bagaimana Anda memeriksa bahwa itu adalah properti yang menyebabkan AttributeError, dan bukan sesuatu di doStuff ()? Sepertinya kamu tidak. Saya pikir lebih mudah untuk meminta pengampunan, tetapi seringkali, itu juga salah.
jpalecek
286
EAFP sepertinya ... gila. HasAttr mengirim telegraf kepada pemrogram pemeliharaan masa depan yang Anda periksa untuk atribut tertentu. Mendapatkan pengecualian tidak memberi tahu programmer masa depan apa pun dan bisa menuntun seseorang ke lubang kelinci.
Ethan Heilman
74
@ e5: Anda memiliki titik adil dalam kasus ini, tetapi dalam banyak kasus EAFP adalah satu-satunya pilihan yang benar. Misalnya, jika Anda memeriksa keberadaan file dan kemudian membukanya, berharap itu pasti ada, kode Anda salah: file mungkin dihapus atau diganti nama antara cek dan penggunaan. Ini disebut kesalahan TOCTOU (Time-Of-Check-To-Time-Of-Use) dan selain itu menyebabkan crash juga dapat menjadi sumber kerentanan keamanan.
Maks
15
@EthanHeilman itu hanya gila ketika ada ambiguitas dalam sumber pengecualian, yang dapat dihindari dengan desain yang bagus dalam banyak kasus. Penataan logika yang baik dalam try / kecuali / akhirnya umumnya membuat logika yang lebih kuat (lebih sedikit kesalahan programmer) daripada mengotori kode dengan preemptive if-check untuk setiap bagian dari kode pengkonsumsi. Membuat kesalahan sangat eksplisit juga, dan memungkinkan pemrogram pilihan untuk berurusan dengan mereka secara langsung.
Peter M. Elias
64
Sebagian besar keluhan ambiguitas di sini hanya karena kode sampel terstruktur dengan buruk. Satu-satunya hal di dalam try:seharusnya adalah akses atribut yang dicoba; tidak ada alasan untuk membungkus eksekusi doStuffjuga. Namun, masih ada beberapa potensi ambiguitas: jika propertymerupakan properti yang dihitung alih-alih atribut biasa, implementasinya dapat meningkat secara AttributeErrorinternal. Inilah sebabnya mengapa dalam hampir semua situasi nyata seperti ini, getattrlebih disukai daripada hasattrmenangkap atau menangkap AttributeError.
Carl Meyer
485

Anda dapat menggunakan hasattr()atau menangkap AttributeError, tetapi jika Anda benar-benar hanya ingin nilai atribut dengan default jika tidak ada, opsi terbaik adalah dengan menggunakan getattr():

getattr(a, 'property', 'default value')
Carl Meyer
sumber
14
Ini memecahkan kedua masalah yang disebutkan di atas: a) Ketidakjelasan sumber kemungkinan AttributeError, b) Melestarikan pendekatan EAFP.
Peter M. Elias
6
Ini juga 25% dari baris kode. Tentunya ini harus menjadi solusi terbaik.
fatuhoku
16
Ini adalah solusi terbaik "jika Anda benar-benar hanya ingin nilai atribut dengan default." Meskipun saya percaya ini adalah apa yang sebenarnya diinginkan banyak orang ketika mereka mengatakan mereka ingin mendeteksi apakah suatu atribut hadir, OP sebenarnya meminta yang terakhir, jadi masuk akal jika jawaban langsung untuk pertanyaan itu (hasattr, AttributeError) dicantumkan lebih tinggi .
Carl Meyer
41

Saya pikir apa yang Anda cari adalah hasattr . Namun, saya akan merekomendasikan sesuatu seperti ini jika Anda ingin mendeteksi properti python -

try:
    getattr(someObject, 'someProperty')         
except AttributeError:
    print "Doesn't exist"
else
    print "Exists"

Kerugian di sini adalah bahwa kesalahan atribut dalam __get__kode properti juga ditangkap.

Kalau tidak, jangan-

if hasattr(someObject, 'someProp'):
    #Access someProp/ set someProp
    pass

Documents: http://docs.python.org/library/functions.html
Peringatan:
Alasan rekomendasi saya adalah bahwa hasattr tidak mendeteksi properti.
Tautan: http://mail.python.org/pipermail/python-dev/2005-December/058498.html

batbrat
sumber
3
hasattrmendeteksi properti secara umum baik-baik saja. Hanya saja itu memperlakukan meningkatkan pengecualian dalam propertyfungsi -wrapped karena berarti tidak ada atribut seperti itu; posting milis Python yang ditautkan adalah tentang properti yang menimbulkan pengecualian ketika Anda mencoba mengaksesnya. Untuk semua tujuan praktis, atribut tersebut tidak ada, karena tidak akan pernah menghasilkan nilai. Juga, hasattrhanya menekan pengecualian secara umum pada Py 3.1 dan sebelumnya; di 3.2+, itu hanya menekan (mengganti dengan Falsekembali) AttributeError.
ShadowRanger
32

Menurut pydoc, hasattr (obj, prop) cukup memanggil getattr (obj, prop) dan menangkap pengecualian. Jadi, sama validnya untuk membungkus akses atribut dengan pernyataan coba dan tangkap AttributeError karena menggunakan hasattr () sebelumnya.

a = SomeClass()
try:
    return a.fake_prop
except AttributeError:
    return default_value
Jordan Lewis
sumber
2
Nah hasattr sebenarnya bisa dioptimalkan. Misalnya dengan pypy.
odinho
6
+1. Ini bahkan lebih aman daripada menggunakan hasattrketika SomeClassditimpa __getattr__karena hasattrakan menangkap semua pengecualian dalam Python 2.x, tidak AttributeErrorseperti yang Anda harapkan. Ini diperbaiki dalam Python 3.2 - silakan lihat jawaban saya yang lain untuk solusi sederhana.
Martin Geisler
24

Saya ingin menyarankan untuk menghindari ini:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

Pengguna @jpalecek menyebutkannya: Jika AttributeErrorterjadi di dalam doStuff(), Anda hilang.

Mungkin pendekatan ini lebih baik:

try:
    val = a.property
except AttributeError:
    otherStuff()
else:
    doStuff(val)
Maico
sumber
13

Tergantung pada situasi Anda dapat memeriksa dengan objek isinstanceapa yang Anda miliki, dan kemudian menggunakan atribut yang sesuai. Dengan diperkenalkannya kelas dasar abstrak di Python 2.6 / 3.0 pendekatan ini juga menjadi jauh lebih kuat (pada dasarnya ABC memungkinkan cara yang lebih canggih untuk mengetik bebek).

Satu situasi adalah ini berguna jika dua objek yang berbeda memiliki atribut dengan nama yang sama, tetapi dengan makna yang berbeda. Hanya menggunakanhasattr bisa menyebabkan kesalahan aneh.

Satu contoh yang bagus adalah perbedaan antara iterator dan iterables (lihat pertanyaan ini ). The __iter__metode dalam iterator dan iterable memiliki nama yang sama tetapi secara semantik sangat berbeda! Jadi hasattrtidak ada gunanya, tetapi isinstancebersama dengan ABC memberikan solusi bersih.

Namun, saya setuju bahwa dalam kebanyakan situasi hasattrpendekatan (dijelaskan dalam jawaban lain) adalah solusi yang paling tepat.

nikow
sumber
13

Harap Anda mengharapkan hasattr (), tetapi cobalah untuk menghindari hasattr () dan lebih suka getattr (). getattr () lebih cepat dari hasattr ()

menggunakan hasattr ():

 if hasattr(a, 'property'):
     print a.property

sama di sini saya menggunakan getattr untuk mendapatkan properti jika tidak ada properti itu tidak mengembalikan apa pun

   property = getattr(a,"property",None)
    if property:
        print property
Janarthanan Ramu
sumber
11

EDIT : Pendekatan ini memiliki batasan serius. Ini harus bekerja jika objek itu objek yang dapat diubah . Silakan periksa komentar di bawah ini.

Jika Anda menggunakan Python 3.6 atau lebih tinggi seperti saya, ada alternatif yang nyaman untuk memeriksa apakah suatu objek memiliki atribut tertentu:

if 'attr1' in obj1:
    print("attr1 = {}".format(obj1["attr1"]))

Namun, saya tidak yakin mana yang merupakan pendekatan terbaik saat ini. menggunakan hasattr(), menggunakan getattr()atau menggunakan in. Komentar diterima.

nayak
sumber
6
inkata kunci berfungsi untuk memeriksa jenis yang dapat diubah. Misalnya, 'foo' in Nonemelempar kesalahan TypeError: argument of type 'NoneType' is not iterable. Cara mengatasinya adalah untuk memeriksa apakah jenisnya dapat diubah sebelum digunakan in. Setelah mengoreksi kasus tepi seperti jenis yang tidak dapat diubah, Anda mungkin lebih baik menggunakan hasattr()karena dirancang untuk menangani kasus tepi.
Seth Difley
3
Ini tidak ada hubungannya dengan akses atribut. Saya tidak tahu bagaimana itu bisa dipilih. Satu-satunya kesamaan yang harus dimiliki akses atribut adalah jika Anda menggunakan dictsebagai "objek ringan", mirip dengan desain objek JavaScript, tetapi sebagian besar kelas normal tidak akan mendukung ini secara umum (mendapatkan varian pada kesalahan yang disebutkan oleh @SethDifley) .
ShadowRanger
6

Inilah pendekatan yang sangat intuitif:

if 'property' in dir(a):
    a.property
Alec Alameddine
sumber
1

Ini super sederhana, cukup gunakan dir(objek.)
Ini akan mengembalikan daftar setiap fungsi dan atribut objek yang tersedia.

Kristen Sean
sumber
1

Opsi lain yang mungkin, tetapi itu tergantung jika apa yang Anda maksudkan sebelumnya :

undefined = object()

class Widget:

    def __init__(self):
        self.bar = 1

    def zoom(self):
        print("zoom!")

a = Widget()

bar = getattr(a, "bar", undefined)
if bar is not undefined:
    print("bar:%s" % (bar))

foo = getattr(a, "foo", undefined)
if foo is not undefined:
    print("foo:%s" % (foo))

zoom = getattr(a, "zoom", undefined)
if zoom is not undefined:
    zoom()

keluaran:

bar:1
zoom!

Ini memungkinkan Anda bahkan memeriksa atribut Tidak Ada yang dihargai.

Tapi! Berhati-hatilah, Anda tidak sengaja membuat instance dan membandingkan undefinedbeberapa tempat karena isitu tidak akan pernah berfungsi dalam kasus itu.

Memperbarui:

karena apa yang saya peringatkan di paragraf di atas, memiliki banyak undefined yang tidak pernah cocok, saya baru saja sedikit mengubah pola ini:

undefined = NotImplemented

NotImplemented, jangan bingung dengan NotImplementedError, adalah built-in: itu semi-cocok dengan maksud JS undefineddan Anda dapat menggunakan kembali definisi di mana-mana dan itu akan selalu cocok. Kelemahannya adalah "benar" di boolean dan bisa terlihat aneh di log dan tumpukan jejak (tapi Anda cepat mengatasinya ketika Anda tahu itu hanya muncul dalam konteks ini).

JL Peyret
sumber
0

Anda dapat memeriksa apakah objectmengandung atribut dengan menggunakan hasattrmetode builtin.

Misalnya jika objek aAnda dan Anda ingin memeriksa atributstuff

>>> class a:
...     stuff = "something"
... 
>>> hasattr(a,'stuff')
True
>>> hasattr(a,'other_stuff')
False

Metode signature itu sendiri hasattr(object, name) -> boolyang berarti jika objectmemiliki atribut yang diteruskan ke argumen kedua hasattrdaripada memberikan boolean Trueatau Falsesesuai dengan keberadaan nameatribut dalam objek.

Devang Padhiyar
sumber
0

hasattr()adalah jawaban yang tepat. Yang ingin saya tambahkan adalah yang hasattr()juga dapat digunakan dengan baik bersama penegasan (untuk menghindari ifpernyataan yang tidak perlu dan membuat kode lebih mudah dibaca):

assert hasattr(a, 'property'), 'object lacks property' 

Sebagaimana dinyatakan dalam jawaban lain pada SO : Asserts harus digunakan untuk menguji kondisi yang seharusnya tidak pernah terjadi. Tujuannya adalah untuk crash awal dalam kasus program yang korup.

FMF
sumber
Ini membantu tetapi mungkin tidak selalu demikian. Mungkin saya ingin menguji apakah objek memiliki properti dan kemudian menambahkannya untuk pertama kali, atau mungkin saya harus menjalankan kode berbeda untuk objek dengan properti itu. Ketika kode tidak dapat melanjutkan, pernyataan mungkin baik-baik saja. Tetapi sekali lagi, tidak selalu demikian. Yang penting adalah penggunaan hasattrbukan kode sekitarnya.
Lucas Gabriel Sánchez