Untuk semua penghuni yang memiliki rasa deja vu: Saya diminta untuk menulis posting ini dengan artikel "Pengantar Python" dan mengomentarinya. Sayangnya, kualitas "pengantar" ini ahem ... jangan bicara tentang hal-hal yang menyedihkan. Tapi itu lebih menyedihkan untuk mengamati pertengkaran dalam komentar dari kategori "C ++ lebih cepat dari Python", "Karat bahkan lebih cepat dari C ++", "Python tidak diperlukan", dll. Sungguh menakjubkan bahwa mereka tidak ingat Ruby!
Seperti yang dikatakan Bjarn Stroustrup,
"Hanya ada dua jenis bahasa pemrograman: yang orang bersumpah sepanjang waktu, dan yang tidak ada yang menggunakan."
Selamat datang di semua orang yang ingin berkenalan dengan Python tanpa jatuh dalam kutukan kotor!
Pagi di pegunungan Kaukasus Timur ditandai dengan tangisan. Dua pria muda duduk di atas batu besar dan dengan penuh semangat membahas sesuatu, dengan aktif menggerakkan tangan. Semenit kemudian, mereka mulai saling mendorong, dan kemudian bergulat dan jatuh dari batu ke (ternyata) semak jelatang. Rupanya semak ini tumbuh di sana karena suatu alasan, - ia segera menenangkan para petarung dan membawa gencatan senjata ke perselisihan mereka yang tak terpadamkan. Seperti yang mungkin Anda tebak, saya adalah salah satu pendebat, yang lain adalah teman baik saya (halo, Quaker_t!), Tapi topik pembicaraan kecil kami adalah Visual Basic vs. Delphi !
Apakah Anda mengenali diri sendiri? Terkadang kita mengubah bahasa pemrograman favorit kita menjadi sekte dan siap untuk mempertahankannya sampai akhir! Tetapi tahun demi tahun berlalu dan saatnya datang ketika "A vs B" dari subjek pertengkaran berkembang menjadi "Saya lebih nyaman bekerja dengan A, tetapi jika perlu saya akan belajar cara bekerja dengan B, C, D, E dan secara umum, dengan apa pun ." Itu hanya ketika kita menemukan bahasa pemrograman baru, kebiasaan lama dan budaya mungkin tidak membiarkan kita pergi untuk waktu yang lama.
Saya ingin memperkenalkan Anda ke Python dan membantu mentransfer pengalaman Anda ke arah yang baru. Seperti halnya teknologi apa pun, ia memiliki kekuatan dan kelemahannya sendiri. Python, seperti C ++, Rust, Ruby, JS, dan yang lainnya, adalah alat. Instruksi terlampir pada instrumen apa pun dan Anda harus belajar menggunakan instrumen apa pun dengan benar .
"Penulis, tidak punya otak, apakah Anda akan memperkenalkan kami ke Python?" Mari berkenalan!
Python adalah bahasa pemrograman tujuan umum tingkat tinggi yang dinamis. Python adalah bahasa pemrograman yang matang dengan ekosistem dan tradisi yang kaya. Meskipun bahasa ini dirilis pada tahun 1991, penampilannya yang modern mulai terbentuk pada awal tahun 2000-an. Python adalah bahasa yang dibebankan , di perpustakaan standarnya ada solusi untuk banyak kesempatan. Python adalah bahasa pemrograman yang populer : Dropbox, Reddit, Instagram, Disqus, YouTube, Netflix, sial, bahkan Eve Online dan banyak lainnya aktif menggunakan Python.
Apa alasan popularitas ini? Dengan izin Anda, saya akan menyajikan versi saya sendiri.
Python adalah bahasa pemrograman yang sederhana . Pengetikan dinamis. Pengumpul sampah. Fungsi urutan lebih tinggi. Sintaks sederhana untuk bekerja dengan kamus, set, tupel dan daftar (termasuk untuk mendapatkan irisan). Python sangat bagus untuk pemula: memungkinkan untuk memulai dengan pemrograman prosedural, secara perlahan beralih ke OOP dan merasakan pemrograman fungsional. Tapi kesederhanaan ini seperti ujung gunung es. Layak menyelam ke kedalaman ketika Anda menemukan filosofi Python - Zen Of Python . Menyelam lebih jauh - dan Anda menemukan diri Anda dalam serangkaian aturan yang jelas untuk desain kode - Panduan Gaya untuk Kode Python . Menyelam, programmer secara bertahap menggali ke dalam konsep "cara Python" atau "Pythonic". Pada tahap pembelajaran bahasa yang menakjubkan ini, Anda mulai memahami mengapa program Python yang baik ditulis dengan cara ini dan bukan sebaliknya. Mengapa bahasa telah berevolusi ke arah ini, dan tidak ke yang lain. Python tidak berhasil dalam kecepatan. Tetapi ia berhasil dalam aspek terpenting dari pekerjaan kami - keterbacaan. "Tulis kode untuk orang, bukan untuk mobil" - ini adalah dasar dari dasar-dasar Python.
Kode Python yang bagus terlihat indah. Dan untuk menulis kode yang indah - pekerjaan apa yang tidak menyenangkan?
Kiat 0: Sebelum membaca lebih lanjut, silakan melihat sudut Zen Python . Bahasa ini didasarkan pada postulat-postulat ini dan komunikasi kami akan jauh lebih menyenangkan jika Anda akan terbiasa dengannya.
Pria pintar apa yang muncul dengan lekukan?
Kejutan pertama bagi mereka yang belum pernah melihat kode dengan Python adalah lekukan tubuh instruksi:
def main(): ins = input('Please say something') for w in ins.split(' '): if w == 'hello': print('world!')
Saya ingat malam hari di asrama Politeknik St. Petersburg ketika tetangga saya, VlK , dengan mata yang terbakar mengatakan kepada saya bahwa ia telah menggali sesuatu yang baru dengan Python. "Badan lekukan? Serius?" - adalah reaksi saya. Memang, bagi seseorang yang beralih dari Visual Basic ( if ... end if
) ke C # (kurung kurawal) melalui C, C ++ dan Java, pendekatan ini tampaknya, secara halus, aneh. "Apakah Anda memformat kode dengan lekukan?" Tanya VlK . Tentu saja saya memformatnya. Lebih tepatnya, spiral Studio Visual melakukannya untuk saya. Dia melakukannya dengan sangat baik. Saya tidak pernah berpikir tentang pemformatan dan indentasi - mereka muncul dalam kode sendiri dan tampaknya menjadi sesuatu yang biasa dan akrab. Tapi tidak ada yang disembunyikan - kode selalu diformat dengan lekukan. "Lalu mengapa kamu perlu kawat gigi keriting jika tubuh instruksi dalam hal apapun bergeser ke kanan?"
Malam itu saya duduk dengan Python. Melihat ke belakang, saya dapat mengatakan dengan pasti apa yang sebenarnya membantu untuk dengan cepat menyerap materi baru. Itu adalah editor kode. Di bawah pengaruh VlK yang sama, tak lama sebelum peristiwa yang dijelaskan di atas, saya beralih dari Windows ke Ubuntu dan Emacs sebagai editor (di halaman 2007, ke PyCharm, Atom, VS Code, dan lainnya - bertahun-tahun lagi). "Yah, sekarang Emacs akan PR ..." - katamu. Hanya sedikit :) Secara tradisional, tombol <tab>
di Emacs tidak menambahkan tab, tetapi berfungsi untuk menyelaraskan baris sesuai dengan aturan mode ini. Ditekan <tab>
- dan baris kode digeser ke posisi yang sesuai berikutnya:

