Apakah mungkin untuk memiliki variabel atau metode kelas statis di Python? Sintaks apa yang diperlukan untuk melakukan ini?
Variabel yang dideklarasikan di dalam definisi kelas, tetapi tidak di dalam metode adalah variabel kelas atau statis:
>>> class MyClass:
... i = 3
...
>>> MyClass.i
3
Seperti yang ditunjukkan oleh @ millerdev , ini menciptakan i
variabel level kelas , tetapi ini berbeda dari i
variabel level instance mana pun , sehingga Anda dapat memiliki
>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)
Ini berbeda dari C ++ dan Java, tetapi tidak begitu berbeda dari C #, di mana anggota statis tidak dapat diakses menggunakan referensi ke instance.
Lihat apa yang dikatakan tutorial Python tentang subjek kelas dan objek kelas .
@Steve Johnson telah menjawab mengenai metode statis , juga didokumentasikan dalam "Fungsi Bawaan " di Referensi Pustaka Python .
class C:
@staticmethod
def f(arg1, arg2, ...): ...
@beidy merekomendasikan classmethod s over staticmethod, karena metode ini kemudian menerima tipe class sebagai argumen pertama, tapi saya masih sedikit kabur tentang kelebihan pendekatan ini atas staticmethod. Jika Anda juga, maka itu mungkin tidak masalah.
@classmethod
lebih@staticmethod
AFAIK adalah bahwa Anda selalu mendapatkan nama kelas metode ini dipanggil pada, bahkan jika itu subclass. Metode statis tidak memiliki informasi ini, jadi tidak dapat memanggil metode yang diganti, misalnya.const.py
dengan beberapaPI = 3.14
dan Anda dapat mengimpornya di mana saja.from const import PI
i = 3
ini bukan variabel statis, itu adalah atribut kelas, dan karena ia berbeda dari atribut tingkat instancei
ia tidak berperilaku seperti variabel statis dalam bahasa lain. Lihat jawaban millerdev ini , jawaban Yann ini , dan jawaban saya di bawah ini.i
(variabel statis) akan berada di memori bahkan jika saya membuat ratusan instance dari kelas ini?@ Blair Conrad mengatakan variabel statis dideklarasikan di dalam definisi kelas, tetapi tidak di dalam metode adalah variabel kelas atau "statis":
Ada beberapa gotcha di sini. Melanjutkan dari contoh di atas:
Perhatikan bagaimana variabel instan
t.i
keluar dari sinkronisasi dengan variabel kelas "statis" ketika atributi
disetel langsungt
. Ini karenai
terikat kembali di dalamt
namespace, yang berbeda dariTest
namespace. Jika Anda ingin mengubah nilai variabel "statis", Anda harus mengubahnya dalam ruang lingkup (atau objek) di mana ia awalnya didefinisikan. Saya menaruh "statis" dalam tanda kutip karena Python tidak benar-benar memiliki variabel statis dalam arti bahwa C ++ dan Java lakukan.Meskipun tidak mengatakan sesuatu yang spesifik tentang variabel atau metode statis, tutorial Python memiliki beberapa informasi yang relevan tentang kelas dan objek kelas .
@Steve Johnson juga menjawab mengenai metode statis, juga didokumentasikan dalam "Fungsi Bawaan" di Referensi Pustaka Python.
@beid juga menyebutkan classmethod, yang mirip dengan staticmethod. Argumen pertama classmethod adalah objek kelas. Contoh:
sumber
class Test(object):
,_i = 3
,@property
,def i(self)
,return type(self)._i
,@i.setter
,def i(self,val):
,type(self)._i = val
. Sekarang Anda dapat melakukanx = Test()
,x.i = 12
,assert x.i == Test.i
.Metode Statis dan Kelas
Seperti yang dicatat oleh jawaban lain, metode statis dan kelas mudah dilakukan dengan menggunakan dekorator bawaan:
Seperti biasa, argumen pertama
MyMethod()
terikat ke objek instance kelas. Sebaliknya, argumen pertama untukMyClassMethod()
yang terikat ke objek kelas itu sendiri (misalnya, dalam kasus ini,Test
). SebabMyStaticMethod()
, tidak ada argumen yang terikat, dan memiliki argumen sama sekali adalah opsional."Variabel Statis"
Namun, menerapkan "variabel statis" (yah, variabel statis yang dapat berubah , bagaimanapun, jika itu bukan kontradiksi dalam istilah ...) tidak semudah itu. Seperti yang ditunjukkan millerdev dalam jawabannya , masalahnya adalah atribut kelas Python tidak benar-benar "variabel statis". Mempertimbangkan:
Ini karena baris
x.i = 12
telah menambahkan atribut instance barui
untukx
bukannya mengubah nilaiTest
kelasi
atribut .Perilaku variabel statis parsial yang diharapkan, yaitu, sinkronisasi atribut antara beberapa instance (tetapi tidak dengan kelas itu sendiri; lihat "gotcha" di bawah), dapat dicapai dengan mengubah atribut kelas menjadi properti:
Sekarang Anda bisa melakukannya:
Variabel statis sekarang akan tetap sinkron antara semua instance kelas .
(CATATAN: Yaitu, kecuali instance kelas memutuskan untuk mendefinisikan versinya sendiri
_i
! Tetapi jika seseorang memutuskan untuk melakukan ITU, mereka layak mendapatkan apa yang mereka dapatkan, bukankah begitu ???)Perhatikan bahwa secara teknis,
i
masih bukan 'variabel statis' sama sekali; itu adalahproperty
, yang merupakan tipe deskriptor khusus. Namun demikianproperty
perilaku sekarang setara dengan variabel statis (dapat diubah) disinkronkan di semua instance kelas."Variabel Statis" yang Tidak Berubah
Untuk perilaku variabel statis yang tidak dapat diubah, cukup abaikan
property
setter:Sekarang mencoba untuk mengatur
i
atribut instance akan mengembalikanAttributeError
:Satu Gotcha menjadi Sadar
Perhatikan bahwa metode di atas hanya berfungsi dengan instance kelas Anda - mereka tidak akan berfungsi saat menggunakan kelas itu sendiri . Jadi misalnya:
Garis
assert Test.i == x.i
menghasilkan kesalahan, karenai
atributTest
danx
dua objek berbeda.Banyak orang akan menganggap ini mengejutkan. Namun, seharusnya tidak demikian. Jika kita kembali dan memeriksa
Test
definisi kelas kita (versi kedua), kita perhatikan baris ini:Jelas, anggota
i
dariTest
keharusan menjadiproperty
objek, yang merupakan jenis objek kembali dariproperty
fungsi.Jika Anda menemukan hal di atas membingungkan, kemungkinan besar Anda masih memikirkannya dari perspektif bahasa lain (mis. Java atau c ++). Anda harus belajar
property
objek tersebut, tentang urutan pengembalian atribut Python, protokol deskriptor, dan urutan resolusi metode (MRO).Saya menyajikan solusi untuk 'gotcha' di atas di bawah ini; namun saya akan menyarankan - sangat - bahwa Anda tidak mencoba melakukan sesuatu seperti berikut sampai - minimal - Anda benar-benar mengerti mengapa
assert Test.i = x.i
menyebabkan kesalahan.Variabel Statis NYATA, AKTUAL -
Test.i == x.i
Saya menyajikan solusi (Python 3) di bawah ini hanya untuk tujuan informasi. Saya tidak mendukungnya sebagai "solusi yang baik". Saya ragu apakah meniru perilaku variabel statis bahasa lain di Python benar-benar diperlukan. Namun, terlepas dari apakah itu benar-benar berguna, di bawah ini akan membantu pemahaman lebih lanjut tentang cara kerja Python.
UPDATE: upaya ini sangat mengerikan ; jika Anda bersikeras melakukan sesuatu seperti ini (petunjuk: tolong jangan; Python adalah bahasa yang sangat elegan dan menganggapnya seperti bahasa lain tidak perlu), gunakan kode dalam jawaban Ethan Furman sebagai gantinya.
Meniru perilaku variabel statis dari bahasa lain menggunakan metaclass
Metaclass adalah kelas suatu kelas. Metaclass default untuk semua kelas di Python (yaitu, kelas "gaya baru" memposting Python 2.3 saya percaya) adalah
type
. Sebagai contoh:Namun, Anda dapat mendefinisikan metaclass Anda sendiri seperti ini:
Dan terapkan ke kelas Anda sendiri seperti ini (hanya Python 3):
Di bawah ini adalah metaclass yang saya buat yang mencoba meniru perilaku "variabel statis" dari bahasa lain. Ini pada dasarnya bekerja dengan mengganti pengambil default, setter, dan deleter dengan versi yang memeriksa untuk melihat apakah atribut yang diminta adalah "variabel statis".
Katalog "variabel statis" disimpan dalam
StaticVarMeta.statics
atribut. Semua permintaan atribut pada awalnya dicoba untuk diselesaikan menggunakan urutan resolusi pengganti. Saya telah menjuluki ini "urutan resolusi statis", atau "SRO". Ini dilakukan dengan mencari atribut yang diminta dalam set "variabel statis" untuk kelas tertentu (atau kelas induknya). Jika atribut tidak muncul di "SRO", kelas akan kembali pada atribut default dapatkan / atur / hapus perilaku (yaitu, "MRO").sumber
Test
(sebelum menggunakannya untuk instance instantiating) sebagai berada di domain meta-programming? Misalnya, Anda mengubah perilaku kelas dengan melakukanTest.i = 0
(di sini Anda hanya menghancurkan objek properti sepenuhnya). Saya kira "mekanisme properti" hanya menendang pada akses-properti pada instance kelas (kecuali jika Anda mengubah perilaku mendasar menggunakan meta-class sebagai perantara, mungkin). Btw, tolong selesaikan jawaban ini :-)Anda juga dapat menambahkan variabel kelas ke kelas on the fly
Dan instance kelas dapat mengubah variabel kelas
sumber
Secara pribadi saya akan menggunakan classmethod setiap kali saya membutuhkan metode statis. Terutama karena saya mendapatkan kelas sebagai argumen.
atau menggunakan dekorator
Untuk properti statis .. Saatnya Anda mencari beberapa definisi python .. variabel selalu dapat berubah. Ada dua jenis dari mereka bisa berubah dan tidak berubah .. Juga, ada atribut kelas dan atribut contoh .. Tidak ada yang benar-benar seperti atribut statis dalam arti java & c ++
Mengapa menggunakan metode statis dalam arti pythonic, jika tidak memiliki hubungan apa pun dengan kelas! Jika saya jadi Anda, saya akan menggunakan metode classmet atau mendefinisikan metode independen dari kelas.
sumber
Satu hal khusus yang perlu diperhatikan tentang properti statis & properti instan, ditunjukkan dalam contoh di bawah ini:
Ini berarti sebelum menetapkan nilai ke properti instance, jika kami mencoba mengakses properti melalui instance, nilai statis digunakan. Setiap properti yang dideklarasikan dalam kelas python selalu memiliki slot statis di memori .
sumber
Metode statis dalam python disebut classmethod s. Lihatlah kode berikut
Perhatikan bahwa ketika kita memanggil metode myInstanceMethod , kita mendapatkan kesalahan. Ini karena membutuhkan metode yang dipanggil pada turunan dari kelas ini. Metode myStaticMethod ditetapkan sebagai metode kelas menggunakan dekorator @classmethod .
Hanya untuk iseng dan cekikikan, kita bisa memanggil myInstanceMethod di kelas dengan mengirimkan instance kelas, seperti:
sumber
@staticmethod
;@classmethod
adalah (jelas) untuk metode kelas (yang terutama dimaksudkan untuk digunakan sebagai konstruktor alternatif, tetapi dapat berfungsi dalam keadaan darurat sebagai metode statis yang kebetulan menerima referensi ke kelas yang mereka dipanggil melalui).Ketika mendefinisikan beberapa variabel anggota di luar metode anggota, variabel dapat berupa statis atau non-statis tergantung pada bagaimana variabel tersebut diekspresikan.
Sebagai contoh:
Hasilnya
sumber
Dimungkinkan untuk memiliki
static
variabel kelas, tetapi mungkin tidak sepadan dengan usaha.Berikut adalah bukti konsep yang ditulis dalam Python 3 - jika ada detail yang salah, kode dapat diubah agar sesuai dengan apa pun yang Anda maksud dengan
static variable
:dan digunakan:
dan beberapa tes:
sumber
Anda juga bisa memaksakan kelas menjadi statis menggunakan metaclass.
Kemudian setiap kali secara tidak sengaja Anda mencoba menginisialisasi MyClass Anda akan mendapatkan StaticClassError.
sumber
__new__
tuanya ...Satu hal yang sangat menarik tentang pencarian atribut Python adalah ia dapat digunakan untuk membuat " variabel virtual ":
Biasanya tidak ada tugas untuk ini setelah dibuat. Perhatikan bahwa pencarian menggunakan
self
karena, meskipunlabel
statis dalam arti tidak dikaitkan dengan contoh tertentu , nilainya masih tergantung pada instance (kelas dari).sumber
Sehubungan dengan jawaban ini , untuk variabel statis konstan , Anda dapat menggunakan deskriptor. Ini sebuah contoh:
yang menghasilkan ...
Anda selalu dapat mengajukan pengecualian jika mengabaikan nilai pengaturan (di
pass
atas) dengan diam-diam bukan pilihan Anda. Jika Anda mencari C ++, variabel kelas statis gaya Java:Lihatlah jawaban ini dan dokumen resmi HOWTO untuk informasi lebih lanjut tentang deskriptor.
sumber
@property
, yang sama dengan menggunakan deskriptor, tetapi kode ini jauh lebih sedikit.Benar-benar Ya, Python dengan sendirinya tidak memiliki anggota data statis secara eksplisit, tetapi Kami dapat melakukannya dengan melakukannya
keluaran
penjelasan
sumber
Ya, sangat mungkin untuk menulis variabel dan metode statis dengan python.
Variabel Statis: Variabel yang dideklarasikan di tingkat kelas disebut variabel statis yang dapat diakses langsung menggunakan nama kelas.
Variabel Instance: Variabel yang terkait dan diakses oleh instance dari kelas adalah variabel instan.
Metode Statis: Mirip dengan variabel, metode statis dapat diakses secara langsung menggunakan Nama kelas. Tidak perlu membuat instance.
Namun perlu diingat, metode statis tidak dapat memanggil metode non-statis dengan python.
sumber
Untuk menghindari kemungkinan kebingungan, saya ingin membandingkan variabel statis dan objek yang tidak dapat diubah.
Beberapa tipe objek primitif seperti integer, float, string, dan touple tidak berubah dalam Python. Ini berarti bahwa objek yang dirujuk oleh nama yang diberikan tidak dapat berubah jika itu salah satu dari jenis objek yang disebutkan di atas. Nama dapat dipindahkan ke objek yang berbeda, tetapi objek itu sendiri tidak dapat diubah.
Membuat variabel statis mengambil langkah ini lebih jauh dengan melarang nama variabel untuk menunjuk ke objek apa pun kecuali yang saat ini ditunjuknya. (Catatan: ini adalah konsep perangkat lunak umum dan tidak khusus untuk Python; silakan lihat posting orang lain untuk informasi tentang penerapan statika dalam Python).
sumber
Cara terbaik yang saya temukan adalah menggunakan kelas lain. Anda dapat membuat objek dan kemudian menggunakannya pada objek lain.
Dengan contoh di atas, saya membuat kelas bernama
staticFlag
.Kelas ini harus menyajikan var statis
__success
(Private Static Var).tryIt
kelas mewakili kelas reguler yang perlu kita gunakan.Sekarang saya membuat objek untuk satu flag (
staticFlag
). Bendera ini akan dikirim sebagai referensi ke semua objek biasa.Semua objek ini sedang ditambahkan ke daftar
tryArr
.Hasil Skrip Ini:
sumber
Variabel statis di Kelas pabrik python3.6
Bagi siapa pun yang menggunakan pabrik kelas dengan python3.6 dan lebih tinggi gunakan
nonlocal
kata kunci untuk menambahkannya ke lingkup / konteks kelas yang sedang dibuat seperti:sumber
hasattr(SomeClass, 'x')
adalahFalse
. saya ragu ini yang orang maksud dengan variabel statis sama sekali.some_var
berubah, dan didefinisikan secara statis, atau bukan? Apa yang harus dilakukan oleh akses pengambil luar dengan variabel yang statis atau tidak? Saya punya banyak pertanyaan sekarang. akan senang mendengar beberapa jawaban ketika Anda mendapatkan waktu.some_var
atas bukan anggota kelas sama sekali. Dalam Python semua anggota kelas dapat diakses dari luar kelas.nonlocal
keywoard "benjolan" ruang lingkup variabel. Lingkup definisi badan kelas tidak tergantung pada ruang lingkup yang ditemukannya sendiri ketika Anda mengatakannonlocal some_var
, itu hanya membuat referensi nama non-lokal (baca: BUKAN dalam lingkup definisi kelas) ke objek bernama lain. Oleh karena itu tidak melekat pada definisi kelas karena tidak ada dalam ruang lingkup kelas.Jadi ini mungkin hack, tapi saya sudah menggunakan
eval(str)
untuk mendapatkan objek statis, semacam kontradiksi, dengan python 3.Ada file Records.py yang hanya memiliki
class
objek yang ditentukan dengan metode statis dan konstruktor yang menyimpan beberapa argumen. Kemudian dari file .py lain Iimport Records
tetapi saya perlu secara dinamis memilih setiap objek dan kemudian instantiate sesuai permintaan sesuai dengan jenis data yang sedang dibaca.Jadi di mana
object_name = 'RecordOne'
atau nama kelas, saya panggilcur_type = eval(object_name)
dan kemudian untuk instantiate Anda lakukancur_inst = cur_type(args)
Namun sebelum Anda instantiate Anda dapat memanggil metode statis daricur_type.getName()
misalnya, jenis seperti implementasi kelas dasar abstrak atau apa pun tujuannya. Namun di backend, mungkin instantiated dengan python dan tidak benar-benar statis, karena eval mengembalikan objek .... yang pasti instantiated .... yang memberikan perilaku seperti statis.sumber
Anda dapat menggunakan daftar atau kamus untuk mendapatkan "perilaku statis" di antara instance.
sumber
Jika Anda mencoba untuk membagikan variabel statis untuk, dengan contoh, meningkatkannya di contoh lain, sesuatu seperti skrip ini berfungsi dengan baik:
sumber