Saya telah mengalami sedikit modul pengimpor dinding dalam skrip Python. Saya akan melakukan yang terbaik untuk menjelaskan kesalahan tersebut, mengapa saya mengalaminya, dan mengapa saya menggunakan pendekatan khusus ini untuk menyelesaikan masalah saya (yang akan saya jelaskan sebentar lagi):
Misalkan saya memiliki modul di mana saya telah mendefinisikan beberapa fungsi / kelas utilitas, yang merujuk ke entitas yang ditentukan dalam namespace tempat modul tambahan ini akan diimpor (misalkan "a" menjadi entitas seperti itu):
modul 1:
def f():
print a
Dan kemudian saya memiliki program utama, di mana "a" didefinisikan, di mana saya ingin mengimpor utilitas tersebut:
import module1
a=3
module1.f()
Menjalankan program akan memicu kesalahan berikut:
Traceback (most recent call last):
File "Z:\Python\main.py", line 10, in <module>
module1.f()
File "Z:\Python\module1.py", line 3, in f
print a
NameError: global name 'a' is not defined
Pertanyaan serupa telah diajukan di masa lalu (dua hari yang lalu, d'uh) dan beberapa solusi telah disarankan, namun menurut saya ini tidak sesuai dengan kebutuhan saya. Inilah konteks khusus saya:
Saya mencoba membuat program Python yang terhubung ke server database MySQL dan menampilkan / memodifikasi data dengan GUI. Demi kebersihan, saya telah mendefinisikan sekumpulan fungsi bantu / utilitas terkait MySQL dalam file terpisah. Namun mereka semua memiliki variabel umum, yang awalnya saya tentukan di dalam modul utilitas, dan yang merupakan objek kursor dari modul MySQLdb. Saya kemudian menyadari bahwa objek kursor (yang digunakan untuk berkomunikasi dengan server db) harus didefinisikan dalam modul utama, sehingga modul utama dan apa pun yang diimpor ke dalamnya dapat mengakses objek itu.
Hasil akhirnya akan seperti ini:
utilities_module.py:
def utility_1(args):
code which references a variable named "cur"
def utility_n(args):
etcetera
Dan modul utama saya:
program.py:
import MySQLdb, Tkinter
db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined!
from utilities_module import *
Dan kemudian, segera setelah saya mencoba memanggil salah satu fungsi utilitas, ini memicu kesalahan "nama global tidak ditentukan" yang disebutkan di atas.
Saran khusus adalah memiliki pernyataan "from program import cur" di file utilitas, seperti ini:
utilities_module.py:
from program import cur
#rest of function definitions
program.py:
import Tkinter, MySQLdb
db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined!
from utilities_module import *
Tapi itu impor siklik atau sesuatu seperti itu dan, intinya, itu macet juga. Jadi pertanyaan saya adalah:
Bagaimana saya bisa membuat objek "cur", yang didefinisikan dalam modul utama, terlihat oleh fungsi tambahan yang diimpor ke dalamnya?
Terima kasih atas waktu Anda dan permintaan maaf saya yang terdalam jika solusinya telah diposting di tempat lain. Saya tidak bisa menemukan jawabannya sendiri dan saya tidak punya trik lagi di buku saya.
fetch_all
dan beralih melalui dua daftar sebagai gantinya , atau agar Anda dapat memiliki dua utas / greenlets / callback-chains / apa pun yang berbeda menggunakan database tanpa konflik).db
(dancur
, jika Anda bersikeras) ke modul terpisah yang keduanyaprogram
danutilities_module
impor darinya. Dengan cara itu Anda tidak mendapatkan dependensi melingkar (mengimpor program dari modul yang diimpor oleh program) dan kebingungan yang menyertainya.Jawaban:
Global di Python bersifat global untuk satu modul , bukan di semua modul. (Banyak orang bingung dengan ini, karena di, katakanlah, C, global adalah sama di semua file implementasi kecuali Anda secara eksplisit membuatnya
static
.)Ada berbagai cara untuk mengatasinya, bergantung pada kasus penggunaan Anda yang sebenarnya.
Bahkan sebelum menempuh jalur ini, tanyakan pada diri Anda apakah ini benar-benar perlu global. Mungkin Anda benar-benar menginginkan kelas, dengan
f
sebagai metode contoh, daripada hanya fungsi gratis? Kemudian Anda bisa melakukan sesuatu seperti ini:Jika Anda benar-benar menginginkan global, tetapi itu hanya untuk digunakan oleh
module1
, setel di modul itu.Di sisi lain, jika
a
dibagikan oleh banyak modul, letakkan di tempat lain, dan minta semua orang mengimpornya:… Dan, dalam module1.py:
Jangan gunakan
from
impor kecuali variabel dimaksudkan sebagai konstanta.from shared_stuff import a
akan membuata
variabel baru yang diinisialisasi ke apa pun yangshared_stuff.a
dirujuk pada saat impor, dana
variabel baru ini tidak akan terpengaruh oleh tugas keshared_stuff.a
.Atau, dalam kasus yang jarang terjadi di mana Anda benar-benar membutuhkannya untuk benar-benar global di mana-mana, seperti bawaan, tambahkan ke modul bawaan. Detail persisnya berbeda antara Python 2.x dan 3.x. Dalam 3.x, ini berfungsi seperti ini:
sumber
Sebagai solusinya, Anda dapat mempertimbangkan untuk mengatur variabel lingkungan di lapisan luar, seperti ini.
main.py:
mymodule.py:
Sebagai tindakan pencegahan ekstra, tangani kasus ketika MYVAL tidak didefinisikan di dalam modul.
sumber
Sebuah fungsi menggunakan global dari modul yang ditentukan di dalamnya . Sebagai
a = 3
contoh, Anda harus menyetel daripada menyetelmodule1.a = 3
. Jadi, jika Anda ingincur
tersedia sebagai global inutilities_module
, setutilities_module.cur
.Solusi yang lebih baik: jangan gunakan global. Teruskan variabel yang Anda perlukan ke dalam fungsi yang membutuhkannya, atau buat kelas untuk menggabungkan semua data menjadi satu, dan teruskan saat menginisialisasi instance.
sumber
Posting ini hanyalah observasi untuk perilaku Python yang saya temui. Mungkin saran yang Anda baca di atas tidak berhasil untuk Anda jika Anda melakukan hal yang sama seperti yang saya lakukan di bawah.
Yaitu, saya memiliki modul yang berisi variabel global / bersama (seperti yang disarankan di atas):
Lalu saya memiliki modul utama yang mengimpor barang-barang yang dibagikan dengan:
dan beberapa modul lain yang benar-benar mengisi larik ini. Ini disebut oleh modul utama. Saat keluar dari modul lain ini, saya dapat dengan jelas melihat bahwa array sudah terisi. Tapi saat membacanya kembali di modul utama, semuanya kosong. Ini agak aneh bagi saya (yah, saya baru mengenal Python). Namun, ketika saya mengubah cara saya mengimpor sharedstuff.py di modul utama menjadi:
itu berhasil (array diisi).
Katakan saja
sumber
Solusi termudah untuk masalah khusus ini adalah dengan menambahkan fungsi lain di dalam modul yang akan menyimpan kursor dalam variabel global ke modul. Kemudian semua fungsi lainnya dapat menggunakannya juga.
modul 1:
program utama:
sumber
Karena global adalah modul khusus, Anda dapat menambahkan fungsi berikut ke semua modul yang diimpor, lalu menggunakannya untuk:
Maka yang Anda butuhkan untuk menyampaikan global saat ini adalah:
sumber
Karena saya belum melihatnya dalam jawaban di atas, saya pikir saya akan menambahkan solusi sederhana saya, yang hanya menambahkan
global_dict
argumen ke fungsi yang membutuhkan global modul pemanggil, dan kemudian meneruskan dict ke dalam fungsi saat memanggil; misalnya:sumber
Cara OOP untuk melakukan ini adalah membuat modul Anda menjadi kelas, bukan kumpulan metode tak terikat. Kemudian Anda dapat menggunakan
__init__
atau metode penyetel untuk menyetel variabel dari pemanggil untuk digunakan dalam metode modul.sumber