Suatu ketika, di masa mahasiswa saya, saya digigit oleh python, meskipun masa inkubasi tertunda dan ternyata saya menjadi programmer mutiara.
Namun, pada suatu titik, mutiara itu kehabisan tenaga dan saya memutuskan untuk mengambil python, pada awalnya saya hanya melakukan sesuatu dan mencari tahu apa yang diperlukan untuk tugas ini, dan kemudian saya menyadari bahwa saya memerlukan semacam pengetahuan sistematis dan membaca beberapa buku:
- Bill Lyubanovich βPython Sederhana. Gaya pemrograman modern β
- Dan Bader "Python Murni. Seluk-beluk pemrograman untuk pro Β»
- Brett Slatkin "Rahasia Python: 59 Tips untuk Menulis Kode Efektif"
Yang menurut saya cukup cocok untuk memahami seluk beluk dasar bahasa, meskipun saya tidak ingat menyebutkan slot di dalamnya, tetapi saya tidak yakin bahwa ini adalah fitur yang sangat diperlukan - jika saya menekannya dari memori, maka kemungkinan besar metode ini tidak akan cukup, tetapi tentu saja metode ini tidak akan cukup, tetapi tentu saja itu semua tergantung situasi.
Sebagai hasilnya, saya telah mengumpulkan beberapa catatan tentang fitur python, yang menurut saya, dapat berguna bagi seseorang yang ingin bermigrasi ke sana dari bahasa lain.
Saya perhatikan bahwa selama wawancara pada python cukup sering mereka mengajukan pertanyaan tentang hal-hal yang tidak terkait dengan pengembangan nyata, seperti apa yang mungkin menjadi kunci dari kamus (atau apa artinya x = yield y
), well dudes, dalam kehidupan nyata, kuncinya mungkin hanya angka atau string, dalam kasus unik saat ini tidak begitu, Anda dapat membaca dokumentasi dan mencari tahu mengapa bertanya ini? Untuk menemukan apa yang tidak diketahui orang yang diwawancarai? Jadi pada akhirnya, semua orang akan mengingat jawaban untuk pertanyaan khusus ini dan itu akan berhenti berfungsi.
Saya menganggap versi python lebih tinggi dari 3,5 relevan ( sudah waktunya untuk melupakan python kedua untuk waktu yang lama) sejak itu ini adalah versi dalam debian stabil, yang berarti di semua tempat lain ada versi yang lebih baru)
Karena saya bukan guru python sama sekali, saya berharap mereka benar di komentar jika saya tiba-tiba membeku semacam kebodohan.
Mengetik
Python adalah bahasa yang diketik secara dinamis, mis. itu memeriksa pencocokan jenis saat runtime, misalnya:
cat type.py a=5 b='5' print(a+b)
melakukan:
python3 type.py ... TypeError: unsupported operand type(s) for +: 'int' and 'str'
Namun, jika proyek Anda telah matang dengan kebutuhan untuk mengetik statis, maka python memberikan kesempatan seperti itu dengan menggunakan penganalisa statis mypy
:
mypy type.py type.py:3: error: Unsupported operand types for + ("int" and "str")
Benar, tidak semua kesalahan ditangkap dengan cara ini:
cat type2.py def greeting(name): return 'Hello ' + name greeting(5)
mypy tidak akan bersumpah di sini, tetapi kesalahan akan terjadi selama eksekusi, sehingga versi python saat ini mendukung sintaks khusus untuk menentukan jenis argumen fungsi:
cat type3.py def greeting(name: str) -> str: return 'Hello ' + name greeting(5)
dan sekarang:
mypy type3.py type3.py:4: error: Argument 1 to "greeting" has incompatible type "int"; expected "str"
Variabel dan Data
Variabel dalam python tidak menyimpan data, tetapi hanya merujuk padanya, dan data bisa berubah-ubah (bisa berubah) dan tidak berubah (tidak berubah).
Ini mengarah ke perilaku yang berbeda tergantung pada jenis data dalam situasi yang hampir identik, misalnya, kode seperti itu:
x = 1 y = x x = 2 print(y)
mengarah pada fakta bahwa variabel x
dan y
merujuk pada data yang berbeda, dan ini:
x = [1, 2, 3] y = x x[0] = 7 print(y)
tidak, x
dan y
tetap tautan ke daftar yang sama (meskipun seperti yang disebutkan dalam komentar, contohnya tidak terlalu berhasil, tapi saya belum menemukan yang lebih baik) bahwa omong-omong dengan python Anda dapat memeriksa dengan operator is
(saya yakin bahwa pencipta Jawa telah kehilangan tidur yang baik selamanya dari rasa malu ketika saya mengetahui tentang operator ini di python).
Meskipun baris terlihat seperti daftar, mereka adalah tipe data yang tidak dapat diubah, ini berarti bahwa string itu sendiri tidak dapat diubah, Anda hanya dapat membuat yang baru, tetapi Anda dapat menetapkan nilai yang berbeda untuk variabel, meskipun data asli tidak akan berubah:
>>> mystr = 'sss' >>> newstr = mystr # >>> mystr[0] = 'a' ... TypeError: 'str' object does not support item assignment >>> mystr = 'ssa' # >>> newstr # 'sss'
Berbicara tentang string, karena kekebalannya, merangkai daftar string yang sangat besar dengan menambahkan atau menambahkan dalam satu lingkaran mungkin tidak terlalu efektif (tergantung pada implementasi dalam kompiler / versi tertentu), biasanya disarankan untuk menggunakan metode gabungan untuk kasus-kasus seperti itu, yang berperilaku sedikit tidak terduga:
>>> str_list = ['ss', 'dd', 'gg'] >>> 'XXX'.join(str_list) 'ssXXXddXXXgg' >>> str = 'hello' >>> 'XXX'.join(str) 'hXXXeXXXlXXXlXXXo'
Pertama, garis di mana metode ini disebut menjadi pemisah, dan bukan awal dari garis baru seperti yang mungkin dipikirkan orang, dan kedua, Anda perlu melewati daftar (objek yang dapat diubah), dan bukan garis yang terpisah, karena juga merupakan objek yang dapat diubah dan akan disimbolkan .
Karena variabel adalah tautan, sangat normal untuk ingin membuat salinan objek agar tidak merusak objek asli, tetapi ada jebakan - fungsi salin hanya menyalin satu tingkat, yang jelas bukan apa yang diharapkan dari fungsi dengan nama ini, jadi gunakan deepcopy
.
Masalah serupa dengan penyalinan dapat terjadi ketika koleksi dikalikan dengan skalar, seperti dijelaskan di sini .
Lingkup
Topik ruang lingkup mungkin layak artikel terpisah, tetapi ada jawaban yang bagus untuk SO .
Singkatnya, ruang lingkupnya leksikal dan ada enam area visibilitas - variabel dalam tubuh fungsi, penutupan, dalam modul, di tubuh kelas, fungsi python bawaan dan variabel di dalam daftar dan inklusi lainnya.
Ada kehalusan - variabel default dapat dibaca dalam ruang nama bersarang leksikal, tetapi modifikasi memerlukan penggunaan kata kunci khusus nonlocal
dan global
untuk memodifikasi variabel satu tingkat lebih tinggi atau visibilitas global, masing-masing.
Misalnya, kode seperti ini:
x = 7 print(id(x)) def func(): print(id(x)) return x print(func())
Ini berfungsi dengan satu variabel global, dan yang ini:
x = 7 print(id(x)) def func(): x = 1 print(id(x)) return x print(func()) print(x)
sudah memunculkan yang lokal.
Dari sudut pandang saya, ini tidak terlalu baik, pada prinsipnya, setiap penggunaan variabel non-lokal dalam suatu fungsi adalah bagian dari antarmuka publik dari fungsi, tanda tangannya, yang berarti harus dinyatakan secara eksplisit dan terlihat pada awal fungsi. Juga, kata kunci tidak terlalu informatif - global
terdengar seperti definisi fungsi global, tetapi sebenarnya use global
.
Dalam python tidak ada titik masuk wajib dari mana program dimulai, seperti yang dilakukan dalam banyak bahasa, hanya semua yang ditulis pada tingkat modul dieksekusi secara berurutan, namun, karena variabel pada tingkat modul adalah variabel global, dari sudut pandang saya, itu harus menjadi praktik yang baik menjejalkan kode utama ke fungsi main()
, diikuti dengan panggilannya di akhir file:
if __name__ == '__main__': main()
kondisi ini akan berfungsi jika file tersebut disebut sebagai skrip dan tidak diimpor sebagai modul.
Argumen fungsi
Python menyediakan peluang yang cukup bagus untuk mendefinisikan argumen fungsi - posisional, argumen bernama dan kombinasinya.
Tetapi Anda perlu memahami bagaimana argumen disahkan - karena dalam python, semua variabel adalah tautan ke data, maka Anda dapat menebak bahwa transfer dilakukan dengan referensi, tetapi ada kekhasan - tautan itu sendiri dilewatkan oleh nilai i.e. Anda dapat mengubah nilai yang dapat diubah dengan referensi:
def add_element(mylist): mylist.append(3) mylist = [1,2] add_element(mylist) print(mylist)
melakukan:
python3 arg_modify.py [1, 2, 3]
namun, Anda tidak dapat menimpa tautan asli dalam suatu fungsi:
def try_del(mylist): mylist = [] return mylist mylist = [1,2] try_del(mylist) print(mylist)
tautan sumber masih hidup dan berfungsi:
python3 arg_kill.py [1, 2]
Anda juga dapat mengatur nilai default untuk argumen, tetapi ada satu hal yang tidak jelas untuk diingat: nilai default dihitung sekali ketika mendefinisikan fungsi, ini tidak membuat masalah jika Anda melewatkan data yang tidak berubah sebagai nilai default, dan jika Anda lulus data variabel atau nilai dinamis, hasilnya akan sedikit tidak terduga:
data yang bisa diubah:
cat arg_list.py def func(arg = []): arg.append('x') return arg print(func()) print(func()) print(func())
hasil:
python3 arg_list.py ['x'] ['x', 'x'] ['x', 'x', 'x']
nilai dinamis:
cat arg_now.py from datetime import datetime def func(arg = datetime.now()): return arg print(func()) print(func()) print(func())
kami mendapatkan:
python3 arg_now.py 2018-09-28 10:28:40.771879 2018-09-28 10:28:40.771879 2018-09-28 10:28:40.771879
OOP
OOP dengan python telah dilakukan dengan sangat menarik (beberapa properti sepadan) dan ini adalah topik yang besar, tetapi sapiens yang akrab dengan OOP mungkin juga google segalanya (atau menemukannya di hub ), jadi dia tidak perlu mengulanginya, meskipun perlu dikatakan bahwa python harus sedikit filosofi yang berbeda - adalah bahwa programmer cerdas mesin, dan bukan merupakan ancaman (UPD: lebih ), sehingga default python tidak biasa untuk bahasa lain akses pengubah: metode swasta dilaksanakan dengan menambahkan garis bawah ganda (yang mengubah runtime dari nama metode tidak OAPC kesempatan untuk menggunakannya), dan dilindungi satu garis bawah (yang tidak melakukan apa-apa benang, itu hanya konvensi penamaan).
Mereka yang kehilangan fungsi biasa dapat mencari upaya untuk membawa peluang seperti itu ke python, beberapa opsi ( lang , python-access ) di-google-kan oleh saya, tetapi saya tidak menguji atau mempelajarinya.
Satu-satunya minus dari kelas standar adalah kode boilerplate dalam metode Dunder , saya pribadi suka perpustakaan attrs , itu jauh lebih pythonic.
Perlu disebutkan bahwa karena dalam Python semua objek, termasuk fungsi dan kelas, kelas dapat dibuat secara dinamis (tanpa menggunakan eval
) oleh fungsi tipe .
Penting juga membaca tentang metaclasses ( tentang Habr ) dan deskriptor ( Habr ).
Sebuah kekhasan yang patut diingat adalah bahwa atribut kelas dan objek bukan hal yang sama, dalam hal atribut abadi ini tidak menimbulkan masalah karena atributnya adalah "membayangi" - atribut objek dengan nama yang sama dibuat secara otomatis, tetapi dalam kasus atribut yang dapat diubah, Anda dapat tidak mengerti apa yang diharapkan:
cat class_attr.py class MyClass: storage = [7,] def __init__(self, number): self.number = number obj = MyClass(1) obj2 = MyClass(2) obj.number = 5 obj.storage.append(8) print(obj2.storage, obj2.number)
kami mendapatkan:
python3 class_attr.py [7, 8] 2
seperti yang Anda lihat - mereka mengubah obj
, dan storage
berubah di obj2
juga. atribut ini (tidak seperti number
) bukan milik instance, tetapi ke kelas.
Konstanta
Seperti dalam kasus pengubah akses, python tidak mencoba membatasi pengembang, oleh karena itu, tidak mungkin untuk mendefinisikan variabel skalar yang dilindungi dari modifikasi dengan cara standar, hanya ada kesepakatan bahwa variabel dengan nama dalam huruf besar harus dianggap konstanta.
Python, di sisi lain, memiliki struktur data yang tidak dapat diubah seperti tuple, jadi jika Anda ingin membuat beberapa struktur global seperti konfigurasi yang tidak dapat diubah dan tidak ingin dependensi tambahan, maka namupuple adalah pilihan yang baik, walaupun itu akan memerlukan sedikit usaha lebih untuk menggambarkan tipe, oleh karena itu Saya suka implementasi alternatif dari struktur yang tidak dapat diubah dengan notasi titik - Box (lihat parameter frozen_box).
Nah, jika Anda ingin konstanta skalar, maka Anda dapat menerapkan kontrol akses pada tahap "kompilasi" yaitu memeriksa melalui mypy, contoh dan detail .
.sort () vs diurutkan ()
Ada dua cara untuk mengurutkan daftar dengan python. Yang pertama adalah metode .sort()
yang mengubah daftar asli dan tidak mengembalikan apa pun (Tidak ada) yaitu tidak bisa melakukan ini:
my_list = my_list.sort()
Yang kedua adalah fungsi sorted()
, yang memunculkan daftar baru dan dapat bekerja dengan semua objek yang dapat diulang. Siapa yang mau info lebih lanjut harus mulai dengan SO .
Perpustakaan standar
Biasanya, pustaka python standar mencakup solusi luar biasa untuk masalah umum, tetapi layak untuk dijadikan kritis, karena ada cukup keanehan. Benar, itu juga terjadi bahwa apa yang tampak aneh pada pandangan pertama ternyata menjadi solusi terbaik, Anda hanya perlu mengetahui semua kondisi (lihat di bawah untuk kisaran), tetapi masih ada keanehan.
Sebagai contoh, modul unit unittest yang datang dengan kit tidak ada hubungannya dengan python dan bernada Jawa, oleh karena itu, sebagai penulis python mengatakan : "Semua orang menggunakan py.test ...". Meskipun cukup menarik, meskipun tidak selalu cocok, modul doctest hadir sebagai standar.
Modul urllib yang disediakan tidak memiliki antarmuka yang indah seperti modul permintaan pihak ketiga.
Kisah yang sama dengan modul untuk parsing parameter baris perintah - argparse yang dibundel adalah demonstrasi OOP otak, dan modul docopt tampaknya hanya solusi cerdas - dokumentasi mandiri! Meskipun, menurut rumor, terlepas dari doktrin dan klik, ceruk tetap.
Dengan debugger juga - seperti yang saya mengerti, beberapa orang menggunakan pdb yang termasuk dalam paket, ada banyak alternatif, tetapi tampaknya sebagian besar pengembang menggunakan ipdb , yang, dari sudut pandang saya, paling nyaman untuk digunakan melalui modul debug wrapper.
Ini memungkinkan alih-alih import ipdb;ipdb.set_trace()
hanya menulis import debug
, itu juga menambahkan modul lihat untuk memudahkan pemeriksaan objek.
Untuk mengganti modul serialisasi standar, acar dibuat, omong-omong, perlu diingat bahwa modul-modul ini tidak cocok untuk bertukar data dalam sistem eksternal karena mengembalikan objek sewenang-wenang yang diterima dari sumber yang tidak terkontrol tidak aman, untuk kasus seperti itu ada json (untuk REST) ββdan gRPC (untuk RPC).
Untuk mengganti modul pemrosesan ekspresi reguler standar, kembali membuat modul regex dengan segala macam barang tambahan, seperti kelas karakter ala \p{Cyrillic}
.
Ngomong-ngomong, sesuatu tidak ditemukan untuk python debugger yang menyenangkan untuk regex yang mirip dengan jelai mutiara .
Berikut adalah contoh lain - seseorang membuat modul in-place-nya untuk memperbaiki kelengkungan dan ketidaklengkapan API dari modul input file standar di bagian menggantikan file editing.
Yah, saya sering memikirkan kasus-kasus seperti itu, karena saya bahkan telah menemukan lebih dari satu, jadi berhati-hatilah dan jangan lupa untuk melihat segala macam daftar yang luar biasa berguna, saya pikir seorang ahli gizi yang baik memiliki hidung untuk mengukur rasionalitas dari solusi, ini adalah dengan cara topik untuk diskusi lain - menurut perasaan saya (tentu saja, tidak ada statistik tentang hal ini dan tampaknya tidak bisa) di dunia python tingkat spesialis di atas rata-rata, karena sering kali perangkat lunak yang baik ternyata ditulis dalam python, tulis di komentar apa pendapat Anda tentang hal ini.
Konkurensi dan Persaingan
Python memberikan banyak peluang untuk pemrograman paralel dan kompetitif, tetapi bukan tanpa fitur.
Jika Anda membutuhkan paralelisme, dan ini terjadi ketika tugas Anda membutuhkan perhitungan, maka Anda harus memperhatikan modul multiprosesor .
Dan jika tugas Anda memiliki banyak harapan IO, maka python menyediakan banyak opsi untuk dipilih, dari utas dan gevent , hingga asyncio .
Semua opsi ini terlihat cukup cocok untuk digunakan (walaupun utas membutuhkan lebih banyak sumber daya), tetapi ada perasaan bahwa asyncio secara perlahan memeras sisanya, termasuk berkat semua jenis barang seperti uvloop .
Jika seseorang tidak memperhatikan - dengan python, utas bukan tentang paralelisme, saya tidak cukup kompeten untuk berbicara tentang GIL dengan baik , tetapi ada cukup materi tentang topik ini, oleh karena itu tidak ada kebutuhan seperti itu, hal utama yang perlu diingat adalah bahwa utas dalam python (lebih tepatnya dalam CPython) mereka berperilaku berbeda dari bahasa pemrograman lain - mereka berjalan hanya pada satu inti, yang berarti mereka tidak cocok untuk kasus-kasus di mana Anda membutuhkan paralelisme nyata, namun, eksekusi thread berhenti ketika menunggu input / output, sehingga mereka dapat digunakan untuk bersaing.
Keanehan lainnya
Dalam python, a = a + b
tidak selalu setara dengan a += b
:
a = [1] a = a + (2,3) TypeError: can only concatenate list (not "tuple") to list a += (2,3) a [1, 2, 3]
Saya mengirimnya ke SO untuk detail, sampai saya menemukan waktu untuk mencari tahu mengapa demikian, dalam arti untuk alasan apa mereka melakukannya, seperti ini lagi-lagi tentang mutabilitas.
Keanehan yang bukan keanehan
Pada pandangan pertama, tampak aneh bagi saya bahwa jenis jangkauan tidak termasuk perbatasan kanan, tetapi kemudian orang yang baik hati mengatakan kepada saya untuk mengabaikan mana yang perlu saya pelajari dan ternyata semuanya cukup logis.
Topik besar yang terpisah adalah pembulatan (meskipun masalah ini umum untuk hampir semua bahasa pemrograman), selain menggunakan pembulatan yang Anda suka, kecuali bahwa semua orang belajar di sekolah matematika, sehingga masalah mewakili angka floating-point masih ditumpangkan di atasnya, saya merujuk ke artikel rinci.
Secara kasar, alih-alih algoritma setengah- putaran yang biasa untuk matematika sekolah, algoritma setengah- genangan digunakan, yang mengurangi kemungkinan distorsi dalam analisis statistik dan karenanya direkomendasikan oleh standar IEEE 754.
Juga, saya tidak bisa mengerti mengapa -22//10=-3
, dan kemudian orang baik lainnya menunjukkan bahwa ini pasti mengikuti dari definisi matematika itu sendiri, yang menurutnya, sisanya tidak boleh negatif, yang mengarah ke perilaku yang tidak biasa seperti itu untuk angka negatif.
ACHTUNG! Sekarang ini lagi hal yang aneh dan saya tidak mengerti apa-apa, lihat utas ini.
Debugging Ekspresi Reguler
Dan di sini ternyata bahwa di dunia python tidak ada alat untuk debugging ekspresi reguler yang mirip dengan modul mutiara yang sangat baik Regexp :: Debugger ( presentasi video ), tentu saja ada banyak alat online, ada beberapa jenis solusi Windows-proprietary, tetapi bagi saya bukan itu, mungkin layak menggunakan alat bilah mutiara, karena rex python tidak jauh berbeda dari bilah mutiara, saya akan menulis instruksi untuk mereka yang tidak memiliki bilah mutiara:
sudo apt install cpanminus cpanm Regexp::Debugger perl -I ~/perl5/lib/perl5/ -E "use Regexp::Debugger; 'ababc' =~ /(a|b) b+ c/x"
Saya pikir bahkan orang yang tidak terbiasa dengan mutiara akan mengerti di mana perlu untuk memasukkan baris, dan di mana ekspresi reguler, x
adalah bendera yang mirip dengan python re.VERBOSE.
Tekan s
dan melangkahi ekspresi reguler, deskripsi terperinci dari perintah yang tersedia dalam dokumentasi .
Dokumentasi
Ada fungsi bantuan dalam python, yang memungkinkan Anda untuk mendapatkan bantuan pada setiap fungsi yang dimuat (diambil dari docstring-nya), nama fungsi dilewatkan sebagai parameter:
$ python3 >>> help(help)
tetapi ini tidak selalu merupakan cara yang nyaman dan seringkali lebih nyaman untuk menggunakan utilitas pydoc:
pydoc3 urllib.parse.urlparse
utilitas ini memungkinkan Anda untuk mencari dengan kata kunci dan bahkan memulai server lokal dengan dokumentasi html, tetapi saya belum menguji yang terakhir.