Saya ingin membuat objek dinamis (di dalam objek lain) dengan Python dan kemudian menambahkan atribut padanya.
Saya mencoba:
obj = someobject obj.a = object() setattr(obj.a, 'somefield', 'somevalue')tetapi ini tidak berhasil.
Ada ide?
edit:
Saya mengatur atribut dari loop for yang loop melalui daftar nilai, mis.
params = ['attr1', 'attr2', 'attr3'] obj = someobject obj.a = object() for p in params: obj.a.p # where p comes from for loop variableDalam contoh di atas saya akan mendapatkan obj.a.attr1, obj.a.attr2, obj.a.attr3.
Saya menggunakan fungsi setattr karena saya tidak tahu bagaimana melakukan obj.a.NAME dari loop for.
Bagaimana saya mengatur atribut berdasarkan nilai p pada contoh di atas?
Anda dapat menggunakan resep kuno Bunch saya, tetapi jika Anda tidak ingin membuat "kelas banyak", yang sangat sederhana sudah ada di Python - semua fungsi dapat memiliki atribut yang berubah-ubah (termasuk fungsi lambda). Jadi, karya-karya berikut:
obj = someobject obj.a = lambda: None setattr(obj.a, 'somefield', 'somevalue')Apakah hilangnya kejelasan dibandingkan dengan resep Bunch yang terhormat itu OK, adalah keputusan gaya saya tentu saja akan menyerahkan kepada Anda.
Built-in object dapat instantiated tetapi tidak dapat menetapkan atribut apa pun di dalamnya. (Saya berharap bisa, untuk tujuan yang tepat ini.) Tidak memiliki __dict__ untuk menyimpan atribut.
Saya biasanya hanya melakukan ini:
class Object(object): pass a = Object() a.somefield = somevalueKetika saya bisa, saya memberi kelas Object nama yang lebih bermakna, tergantung pada data apa yang saya masukkan di dalamnya.
Beberapa orang melakukan hal yang berbeda, di mana mereka menggunakan sub-kelas dict yang memungkinkan akses atribut untuk mendapatkan kunci. (d.key bukan d['key'])
Edit : Untuk tambahan pertanyaan Anda, menggunakan setattr tidak masalah. Anda tidak bisa menggunakan setattr pada contoh object().
params = ['attr1', 'attr2', 'attr3'] for p in params: setattr(obj.a, p, value)Ada beberapa cara untuk mencapai tujuan ini ... Pada dasarnya Anda membutuhkan objek yang dapat diperpanjang.
obj.a = type('Test', (object,), {}) obj.a.b = 'fun' obj.b = lambda:None class Test: pass obj.c = Test()Sekarang Anda bisa melakukannya (tidak yakin apakah itu jawaban yang sama dengan evilpie):
MyObject = type('MyObject', (object,), {}) obj = MyObject() obj.value = 42Modul mock pada dasarnya dibuat untuk itu.
Coba kode di bawah ini:
$ python >>> class Container(object): ... pass ... >>> x = Container() >>> x.a = 10 >>> x.b = 20 >>> x.banana = 100 >>> x.a, x.b, x.banana (10, 20, 100) >>> dir(x) ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'banana']sebagai docs say :
Catatan: object tidak tidak memiliki __dict__, sehingga Anda tidak dapat menetapkan atribut arbitrer ke turunan dari kelas object.
Anda bisa menggunakan instance kelas dummy.
Anda juga dapat menggunakan objek kelas secara langsung; itu menciptakan namespace:
class a: pass a.somefield1 = 'somevalue1' setattr(a, 'somefield2', 'somevalue2')Solusi ini sangat membantu selama pengujian. Membangun jawaban orang lain, saya melakukan ini di Python 2.7.9 (tanpa metode statis saya mendapatkan TypeError (metode tidak terikat ...):
In [11]: auth = type('', (), {}) In [12]: auth.func = staticmethod(lambda i: i * 2) In [13]: auth.func(2) Out[13]: 4Jika kita dapat menentukan dan menggabungkan semua atribut dan nilai sebelum membuat objek bersarang, maka kita bisa membuat kelas baru yang menggunakan argumen kamus tentang pembuatan.
Kami juga dapat mengizinkan argumen kata kunci. Lihat posting ini .
class NestedObject(object): def __init__(self, *initial_attrs, **kwargs): for dictionary in initial_attrs: for key in dictionary: setattr(self, key, dictionary[key]) for key in kwargs: setattr(self, key, kwargs[key]) obj.a = NestedObject(attr1='val1', attr2='val2', attr3= 'val3')Datang ke ini pada sore hari tetapi di sini adalah pennyworth saya dengan objek yang kebetulan memegang beberapa jalur yang berguna dalam aplikasi tetapi Anda dapat mengadaptasinya untuk apa pun di mana Anda ingin sedikit informasi yang dapat Anda akses dengan getattr dan notasi titik (yang menurut saya pertanyaan ini sebenarnya tentang):
import os def x_path(path_name): return getattr(x_path, path_name) x_path.root = '/home/x' for name in ['repository', 'caches', 'projects']: setattr(x_path, name, os.path.join(x_path.root, name))Ini keren karena sekarang:
In [1]: x_path.projects Out[1]: '/home/x/projects' In [2]: x_path('caches') Out[2]: '/home/x/caches'Jadi ini menggunakan objek fungsi seperti jawaban di atas tetapi menggunakan fungsi untuk mendapatkan nilai (Anda masih dapat menggunakan (getattr, x_path, 'repository') daripada x_path('repository') jika Anda mau).
Objek mana yang Anda gunakan? Baru saja mencobanya dengan kelas sampel dan berhasil:
class MyClass: i = 123456 def f(self): return "hello world" b = MyClass() b.c = MyClass() setattr(b.c, 'test', 123) b.c.testDan saya mendapat 123 sebagai jawabannya.
Satu-satunya situasi di mana saya melihat kegagalan ini adalah jika Anda mencoba setattr pada objek bawaan.
Pembaruan: Dari komentar ini adalah pengulangan dari: Mengapa Anda tidak dapat menambahkan atribut ke objek dengan python?