Dengan cara ini Anda tidak perlu memikirkan apakah Anda menyelaraskan kode dengan benar.
Kiat 1: Saat Anda mengenal Python, gunakan editor yang menangani lekukan.
Apakah Anda tahu apa efek samping dari semua aib ini? Programmer mencoba menghindari konstruksi yang panjang. Begitu ukuran fungsi melampaui batas vertikal layar, menjadi lebih sulit untuk membedakan mana desain blok kode yang diberikan milik. Dan semakin banyak investasi, semakin sulit. Akibatnya, Anda mencoba menulis sesingkat mungkin, memecah tubuh panjang fungsi, loop, transisi kondisional, dll.
Oh well, mengetik dinamis Anda
O, diskusi ini ada hampir selama konsep "pemrograman" ada! Pengetikan dinamis tidak buruk atau baik. Pengetikan dinamis juga merupakan alat kami. Dalam Python, pengetikan dinamis memberikan kebebasan tindakan yang luar biasa. Dan di mana ada kebebasan yang lebih besar untuk bertindak - lebih mungkin untuk menembak diri sendiri di kaki.
Perlu diklarifikasi bahwa mengetikkan Python ketat dan menambahkan angka ke string tidak berfungsi:
1 + '1' >>> TypeError: unsupported operand type(s) for +: 'int' and 'str'
Python juga memeriksa tanda tangan dari fungsi ketika dipanggil dan akan melempar pengecualian jika tanda tangan panggilan tidak benar:
def sum(x, y): return x + y sum(10, 20, 30) >>> TypeError: sum() takes 2 positional arguments but 3 were given
Tetapi ketika memuat skrip, Python tidak akan memberi tahu Anda bahwa fungsi tersebut mengharapkan angka dan bukan string yang Anda masukkan ke dalamnya. Dan Anda hanya mempelajarinya saat runtime:
def sum(x, y): return x + y sum(10, '10') >>> TypeError: can only concatenate str (not "int") to str
Semakin kuat tantangan untuk programmer, terutama saat menulis proyek besar . Python modern telah menjawab tantangan ini dengan mesin annotation dan tipe library, dan komunitas telah mengembangkan program yang melakukan pengecekan tipe statis . Akibatnya, pemrogram mempelajari tentang kesalahan seperti itu sebelum menjalankan program:
Python tidak mementingkan anotasi, meskipun menyimpannya dalam atribut __annotations__
. Satu-satunya syarat adalah bahwa anotasi harus merupakan nilai yang valid dalam hal bahasa. Sejak kemunculan mereka di versi 3.0 (yang lebih dari sepuluh tahun lalu!), Upaya komunitaslah yang mulai menggunakan anotasi untuk menandai variabel dan argumen yang diketik.
Contoh lain, lebih rumit. Tip 2: Dalam praktiknya, kebanyakan pengetikan dinamis menyebabkan masalah saat membaca dan men-debug kode. Terutama jika kode ini ditulis tanpa anotasi dan Anda harus menghabiskan banyak waktu mencari tahu jenis-jenis variabel. Anda tidak harus menunjukkan dan mendokumentasikan jenis segala sesuatu dan segalanya, tetapi waktu yang dihabiskan untuk deskripsi rinci antarmuka publik dan bagian kode yang paling kritis akan dihargai seratus kali lipat!
Dukun! Mengetik bebek
Kadang-kadang, penggemar Python berpura-pura menjadi misterius dan berbicara tentang "mengetik Bebek."
Mengetik bebek adalah penggunaan uji bebek dalam pemrograman:
Jika suatu benda dukun seperti bebek, terbang seperti bebek dan berjalan seperti bebek, maka kemungkinan besar bebek.
Pertimbangkan sebuah contoh:
class RpgCharacter: def __init__(self, weapon) self.weapon = weapon def battle(self): self.weapon.attack()
Ini adalah injeksi ketergantungan klasik. Kelas RpgCharacter
menerima objek weapon
di konstruktor dan kemudian, dalam metode battle()
, memanggil weapon.attack()
. Tetapi RpgCharacter
tidak tergantung pada implementasi spesifik weapon
. Itu bisa berupa pedang, BFG 9000, atau ikan paus dengan pot bunga, siap mendarat di kepala musuh kapan saja. Penting bahwa objek memiliki metode attack()
, Python tidak tertarik pada yang lainnya.
Sebenarnya, mengetik bebek tidak unik. Itu hadir dalam semua (akrab dengan saya) bahasa dinamis yang menerapkan OOP.
Ini adalah contoh lain tentang cara memprogram dengan cermat dalam dunia pengetikan dinamis. Metode yang tidak disebutkan namanya? Ambigu bernama variabel? Kolega Anda, atau Anda sendiri, setelah sekitar setengah tahun, akan dengan senang hati membuat kode seperti itu :)
Apa yang akan terjadi jika kita menggunakan Java kondisional? interface IWeapon { void attack(); } public class Sword implements IWeapon { public void attack() {
Dan akan ada pengetikan statis klasik, dengan pengecekan tipe pada tahap kompilasi. Harga - ketidakmampuan untuk menggunakan objek yang memiliki metode attack()
, tetapi tidak secara eksplisit mengimplementasikan antarmuka IWeapon
.
Tip 3 : Jika mau, Anda bisa mendeskripsikan antarmuka dengan membangun kelas abstrak Anda sendiri dengan metode dan properti . Lebih baik lagi, habiskan waktu untuk menguji dan menulis dokumentasi untuk diri sendiri dan pengguna kode Anda.
Pendekatan prosedural dan __ special_ metode __ ()
Python adalah bahasa berorientasi object
kelas object
adalah akar dari hierarki warisan:
isinstance('abc', object) >>> True isinstance(10, object) >>> True
Tetapi di mana obj.ToString()
digunakan dalam Java dan C #, akan ada panggilan ke str(obj)
dengan Python. Atau misalnya, alih-alih myList.length
, Python akan memiliki len(my_list)
. Pencipta bahasa, Guido van Rossum, menjelaskan ini sebagai berikut:
Ketika saya membaca kode yang mengatakan len(x)
, saya tahu bahwa panjang sesuatu yang diminta. Ini segera memberi tahu saya bahwa hasilnya akan berupa bilangan bulat, dan argumennya adalah semacam wadah. Sebaliknya, ketika membaca x.len()
, saya perlu tahu bahwa x
adalah semacam wadah yang mengimplementasikan antarmuka tertentu atau mewarisi dari kelas yang memiliki metode len()
. [Sumber] .
Namun demikian, di dalam dirinya sendiri, fungsi len()
, str()
dan beberapa lainnya akan memanggil metode objek tertentu:
class User: def __init__(self, name, last_name): self.name = name self.last_name = last_name def __str__(self): return f"Honourable {self.name} {self.last_name}" u = User('Alex', 'Black') label = str(u) print(label) >>> Honourable Alex Black
Metode khusus juga digunakan oleh operator bahasa, baik matematika dan Boolean, serta for ... in ...
operator loop, with
operator konteks, operator indeks []
, dll.
Misalnya, protokol iterator terdiri dari dua metode: __iter__()
dan __next__()
:
Baiklah, katakanlah metode khusus. Tapi mengapa mereka terlihat begitu bengkok? Guido menjelaskan hal ini dengan fakta bahwa mereka memiliki nama-nama yang biasa tanpa menggarisbawahi, programmer sendiri tidak akan setidaknya, cepat atau lambat mendefinisikan kembali mereka. Yaitu ____()
adalah semacam perlindungan terhadap si bodoh. Seperti yang ditunjukkan waktu - perlindungan efektif :)
Kiat 4: Perhatikan fungsi bawaan dan metode objek khusus . Mereka adalah bagian integral dari bahasa, yang tanpanya tidak mungkin untuk sepenuhnya berbicara itu.
Di mana enkapsulasi? Di mana pribadi saya?! Di mana dongeng saya? !!
Python tidak memiliki pengubah akses untuk atribut kelas. Interior objek terbuka untuk akses tanpa batasan. Namun, ada konvensi yang menyatakan atribut dengan awalan _
dianggap pribadi, misalnya:
import os class MyFile:
Mengapa
Tidak ada yang pribadi di Python. Baik kelas maupun instansinya tidak akan menyembunyikan dari Anda apa yang ada di dalam (berkat introspeksi terdalam yang dimungkinkan). Python mempercayai Anda. Dia semacam berkata, "Sobat, jika Anda ingin mencari-cari di sudut-sudut gelap - tidak masalah. Saya percaya bahwa ada alasan bagus untuk ini dan saya harap Anda tidak akan merusak apa pun.
Pada akhirnya, kita semua adalah orang dewasa di sini.
- Karl Fast [Sumber] .
Tetapi bagaimana cara menghindari tabrakan nama selama pewarisan?Python memiliki mekanisme khusus untuk mengatur nama atribut yang dimulai dengan garis bawah ganda dan tidak berakhir dengan garis bawah ganda ( __my_attr
)! Ini dilakukan untuk menghindari tabrakan nama selama pewarisan. Untuk memanggil metode kelas di luar tubuh, Python menambahkan ___
awalan. Tetapi untuk akses internal, tidak ada yang berubah:
class C: def __init__(self): self.__x = 10 def get_x(self): return self.__x c = C() c.__x >>> 'C' object has no attribute '__x' print(c.get_x()) >>> 10 print(c._C__x) >>> 10
Mari kita lihat aplikasi praktis. Misalnya, ke kelas File
, yang membaca file dari sistem file lokal, kami ingin menambahkan kemampuan caching. Kolega kami berhasil menulis kelas mixin untuk keperluan ini. Tetapi untuk mengisolasi metode dan atribut dari potensi konflik, seorang rekan menambahkan awalan __
ke nama mereka:
class BaseFile: def __init__(self, path): self.path = path class LocalMixin: def read_from_local(self): with open(self.path) as f: return f.read() class CachedMixin: class CacheMissError(Exception): pass def __init__(self):
Jika Anda tertarik untuk melihat implementasi mekanisme ini di CPython, silakan di Python / compile.c
Akhirnya, karena keberadaan properti dalam bahasa, tidak masuk akal untuk menulis getter dan setter dalam gaya Java: getX(), setX()
. Misalnya, dalam Coordinates
kelas yang awalnya ditulis,
class Coordinates: def __init__(self, x, y): self.x = x self.y = y c = Coordinates(10, 10) print(cx, cy) >>> (10, 10)
Saya perlu mengontrol akses ke atribut x
. Pendekatan yang benar adalah menggantinya dengan property
, sehingga mempertahankan kontrak dengan dunia luar.
class Coordinates: _x = 0 def __init__(self, x, y): self.x = x self.y = y @property def x(self): return self._x @x.setter def x(self, val): if val > 10: self._x = val else: raise ValueError('x should be greater than 10') c = Coordinates(20, 10) cx = 5 >>> ValueError: x should be greater than 10
Tip 5: Seperti Python, konsep bidang privat dan metode kelas didasarkan pada konvensi yang sudah mapan. Jangan tersinggung oleh penulis perpustakaan jika "semuanya telah berhenti berfungsi" karena Anda telah secara aktif menggunakan bidang pribadi kelas mereka. Pada akhirnya, kita semua adalah orang dewasa di sini :) .
Sedikit tentang pengecualian
Budaya python memiliki pendekatan unik untuk pengecualian. Selain intersepsi biasa dan pemrosesan ala C ++ / Java, Anda akan menemukan penggunaan pengecualian dalam konteks
"Lebih mudah meminta pengampunan, daripada izin - EAFP."
Mengutip - jangan menulis terlalu banyak if
, dalam kebanyakan kasus, eksekusi akan dilakukan pada cabang ini. Alih-alih, bungkus logika di try..except
.
Contoh: bayangkan penangan permintaan POST yang membuat pengguna dalam database bersyarat. Di input fungsi adalah kamus tipe kunci-nilai:
def create_user_handler(data: Dict[str, str]): try: database.user.persist( username=data['username'], password=data['password'] ) except KeyError: print('There was a missing field in data passed for user creation')
Kami tidak mencemari kode dengan cek "apakah username
atau password
terkandung dalam data
". Kami berharap mereka kemungkinan besar akan ada di sana. Kami tidak meminta "izin" untuk menggunakan bidang ini, tetapi "minta maaf" ketika kulhacker berikutnya memposting formulir dengan data yang hilang.
Hanya saja, jangan membawanya ke titik absurditas!Misalnya, Anda ingin memeriksa apakah nama belakang pengguna ada dalam data dan jika tidak disetel ke nilai kosong. if
sini akan jauh lebih tepat:
def create_user_handler(data): if 'last_name' not in data: data['last_name'] = '' try: database.user.persist( username=data['username'], password=data['password'], last_name=data['last_name'] ) except KeyError: print('There was a missing field in data passed for user creation')
Kesalahan tidak boleh terjadi secara diam-diam. - jangan abaikan pengecualian! Python modern memiliki peningkatan yang luar biasa raise from
konstruk yang memungkinkan Anda untuk mempertahankan konteks rantai pengecualian. Sebagai contoh:
class MyProductError(Exception): def __init__(self): super().__init__('There has been a terrible product error') def calculate(x): try: return 10 / x except ZeroDivisionError as e: raise MyProductError() from e
Tanpa raise from e
rantai pengecualian terputus pada MyProductError
, dan kami tidak dapat menemukan apa sebenarnya penyebab kesalahan ini. Dengan raise from X
, alasan (mis. X
) dari pengecualian yang dilemparkan disimpan dalam atribut __cause__
:
try: calculate(0) except MyProductError as e: print(e.__cause__) >>> division by zero
Tetapi ada sedikit nuansa dalam hal iterasi: StopIterationDalam kasus iterasi, melemparkan pengecualian StopIteration adalah cara resmi untuk memberi sinyal bahwa iterator telah selesai.
class PositiveIntegers: def __init__(self, limit): self.counter = 0 self.limit = limit def __iter__(self): return self def __next__(self): self.counter += 1 if self.counter == self.limit:
Kiat 6: Kami membayar untuk penanganan pengecualian hanya dalam situasi luar biasa. Jangan abaikan mereka!
Harus ada satu - dan lebih disukai hanya satu - cara sebelumnya untuk melakukannya.
switch
atau pencocokan pola? - gunakan if
dan kamus. do-
? - untuk ini ada while
dan for
. goto
Saya pikir Anda sendiri yang menebaknya. Hal yang sama berlaku untuk beberapa teknik desain dan pola yang tampaknya diterima begitu saja dalam bahasa lain. Yang paling menakjubkan adalah tidak ada batasan teknis dalam implementasinya, hanya saja "kami tidak memiliki cara seperti itu".
Misalnya, dalam Python Anda tidak sering melihat pola "Builder". Sebagai gantinya, ia menggunakan kemampuan untuk lulus dan secara eksplisit meminta argumen nama ke fungsi. Sebaliknya
human = HumanBuilder.withName("Alex").withLastName("Black").ofAge(20).withHobbies(['tennis', 'programming']).build()
akan
human = Human( name="Alex" last_name="Black" age=20 hobbies=['tennis', 'programming'] )
Perpustakaan standar tidak menggunakan rantai metode untuk bekerja dengan koleksi . Saya ingat bagaimana seorang kolega yang datang dari dunia Kotlin menunjukkan kode pengertian berikut kepada saya (diambil dari dokumentasi resmi untuk Kotlin):
val shortGreetings = people .filter { it.name.length < 10 } .map { "Hello, ${it.name}!" }
Dalam Python, map()
, filter()
dan banyak lainnya, adalah fungsi, bukan metode pengumpulan. Menulis ulang kode ini satu per satu, kita dapatkan:
short_greetings = map(lambda h: f"Hello, {h.name}", filter(lambda h: len(h.name) < 10, people))
Menurut saya itu terlihat mengerikan. Oleh karena itu, untuk bundel panjang seperti .takewhile().filter().map().reduce()
lebih baik menggunakan apa yang disebut inklusi (pemahaman), atau siklus lama yang baik. Ngomong-ngomong, contoh yang sama tentang Kotlin diberikan dalam bentuk pemahaman daftar yang sesuai. Dan pada Python terlihat seperti ini:
short_greetings = [ f"Hello {h.name}" for h in people if len(h.name) < 10 ]
Bagi mereka yang merindukan rantaiAda perpustakaan seperti Pipe atau py_linq !
Rantai metode digunakan di mana mereka lebih efisien daripada alat standar. Misalnya, dalam kerangka kerja Django web, rantai digunakan untuk membangun objek permintaan basis data:
query = User.objects \ .filter(last_visited__gte='2019-05-01') \ .order_by('username') \ .values('username', 'last_visited') \ [:5]
Tip 7: Sebelum Anda melakukan sesuatu yang sangat akrab dari pengalaman masa lalu, tetapi tidak terbiasa dengan Python, tanyakan pada diri sendiri keputusan apa yang akan dilakukan oleh pythonist berpengalaman?
Python lambat
Ya
Ya, ketika menyangkut kecepatan eksekusi dibandingkan dengan bahasa yang diketik dan dikompilasi secara statis.
Tetapi apakah Anda sepertinya menginginkan jawaban yang terperinci?
Implementasi referensi python (CPython) jauh dari implementasi yang paling efektif. Salah satu alasan penting adalah keinginan pengembang untuk tidak menyulitkannya. Dan logikanya dapat dimengerti - kode yang tidak terlalu muskil berarti lebih sedikit kesalahan, kesempatan yang lebih baik untuk melakukan perubahan, dan pada akhirnya, lebih banyak orang yang ingin membaca, memahami dan menambah kode ini.
Jake VanderPlas di blognya mem-parsing apa yang terjadi di CPython di bawah tenda ketika menambahkan dua variabel yang mengandung nilai integer:
a = 1 b = 2 c = a + b
Bahkan jika kita tidak pergi jauh ke dalam hutan CPython, kita dapat mengatakan bahwa untuk menyimpan variabel a
, b
dan c
, penerjemah harus membuat tiga objek di heap, di mana tipe dan (pointer ke) nilai akan disimpan; binary_add<int, int>(a->val, b->val)
kembali tipe dan nilai selama operasi penambahan untuk memanggil sesuatu seperti binary_add<int, int>(a->val, b->val)
; tulis hasilnya ke c
.
Ini sangat tidak efisien dibandingkan dengan program C serupa.
Masalah lain dengan CPython adalah apa yang disebut Global Interpreter Lock (GIL). Mekanisme ini, pada dasarnya nilai boolean yang dilampirkan oleh mutex, digunakan untuk menyinkronkan eksekusi bytecode. GIL menyederhanakan pengembangan kode yang berjalan di lingkungan multi-threaded: CPython tidak perlu berpikir tentang sinkronisasi akses ke variabel atau deadlock. Anda harus membayar untuk ini karena hanya satu utas yang mendapatkan akses dan mengeksekusi bytecode pada waktu tertentu:
UPD: Tetapi ini tidak berarti bahwa program pada Python secara ajaib akan bekerja di lingkungan multi-utas! Kode pada Python tidak ditransfer ke bytecode satu per satu dan tidak ada jaminan tentang kompatibilitas bytecode antara versi! Karena itu, Anda masih harus menyinkronkan utas dalam kode. Untungnya, di sini Python memiliki seperangkat alat yang kaya, misalnya, memungkinkan Anda untuk beralih antara model eksekusi multi-threaded dan multi-proses.
?
- . ( CFFI ) . API (extensions) C/C++. , Rust, Go Kotlin Native !
- , :
8: , . , IO (, , ) , , , , :)
? Linux MacOS, 95% . , 3., 2.7. Windows . : Docker, Windows Subsystem for Linux, Cygwin, , .
9: . , — - .
"Hello world" ? Hebat! machine learning- - Python Package Index (PyPI).
(packages), .. (virtual environments). , . - . pip
. pip
. , pipenv
poetry
— npm, bundler, cargo ..
0xA: — pip
virtualenv
. — , , . , — sys.path
— , .
?
? . :
Dive into python...
, . , , :)
, !