Deklarasi Variabel Python

87

Belajar Python , dan memiliki beberapa keraguan mendasar.

1. Saya telah melihat deklarasi variabel (path here) sebagai

class writer:
    path = ""

terkadang, tidak ada deklarasi eksplisit tetapi menginisialisasi melalui __init__.

def __init__(self, name):
    self.name = name

Saya memahami tujuan dari __init__, tetapi disarankan untuk mendeklarasikan variabel di fungsi lain.

2. Bagaimana cara membuat variabel untuk menahan jenis kustom?

class writer:
    path = "" # string value
    customObj = ??
bsr
sumber
12
Dan, mengenai pertanyaan ke-2: dalam Python, variabel tidak memiliki tipe: nilai do. Jadi variabel apa pun dapat menampung objek khusus Anda.
jpaugh
4
Ini akan membantu jika Anda berhenti memikirkan nama / idendifier sebagai variabel . Mereka adalah referensi ke objek
John La Rooy
2
@gnibbler Atau nama untuk mereka ...
detly
1
@ benar-benar, saya pikir nama adalah pilihan yang buruk. Benda-benda biasanya hanya memiliki satu nama sedangkan sebuah objek mungkin memiliki banyak referensi
John La Rooy
2
@JohnClements, tetapi python tidak berfungsi seperti matematika. Jika Anda ingin memahami python Anda perlu tahu bahwa objek dengan __name__atribut memiliki "nama". Tidak semua objek memiliki __name__atribut, tetapi Anda masih dapat memiliki referensi ke sana. Jika kita mulai menyebut "referensi" sebagai "nama", kita melakukan tindakan merugikan bagi pemula.
John La Rooy

Jawaban:

205

Oke, hal pertama yang pertama.

Tidak ada yang namanya "deklarasi variabel" atau "inisialisasi variabel" dalam Python.

Ada yang kita sebut sebagai "penugasan", tapi mungkin sebaiknya kita sebut saja "penamaan".

Penugasan berarti "nama di sisi kiri ini sekarang mengacu pada hasil evaluasi sisi kanan, terlepas dari apa yang dirujuk sebelumnya (jika ada)".

foo = 'bar' # the name 'foo' is now a name for the string 'bar'
foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar',
# and starts being a name for the integer 6, resulting from the multiplication

Dengan demikian, nama Python (istilah yang lebih baik daripada "variabel", bisa dibilang) tidak memiliki tipe terkait; nilai-nilai itu. Anda dapat menerapkan kembali nama yang sama untuk apa pun apa pun tipenya, tetapi benda tersebut masih memiliki perilaku yang bergantung pada tipenya. Nama hanyalah cara untuk merujuk ke nilai (objek). Ini menjawab pertanyaan kedua Anda: Anda tidak membuat variabel untuk menampung jenis kustom. Anda tidak membuat variabel untuk menampung tipe tertentu. Anda sama sekali tidak "membuat" variabel. Anda memberi nama pada objek.

Poin kedua: Python mengikuti aturan yang sangat sederhana dalam hal kelas, yang sebenarnya jauh lebih konsisten daripada bahasa seperti Java, C ++ dan C #: semua yang dideklarasikan di dalam classblok adalah bagian dari kelas . Jadi, fungsi ( def) yang ditulis di sini adalah metode, yaitu bagian dari objek kelas (tidak disimpan pada basis per-instance), seperti di Java, C ++ dan C #; tetapi nama lain di sini juga merupakan bagian dari kelas. Sekali lagi, nama hanyalah nama, dan mereka tidak memiliki tipe terkait, dan fungsi adalah objek juga dalam Python. Jadi:

class Example:
    data = 42
    def method(self): pass

Kelas juga merupakan objek , dengan Python.

