Bagaimana cara memanggil setattr () pada modul saat ini?

143

Apa yang harus saya berikan sebagai parameter pertama " object" ke fungsi setattr(object, name, value), untuk menyetel variabel pada modul saat ini?

Sebagai contoh:

setattr(object, "SOME_CONSTANT", 42);

memberikan efek yang sama seperti:

SOME_CONSTANT = 42

dalam modul yang berisi baris-baris ini (dengan benar object).

Saya menghasilkan beberapa nilai pada level modul secara dinamis, dan karena saya tidak dapat mendefinisikan __getattr__pada level modul, ini adalah fallback saya.

Matt Joiner
sumber

Jawaban:

225
import sys

thismodule = sys.modules[__name__]

setattr(thismodule, name, value)

atau, tanpa menggunakan setattr(yang mematahkan surat pertanyaan tetapi memenuhi tujuan praktis yang sama ;-):

globals()[name] = value

Catatan : pada module scope, yang terakhir ini setara dengan:

vars()[name] = value

yang sedikit lebih ringkas, tetapi tidak berfungsi dari dalam suatu fungsi ( vars()memberikan variabel ruang lingkup yang dipanggilnya di: variabel modul ketika dipanggil di lingkup global, dan kemudian tidak apa-apa untuk menggunakannya R / W, tetapi fungsinya variabel ketika dipanggil dalam suatu fungsi, dan kemudian harus diperlakukan sebagai R / O - dokumen online Python dapat sedikit membingungkan tentang perbedaan khusus ini).

Alex Martelli
sumber
9
Dokumen memberi peringatan tentang memodifikasi vars (). docs.python.org/library/functions.html#vars . Kapan boleh melakukan ini?
unutbu
2
@ ~ unutbu, saya tidak akan benar-benar mengatakan bahwa ini cukup "oke", tetapi ini akan bekerja ketika Anda memanggil vars()di lingkup tingkat modul daripada di dalam fungsi.
Mike Graham
4
vars()setara dengan globals()at module scope (dan mengembalikan sebuah dikt yang benar dan dapat dimodifikasi) tetapi ke locals()pada ruang lingkup fungsi (dan mengembalikan pseudodiktus yang tidak pernah dimodifikasi). Saya menggunakan vars()di lingkup modul karena menyimpan 3 karakter, satu suku kata, vs sinonim-dalam-lingkup-itu globals();-)
Alex Martelli
14
Ya, itu akan menghancurkan satu-satunya pengoptimalan terpenting yang dilakukan oleh kompilator Python: variabel lokal suatu fungsi tidak disimpan dalam sebuah dict, mereka berada dalam vektor nilai yang ketat, dan setiap akses variabel lokal menggunakan indeks dalam vektor itu, bukan pencarian nama. Untuk mengalahkan pengoptimalan, memaksa dikt yang Anda inginkan untuk ada, mulai fungsinya dengan exec '': waktu fungsi dengan beberapa loop substansial setiap cara, dan Anda akan melihat pentingnya pengoptimalan inti ini untuk kinerja Python.
Alex Martelli
3
@ msw, saya pikir Anda lupa "kepraktisan mengalahkan kemurnian" ;-).
Alex Martelli
7

Di Python 3.7, Anda akan dapat menggunakan __getattr__di level modul ( jawaban terkait ).

Per PEP 562 :

def __getattr__(name):
    if name == "SOME_CONSTANT":
        return 42
    raise AttributeError(f"module {__name__} has no attribute {name}")
Trey Hunner
sumber
6

Jika Anda harus menyetel variabel cakupan modul dari dalam modul, apa yang salah global?

# my_module.py

def define_module_scoped_variables():
    global a, b, c
    a, b, c = 'a', ['b'], 3

jadi:

>>> import my_module
>>> my_module.define_module_scoped_variables()
>>> a
NameError: name 'a' is not defined
>>> my_module.a
'a'
>>> my_module.b
['b']
msw
sumber
1
Ya, saya selalu (di mana "selalu" didefinisikan sebagai "beberapa bulan terakhir saya telah belajar Python") menemukan bahwa global but not reallypernyataan itu membingungkan. Saya kira itu mungkin peninggalan sejarah yang mendahului ruang nama modul.
msw
1
Pertanyaan awal adalah menanyakan bagaimana menyetel atribut yang namanya diberikan oleh string (hal yang sama yang saya cari saat ini), jadi ini tidak akan membantu.
Curt
-1
  1. Anda tidak akan. Anda akan melakukannyaglobals()["SOME_CONSTANT"] = 42
  2. Anda tidak akan. Anda akan menyimpan konten yang dibuat secara dinamis di tempat lain selain modul.
Mike Graham
sumber
Ya, SOME_CONSTANTdihitung saat run-time tidak benar-benar konstan. Dan jika globals()tidak tersedia untuk Anda, maka Anda harus menjangkau modul lain untuk mengubah atributnya; yang pasti membuat orang bertanya-tanya.
msw
3
Konstan dan bisa berubah sama-sama eksklusif. Konstan dan secara dinamis tidak dihasilkan. Nilai yang saya hasilkan selalu sama, dan ditentukan berdasarkan "konstanta" lebih lanjut, untuk menghemat aritmatika dan mengetik di pihak saya.
Matt Joiner