Diberikan kode berikut:
def A() :
b = 1
def B() :
# I can access 'b' from here.
print( b )
# But can i modify 'b' here? 'global' and assignment will not work.
B()
A()
Untuk kode dalam B()
variabel fungsi b
berada di lingkup luar, tetapi tidak dalam lingkup global. Apakah mungkin untuk mengubah b
variabel dari dalam B()
fungsi? Tentunya saya bisa membacanya dari sini dan print()
, tapi bagaimana cara memodifikasinya?
python
python-2.7
grigoryvp.dll
sumber
sumber
b
bisa berubah. Sebuah tugas untukb
menutupi ruang lingkup luar.nonlocal
belum di-backport ke 2.x. Ini adalah bagian intrinsik dari dukungan penutupan.Jawaban:
Python 3.x memiliki
nonlocal
kata kunci . Saya pikir ini melakukan apa yang Anda inginkan, tetapi saya tidak yakin apakah Anda menjalankan python 2 atau 3.Untuk python 2, saya biasanya hanya menggunakan objek yang bisa berubah (seperti daftar, atau dikt), dan mengubah nilainya alih-alih menetapkan ulang.
contoh:
Keluaran:
sumber
class nonlocal: pass
di lingkup luar. Kemudiannonlocal.x
dapat ditugaskan ke dalam lingkup dalam.SyntaxError
. MungkinNonLocal
?Nonlocal
,? :-)Anda dapat menggunakan kelas kosong untuk menampung ruang lingkup sementara. Ini seperti bisa berubah tapi sedikit lebih cantik.
Ini menghasilkan keluaran interaktif berikut:
sumber
Saya sedikit baru mengenal Python, tapi saya sudah membaca sedikit tentang ini. Saya percaya yang terbaik yang akan Anda dapatkan mirip dengan pekerjaan Java, yaitu membungkus variabel luar Anda dalam daftar.
Sunting: Saya kira ini mungkin benar sebelum Python 3. Sepertinya
nonlocal
adalah jawaban Anda.sumber
Tidak, Anda tidak bisa, setidaknya dengan cara ini.
Karena "operasi set" akan membuat nama baru di lingkup saat ini, yang mencakup yang terluar.
sumber
Bagi siapa pun yang melihat hal ini nanti akan menemukan solusi yang lebih aman tetapi lebih berat. Tanpa perlu melewatkan variabel sebagai parameter.
sumber
Jawaban singkat yang hanya akan bekerja secara otomatis
Saya membuat perpustakaan python untuk memecahkan masalah khusus ini. Ini dirilis di bawah ketidakseimbangan jadi gunakan sesuka Anda. Anda dapat menginstalnya dengan
pip install seapie
atau melihat halaman beranda di sini https://github.com/hirsimaki-markus/SEAPIEuser@pc:home$ pip install seapie
keluaran
argumen memiliki arti sebagai berikut:
B()
, 1 berarti orang tuaA()
dan 2 berarti kakek-nenek<module>
alias globalJawaban yang panjang
Ini lebih rumit. Seapie bekerja dengan mengedit bingkai dalam tumpukan panggilan menggunakan api CPython. CPython adalah standar de facto sehingga kebanyakan orang tidak perlu khawatir tentang itu.
Kata-kata ajaib yang kemungkinan besar akan Anda minati jika Anda membaca ini adalah sebagai berikut:
Yang terakhir akan memaksa pembaruan untuk masuk ke lingkup lokal. Namun cakupan lokal dioptimalkan secara berbeda dari cakupan global sehingga pengenalan objek baru memiliki beberapa masalah saat Anda mencoba memanggilnya secara langsung jika tidak diinisialisasi dengan cara apa pun. Saya akan menyalin beberapa cara untuk menghindari masalah ini dari halaman github
Jika Anda merasa bahwa menggunakan
exec()
bukanlah sesuatu yang Anda inginkan, Anda dapat meniru perilaku tersebut dengan memperbarui kamus lokal yang sebenarnya (bukan yang dikembalikan oleh penduduk setempat ()). Saya akan menyalin contoh dari https://faster-cpython.readthedocs.io/mutable.htmlKeluaran:
sumber
Saya tidak berpikir Anda harus melakukan ini. Fungsi yang dapat mengubah hal-hal dalam konteks yang melingkupinya berbahaya, karena konteks tersebut dapat ditulis tanpa sepengetahuan fungsinya.
Anda bisa membuatnya eksplisit, baik dengan membuat B metode publik dan C metode privat di kelas (cara terbaik mungkin); atau dengan menggunakan tipe yang bisa berubah seperti daftar dan meneruskannya secara eksplisit ke C:
sumber
nonlocal
kata kuncinya - tetapi terserah Anda untuk menggunakannya dengan sangat hati-hati.Anda bisa, tetapi Anda harus menggunakan pernyataan global (bukan solusi yang sangat baik seperti biasa saat menggunakan variabel global, tetapi berfungsi):
sumber
Saya tidak tahu apakah ada atribut dari suatu fungsi yang memberikan
__dict__
ruang luar dari fungsi ketika luar angkasa ini bukan ruang global == modul, yang merupakan kasus ketika fungsi tersebut adalah fungsi bersarang, dengan Python 3.Tetapi di Python 2, sejauh yang saya tahu, tidak ada atribut seperti itu.
Jadi satu-satunya kemungkinan untuk melakukan apa yang Anda inginkan adalah:
1) menggunakan objek yang bisa berubah, seperti yang dikatakan oleh orang lain
2)
hasil
.
Tidak a
Solusi Cédric Julien memiliki kelemahan:
hasil
B global setelah eksekusi
A()
telah dimodifikasi dan mungkin tidak diinginkanItulah kasusnya hanya jika ada objek dengan pengenal b di namespace global
sumber