Jadi sekarang kita telah membuat sebuah objek bernama Example, yang mewakili kelas dari semua benda yang Examples. Objek ini memiliki dua atribut yang disediakan pengguna (Dalam C ++, "anggota"; di C #, "bidang atau properti atau metode"; di Java, "bidang atau metode"). Salah satunya diberi nama data, dan ini menyimpan nilai integer 42. Yang lainnya diberi nama method, dan itu menyimpan objek fungsi. (Ada beberapa atribut lagi yang ditambahkan Python secara otomatis.)

Atribut ini masih belum menjadi bagian dari objek. Pada dasarnya, sebuah objek hanyalah sekumpulan lebih banyak nama (nama atribut), sampai Anda turun ke hal-hal yang tidak dapat dibagi lagi. Dengan demikian, nilai dapat dibagikan antara instance kelas yang berbeda, atau bahkan antara objek dari kelas yang berbeda, jika Anda sengaja menyiapkannya.

Mari buat sebuah contoh:

x = Example()

Sekarang kita memiliki objek terpisah bernama x, yang merupakan turunan dari Example. The datadan methodtidak benar-benar bagian dari objek, tapi kita masih bisa melihat mereka melalui xkarena beberapa keajaiban yang Python dilakukan di belakang layar. Saat kita mencari method, khususnya, kita akan mendapatkan "metode terikat" (saat kita memanggilnya, xakan diteruskan secara otomatis sebagai selfparameter, yang tidak dapat terjadi jika kita mencari Example.methodsecara langsung).

Apa yang terjadi saat kami mencoba menggunakan x.data?

Saat kami memeriksanya, itu mencari di objek terlebih dahulu. Jika tidak ditemukan di objek, Python mencari di kelas.

Namun, saat kita menugaskan x.data , Python akan membuat atribut pada objek tersebut. Ini tidak akan menggantikan atribut kelas '.

Ini memungkinkan kita melakukan inisialisasi objek . Python akan secara otomatis memanggil metode kelas __init__pada instance baru saat dibuat, jika ada. Dalam metode ini, kita cukup menetapkan ke atribut untuk menetapkan nilai awal atribut itu pada setiap objek:

class Example:
    name = "Ignored"
    def __init__(self, name):
        self.name = name
    # rest as before

Sekarang kita harus menentukan namekapan kita membuat Example, dan setiap instance memiliki sendiri name. Python akan mengabaikan atribut class Example.namesetiap kali kita mencari .namedari sebuah instance, karena atribut dari instance tersebut akan ditemukan terlebih dahulu.

Satu peringatan terakhir: modifikasi (mutasi) dan penugasan adalah hal yang berbeda!

Di Python, string tidak bisa diubah. Mereka tidak dapat diubah. Saat kamu melakukan:

a = 'hi '
b = a
a += 'mom'

Anda tidak mengubah string 'hi' yang asli. Itu tidak mungkin dengan Python. Sebaliknya, Anda membuat string baru'hi mom' , dan menyebabkan aberhenti menjadi nama untuk 'hi ', dan mulai menjadi nama untuk 'hi mom'. Kita buat bnama untuk 'hi 'juga, dan setelah di aplikasikan ulang a, bmasih ada nama untuk 'hi ', karena 'hi 'masih ada dan belum diubah.

Tetapi daftar dapat diubah:

a = [1, 2, 3]
b = a
a += [4]

Sekarang b[1, 2, 3, 4] juga, karena kita membuat bnama untuk benda yang sama a, lalu kita ubah benda itu. Kami tidak membuat daftar baru untuk anama, karena Python memperlakukan +=daftar secara berbeda.

Ini penting untuk objek karena jika Anda memiliki daftar sebagai atribut kelas, dan menggunakan sebuah instance untuk mengubah daftar, maka perubahan itu akan "terlihat" di semua contoh lainnya. Ini karena (a) data sebenarnya adalah bagian dari objek kelas, dan bukan objek instance apa pun; (b) karena Anda mengubah daftar dan tidak melakukan tugas sederhana, Anda tidak membuat atribut instance baru yang menyembunyikan atribut kelas.

Karl Knechtel
sumber
12
Inilah mengapa kami menyebutnya 'pengidentifikasi' . :-)
Martijn Pieters
@Karl_Knechtel dalam contoh string Anda pada akhirnya, apa yang terjadi pada 'hai' jika kita tidak pernah menamainya sebagai 'b'? Apakah ini kebocoran memori?
heretoinfinity
2
@heretoinfinity: tidak; Python menggunakan pengumpulan sampah untuk membebaskan objek yang tidak dapat dijangkau
John Clements
Deklarasi variabel dijelaskan dengan baik dalam video ini: youtube.com/watch?v=ao2N37E-D9s .
Ishaq Khan
lihat video ini untuk jawabannya youtube.com/…
Thao N
23

Ini mungkin terlambat 6 tahun, tetapi dengan Python 3.5 dan yang lebih baru, Anda mendeklarasikan tipe variabel seperti ini:

variable_name: type_name

atau ini:

variable_name # type: shinyType

Jadi dalam kasus Anda (jika Anda memiliki CustomObjectkelas yang ditentukan), Anda dapat melakukan:

customObj: CustomObject

