Bisakah saya menggunakan __init__.py untuk mendefinisikan variabel global?

130

Saya ingin mendefinisikan konstanta yang harus tersedia di semua submodul dari sebuah paket. Saya sudah berpikir bahwa tempat terbaik adalah di dalam __init__.pyfile paket root. Tetapi saya tidak tahu bagaimana melakukan ini. Misalkan saya memiliki beberapa sub paket dan masing-masing dengan beberapa modul. Bagaimana saya bisa mengakses variabel itu dari modul-modul ini?

Tentu saja, jika ini benar-benar salah, dan ada alternatif yang lebih baik, saya ingin mengetahuinya.

Andrei Vajna II
sumber

Jawaban:

196

Anda harus bisa memasukkannya __init__.py. Ini dilakukan setiap saat.

mypackage/__init__.py:

MY_CONSTANT = 42

mypackage/mymodule.py:

from mypackage import MY_CONSTANT
print "my constant is", MY_CONSTANT

Kemudian, impor modul saya:

>>> from mypackage import mymodule
my constant is 42

Namun, jika Anda memiliki konstanta, akan masuk akal (praktik terbaik, mungkin) untuk meletakkannya dalam modul terpisah (constants.py, config.py, ...) dan kemudian jika Anda menginginkannya dalam paket namespace, impor mereka.

mypackage/__init__.py:

from mypackage.constants import *

Namun, ini tidak secara otomatis menyertakan konstanta dalam ruang nama modul paket. Setiap modul dalam paket masih harus mengimpor konstanta secara eksplisit baik dari mypackageatau dari mypackage.constants.

Jason R. Coombs
sumber
19
Ini seharusnya jawaban yang diterima. Jika Anda bekerja dengan Python 2.5 atau lebih tinggi, Anda juga dapat menggunakan impor relatif eksplisit serta dijelaskan di sini : from . import MY_CONSTANT
ThatAintWorking
bukankah cara kedua hanya berfungsi untuk konstanta? from mypackage.constants import *akan menempatkan salinan MY_CONSTANTdalam setiap submodule daripada referensi ke variabel yang sama
hardmooth
@hardmooth: Tidak juga. Nilai-nilai disalin dengan referensi, jadi jika Anda bermutasi MY_CONSTANTdi salah satu modul, itu akan bermutasi di mana-mana. Jika Anda ditugaskan ulang MY_CONSTANTdi salah satu modul, itu hanya akan mempengaruhi modul itu. Jika itu niat Anda, Anda harus referensi berdasarkan atribut, yaitu mypackage.constants.MY_CONSTANT.
Jason R. Coombs
7
Satu menangkap dengan contoh adalah jika Anda mengimpor mymodule.pydalam __init__.pysebelum MY_CONSTANT = 42itu akan gagal karena ketika mengimpor mymodule.py MY_CONSTANTbelum ditetapkan belum. Jadi perlu pindah ke MY_CONSTANT = 42atasimport mymodule
markmnl
bagaimana dengan variabel? Ini bertanya tentang variabel, bukan konstanta. Bagaimana python memperlakukan variabel di dalam paket? Bagaimana Jika variabel di dalam paket telah diubah?
TomSawyer
31

Kamu tidak bisa melakukan itu. Anda harus mengimpor konstanta Anda secara eksplisit ke namespace setiap modul. Cara terbaik untuk mencapai ini adalah dengan mendefinisikan konstanta Anda dalam modul "konfigurasi" dan mengimpornya di mana pun Anda membutuhkannya:

# mypackage/config.py
MY_CONST = 17

# mypackage/main.py
from mypackage.config import *
Ferdinand Beyer
sumber
Ya, file konfigurasi adalah apa yang saya inginkan. Saya hanya berpikir bahwa init .py akan menjadi tempat yang bagus. Solusi Anda terdengar seperti praktik standar. Apakah itu?
Andrei Vajna II
1
Poin yang bagus. Saya tidak menyadari pertanyaannya adalah agar konstanta secara otomatis ditempatkan di namespace dari semua modul paket.
Jason R. Coombs
Tetapi setiap kali skrip mengimpor config.py, kode di dalamnya dijalankan. Apa yang Anda rekomendasikan jika kode di dalam config.py hanya dijalankan sekali? Katakanlah saya membaca file settings.json di dalam config.py dan saya tidak ingin membukanya () setiap kali saya mengimpor config.py.
Augiwan
@UGS Ini bukan cara kerja Python. Setiap modul dijalankan hanya sekali. Ketika diimpor untuk kedua kalinya, modul sudah di-cache sys.modules.
Ferdinand Beyer
@FerdinandBeyer Ups! Saya lupa menyebutkan bahwa saya mengimpor config.py dari beberapa skrip dan bukan skrip yang sama. Katakan a.py mengimpor config.py & b.py dan b.py mengimpor config.py. Saya bertanya-tanya apakah mungkin untuk memastikan kode di dalam config.py dijalankan hanya sekali.
Augiwan
2

Anda dapat mendefinisikan variabel global dari mana saja, tetapi itu adalah ide yang sangat buruk. impor __builtin__modul dan modifikasi atau tambahkan atribut ke modul ini, dan tiba-tiba Anda memiliki konstanta atau fungsi bawaan yang baru. Bahkan, ketika aplikasi saya menginstal gettext, saya mendapatkan fungsi _ () di semua modul saya, tanpa mengimpor apa pun. Jadi ini mungkin, tetapi tentu saja hanya untuk proyek tipe Aplikasi, bukan untuk paket atau modul yang dapat digunakan kembali.

Dan saya kira tidak ada yang akan merekomendasikan praktik ini. Apa yang salah dengan namespace? Aplikasi tersebut memiliki modul versi, sehingga saya memiliki variabel "global" yang tersedia seperti version.VERSION, version.PACKAGE_NAMEdll.

u0b34a0f6ae
sumber
0

Hanya ingin menambahkan bahwa konstanta dapat digunakan menggunakan file config.ini dan diuraikan dalam skrip menggunakan perpustakaan configparser. Dengan cara ini Anda bisa memiliki konstanta untuk berbagai keadaan. Misalnya, jika Anda memiliki konstanta parameter untuk dua permintaan URL terpisah, beri label seperti:

mymodule/config.ini
[request0]
conn = 'admin@localhost'
pass = 'admin'
...

[request1]
conn = 'barney@localhost'
pass = 'dinosaur'
...

Saya menemukan dokumentasi di situs web Python sangat membantu. Saya tidak yakin apakah ada perbedaan antara Python 2 dan 3 jadi di sini adalah tautan ke keduanya:

Untuk Python 3: https://docs.python.org/3/library/configparser.html#module-configparser

Untuk Python 2: https://docs.python.org/2/library/configparser.html#module-configparser

Dan Temkin
sumber