Lihat ini atau itu untuk info lebih lanjut.

O. Aroesti
sumber
Itu bukan deklarasi dalam pengertian tradisional, meskipun, ini adalah petunjuk, yang mungkin ditunjukkan oleh pemeriksa tipe statis dan IDE, tetapi akan tetap berjalan dan gagal.
PhilHibbs
@PhilHibbs Itu tidak gagal. Apa yang Anda maksud dengan "gagal"?
O. Aroesti
Yang saya maksud adalah jika Anda melakukannya a: intdan kemudian melakukannya a='hello, world!'tidak akan gagal, jadi itu tidak menyatakan a menjadi int dan hanya pernah menjadi int. Aku seharusnya mengatakan "itu tidak akan gagal", salahku. Jika Anda melakukannya a: int, a='hello, world!', a=a+1maka yang harus gagal di kompilasi dalam bahasa statis diketik.
PhilHibbs
22

Tidak perlu mendeklarasikan variabel baru dengan Python. Jika kita berbicara tentang variabel dalam fungsi atau modul, tidak diperlukan deklarasi. Hanya memberikan nilai pada nama di mana Anda membutuhkannya: mymagic = "Magic". Variabel dalam Python dapat menyimpan nilai jenis apa pun, dan Anda tidak dapat membatasinya.

Pertanyaan Anda secara khusus menanyakan tentang kelas, objek dan variabel instan. Cara idiomatis untuk membuat variabel instance ada di __init__metode dan tidak di tempat lain - meskipun Anda dapat membuat variabel instance baru dengan metode lain, atau bahkan dalam kode yang tidak terkait, itu hanya ide yang buruk. Ini akan membuat kode Anda sulit untuk dipikirkan atau dipertahankan.

Jadi contohnya:

class Thing(object):

    def __init__(self, magic):
        self.magic = magic

Mudah. Sekarang instance kelas ini memiliki magicatribut:

thingo = Thing("More magic")
# thingo.magic is now "More magic"

Membuat variabel di namespace kelas itu sendiri mengarah ke perilaku yang berbeda sama sekali. Ini secara fungsional berbeda, dan Anda hanya boleh melakukannya jika Anda memiliki alasan tertentu. Sebagai contoh:

class Thing(object):

    magic = "Magic"

    def __init__(self):
        pass

Sekarang coba:

thingo = Thing()
Thing.magic = 1
# thingo.magic is now 1

Atau:

class Thing(object):

    magic = ["More", "magic"]

    def __init__(self):
        pass

thing1 = Thing()
thing2 = Thing()
thing1.magic.append("here")
# thing1.magic AND thing2.magic is now ["More", "magic", "here"]

Ini karena namespace dari kelas itu sendiri berbeda dengan namespace dari objek yang dibuat darinya. Saya akan menyerahkannya kepada Anda untuk menelitinya lebih banyak.

Pesan yang dibawa pulang adalah bahwa idiomatik Python adalah untuk (a) menginisialisasi atribut objek dalam __init__metode Anda , dan (b) mendokumentasikan perilaku kelas Anda sesuai kebutuhan. Anda tidak perlu bersusah payah membuat dokumentasi tingkat Sphinx yang lengkap untuk semua yang pernah Anda tulis, tetapi setidaknya beberapa komentar tentang detail apa pun yang mungkin Anda atau orang lain perlukan untuk mengambilnya.

detly
sumber
12

Untuk tujuan pelingkupan, saya menggunakan:

custom_object = None
redhot
sumber
1

Variabel memiliki ruang lingkup, jadi ya itu tepat untuk memiliki variabel yang spesifik untuk fungsi Anda. Anda tidak harus selalu eksplisit tentang definisi mereka; biasanya Anda bisa menggunakannya. Hanya jika Anda ingin melakukan sesuatu yang spesifik untuk jenis variabel, seperti menambahkan untuk daftar, Anda perlu mendefinisikannya sebelum Anda mulai menggunakannya. Contoh tipikal ini.

list = []
for i in stuff:
  list.append(i)

Ngomong-ngomong, ini sebenarnya bukan cara yang baik untuk menyiapkan daftar. Akan lebih baik untuk mengatakan:

list = [i for i in stuff] # list comprehension

... tapi saya ngelantur.

Pertanyaan Anda yang lain. Objek khusus haruslah kelas itu sendiri.

class CustomObject(): # always capitalize the class name...this is not syntax, just style.
  pass
customObj = CustomObject()
ChipHanya
sumber