Python sangat, diketik secara dinamis.
- Mengetik dengan kuat berarti jenis nilai tidak berubah dengan cara yang tidak terduga. String yang hanya berisi angka tidak secara ajaib menjadi angka, seperti yang mungkin terjadi pada Perl. Setiap perubahan jenis memerlukan konversi eksplisit.
- Pengetikan dinamis berarti objek runtime (nilai) memiliki tipe, sebagai lawan dari pengetikan statis di mana variabel memiliki tipe.
Adapun contoh Anda
bob = 1
bob = "bob"
Ini berfungsi karena variabel tidak memiliki tipe; itu bisa menamai objek apa saja. Setelah bob=1
, Anda akan menemukan itu type(bob)
kembali int
, tetapi setelah bob="bob"
itu kembali str
. (Perhatikan bahwa type
ini adalah fungsi biasa, sehingga mengevaluasi argumennya, lalu mengembalikan jenis nilainya.)
Bandingkan ini dengan dialek C yang lebih lama, yang diketik dengan lemah, secara statis, sehingga pointer dan bilangan bulat cukup banyak dapat dipertukarkan. (ISO C modern membutuhkan konversi dalam banyak kasus, tetapi kompiler saya masih lunak tentang hal ini secara default.)
Saya harus menambahkan bahwa pengetikan kuat vs lemah lebih merupakan sebuah kontinum daripada pilihan boolean. C ++ memiliki pengetikan yang lebih kuat daripada C (dibutuhkan lebih banyak konversi), tetapi sistem tipe dapat ditumbangkan dengan menggunakan penunjuk pointer.
Kekuatan sistem tipe dalam bahasa yang dinamis seperti Python benar-benar ditentukan oleh bagaimana fungsi primitif dan pustaka merespons berbagai jenis. Misalnya, +
kelebihan beban sehingga berfungsi pada dua angka atau dua string, tetapi bukan string dan angka. Ini adalah pilihan desain yang dibuat ketika +
diimplementasikan, tetapi tidak benar-benar suatu keharusan mengikuti dari semantik bahasa. Faktanya, ketika Anda membebani +
tipe khusus secara berlebihan , Anda dapat membuatnya secara implisit mengubah apa pun menjadi angka:
def to_number(x):
"""Try to convert function argument to float-type object."""
try:
return float(x)
except (TypeError, ValueError):
return 0
class Foo:
def __init__(self, number):
self.number = number
def __add__(self, other):
return self.number + to_number(other)
Instance of class Foo
dapat ditambahkan ke objek lain:
>>> a = Foo(42)
>>> a + "1"
43.0
>>> a + Foo
42
>>> a + 1
43.0
>>> a + None
42
Mengamati bahwa meskipun sangat diketik Python benar-benar baik-baik saja dengan menambahkan objek tipe int
dan float
dan kembali objek tipe float
(misalnya, int(42) + float(1)
kembali 43.0
). Di sisi lain, karena ketidakcocokan antara jenis Haskell akan mengeluh jika seseorang mencoba yang berikut ini (42 :: Integer) + (1 :: Float)
. Ini membuat Haskell bahasa yang diketik dengan ketat, di mana tipe sepenuhnya terpisah dan hanya bentuk overload yang terkontrol yang dimungkinkan melalui kelas tipe.
True
atauFalse
. Tapi bagaimana dengan promosi nomor?1.0 + 2
berfungsi dengan baik di Python seperti halnya di Perl atau C, meskipun"1.0" + 2
tidak. Saya setuju dengan @jbrendel bahwa ini bukan konversi implisit, ini hanya overloading — tetapi dalam arti yang sama, Perl juga tidak melakukan konversi implisit. Jika fungsi tidak memiliki tipe parameter yang dideklarasikan, tidak ada tempat untuk konversi implisit terjadi.if isValid(value) - 1
bisa bocor. Boolean dipaksa menjadi bilangan bulat, yang kemudian dievaluasi sebagai nilai kebenaran.False - 1
menjadi benar danTrue - 1
menjadi salah, yang menyebabkan kesalahan dua-demi-satu yang memalukan sulit untuk di-debug. Dalam pengertian ini, kebanyakan python diketik dengan kuat; paksaan tipe biasanya tidak menyebabkan kesalahan logis.Ada beberapa masalah penting yang saya pikir tidak terjawab oleh semua jawaban yang ada.
Mengetik lemah berarti memungkinkan akses ke representasi yang mendasarinya. Di C, saya bisa membuat pointer ke karakter, kemudian memberi tahu kompiler saya ingin menggunakannya sebagai pointer ke integer:
Pada platform little-endian dengan bilangan bulat 32-bit, ini
i
menjadi array angka0x64636261
dan0x00676665
. Bahkan, Anda bahkan dapat mengarahkan pointer sendiri ke integer (dengan ukuran yang sesuai):Dan tentu saja ini berarti saya dapat menimpa memori di mana saja dalam sistem. *
* Tentu saja OS modern menggunakan memori virtual dan perlindungan halaman jadi saya hanya dapat menimpa memori proses saya sendiri, tetapi tidak ada apa pun tentang C itu sendiri yang menawarkan perlindungan seperti itu, seperti yang pernah dikodekan oleh siapa pun, katakanlah, Classic Mac OS atau Win16 dapat memberitahu Anda.
Lisp tradisional memungkinkan jenis peretasan yang serupa; pada beberapa platform, mengapung kata ganda dan sel kontra adalah tipe yang sama, dan Anda bisa meneruskan satu ke fungsi yang mengharapkan yang lain dan itu akan "bekerja".
Sebagian besar bahasa saat ini tidak cukup lemah seperti C dan Lisp, tetapi banyak dari mereka masih agak bocor. Misalnya, bahasa OO apa pun yang memiliki "downcast" yang tidak dicentang, * itu tipe kebocoran: Anda pada dasarnya memberi tahu kompiler "Saya tahu saya tidak memberi Anda informasi yang cukup untuk mengetahui ini aman, tapi saya cukup yakin itu adalah, "ketika seluruh titik dari sistem tipe adalah bahwa kompiler selalu memiliki informasi yang cukup untuk mengetahui apa yang aman.
* Downcast yang dicentang tidak membuat sistem tipe bahasa menjadi lebih lemah hanya karena ia menggerakkan check ke runtime. Jika ya, maka subtipe polimorfisme (alias panggilan fungsi virtual atau sepenuhnya dinamis) akan menjadi pelanggaran yang sama pada sistem tipe, dan saya tidak berpikir ada yang mau mengatakan itu.
Sangat sedikit bahasa "scripting" yang lemah dalam hal ini. Bahkan dalam Perl atau Tcl, Anda tidak dapat mengambil string dan hanya menafsirkan byte-nya sebagai integer. * Tetapi perlu dicatat bahwa dalam CPython (dan juga untuk banyak penerjemah lain untuk banyak bahasa), jika Anda benar-benar gigih, Anda dapat digunakan
ctypes
untuk memuatlibpython
, membuang objekid
kePOINTER(Py_Object)
, dan memaksa sistem tipe bocor. Apakah ini membuat sistem tipe lemah atau tidak tergantung pada kasus penggunaan Anda — jika Anda mencoba menerapkan sandbox eksekusi terbatas dalam bahasa untuk memastikan keamanan, Anda harus berurusan dengan pelarian semacam ini ...* Anda dapat menggunakan fungsi seperti
struct.unpack
membaca byte dan membangun int baru dari "bagaimana C akan mewakili byte ini", tapi itu jelas tidak bocor; bahkan Haskell memungkinkan itu.Sementara itu, konversi implisit benar-benar berbeda dari sistem tipe lemah atau bocor.
Setiap bahasa, bahkan Haskell, memiliki fungsi untuk, misalnya, mengubah integer menjadi string atau float. Tetapi beberapa bahasa akan melakukan beberapa konversi untuk Anda secara otomatis — misalnya, dalam C, jika Anda memanggil fungsi yang menginginkan
float
, dan Anda meneruskannyaint
, konversi akan dilakukan untuk Anda. Ini pasti dapat menyebabkan bug dengan, misalnya, luapan yang tidak terduga, tetapi mereka bukan jenis bug yang sama dengan yang Anda dapatkan dari sistem tipe lemah. Dan C tidak benar-benar menjadi lebih lemah di sini; Anda dapat menambahkan int dan float di Haskell, atau bahkan menggabungkan float ke string, Anda hanya perlu melakukannya secara lebih eksplisit.Dan dengan bahasa yang dinamis, ini cukup suram. Tidak ada yang namanya "fungsi yang menginginkan pelampung" dengan Python atau Perl. Tetapi ada fungsi kelebihan beban yang melakukan hal-hal yang berbeda dengan tipe yang berbeda, dan ada perasaan intuitif yang kuat bahwa, misalnya, menambahkan string ke sesuatu yang lain adalah "fungsi yang menginginkan string". Dalam arti itu, Perl, Tcl, dan JavaScript tampaknya melakukan banyak konversi implisit (
"a" + 1
memberi Anda"a1"
), sementara Python melakukan lebih sedikit ("a" + 1
menimbulkan pengecualian, tetapi1.0 + 1
memberi Anda2.0
*). Sulit untuk memahami hal itu dalam istilah formal — mengapa tidak ada+
yang mengambil string dan int, ketika jelas ada fungsi lain, seperti pengindeksan, yang bisa?* Sebenarnya, dalam Python modern, itu dapat dijelaskan dalam hal subtyping OO, karena
isinstance(2, numbers.Real)
itu benar. Saya tidak berpikir ada arti di mana2
merupakan turunan dari tipe string di Perl atau JavaScript ... meskipun di Tcl, sebenarnya, karena semuanya adalah turunan dari string.Akhirnya, ada definisi lain, sepenuhnya ortogonal, dari pengetikan "kuat" vs. "lemah", di mana "kuat" berarti kuat / fleksibel / ekspresif.
Misalnya, Haskell memungkinkan Anda menentukan tipe yang merupakan angka, string, daftar tipe ini, atau peta dari string ke tipe ini, yang merupakan cara sempurna untuk mewakili apa pun yang dapat diterjemahkan dari JSON. Tidak ada cara untuk mendefinisikan tipe seperti itu di Java. Tetapi setidaknya Java memiliki tipe parametrik (generik), jadi Anda dapat menulis fungsi yang mengambil Daftar T dan mengetahui bahwa elemen-elemennya adalah tipe T; bahasa lain, seperti Java awal, memaksa Anda untuk menggunakan Daftar Objek dan tertunduk. Tetapi setidaknya Java memungkinkan Anda membuat tipe baru dengan metode mereka sendiri; C hanya memungkinkan Anda membuat struktur. Dan BCPL bahkan tidak memilikinya. Dan seterusnya ke perakitan, di mana satu-satunya jenis panjang bit yang berbeda.
Jadi, dalam hal itu, sistem tipe Haskell lebih kuat dari Jawa modern, yang lebih kuat dari Jawa sebelumnya, yang lebih kuat dari C, yang lebih kuat dari BCPL.
Jadi, di mana Python cocok dengan spektrum itu? Itu agak rumit. Dalam banyak kasus, mengetik bebek memungkinkan Anda untuk mensimulasikan semua yang dapat Anda lakukan di Haskell, dan bahkan beberapa hal yang tidak dapat Anda lakukan; yakin, kesalahan ditangkap saat runtime alih-alih waktu kompilasi, tetapi masih tertangkap. Namun, ada beberapa kasus di mana mengetik bebek tidak cukup. Misalnya, di Haskell, Anda dapat mengatakan bahwa daftar int kosong adalah daftar int, sehingga Anda dapat memutuskan bahwa pengurangan
+
atas daftar tersebut harus mengembalikan 0 *; dalam Python, daftar kosong adalah daftar kosong; tidak ada jenis informasi untuk membantu Anda memutuskan pengurangan apa yang+
harus dilakukan.* Sebenarnya, Haskell tidak membiarkan Anda melakukan ini; jika Anda memanggil fungsi pengurangan yang tidak mengambil nilai awal pada daftar kosong, Anda mendapatkan kesalahan. Tetapi sistem tipenya cukup kuat sehingga Anda bisa membuatnya bekerja, dan Python tidak.
sumber
char sz[]
bukan pointer ke char, itu array char, dan dalam tugas itu meluruh menjadi pointer.Anda membingungkan 'sangat diketik' dengan 'diketik secara dinamis' .
Saya tidak bisa mengubah tipe
1
dengan menambahkan string'12'
, tetapi saya bisa memilih tipe apa yang saya simpan dalam variabel dan mengubahnya selama waktu program dijalankan.Kebalikan dari pengetikan dinamis adalah pengetikan statis; yang deklarasi jenis variabel tidak berubah selama masa program. Kebalikan dari pengetikan kuat adalah pengetikan lemah; jenis nilai dapat berubah selama masa program.
sumber
Menurut artikel Python wiki ini Python diketik secara dinamis dan sangat kuat (memberikan penjelasan yang baik juga).
Mungkin Anda berpikir tentang bahasa yang diketik secara statis di mana jenis tidak dapat berubah selama pelaksanaan program dan pemeriksaan jenis terjadi selama waktu kompilasi untuk mendeteksi kemungkinan kesalahan.
Pertanyaan SO ini mungkin menarik: Bahasa bertipe dinamis versus bahasa bertipe statis dan artikel Wikipedia tentang Sistem Tipe ini memberikan informasi lebih lanjut
sumber
TLDR;
Pengetikan Python adalah Dinamis sehingga Anda dapat mengubah variabel string ke int
Mengetik Python adalah Kuat sehingga Anda tidak dapat menggabungkan tipe:
Dalam Javascript yang diketik dengan lemah ini terjadi ...
Mengenai Jenis Inferensi
Java memaksa Anda untuk secara eksplisit mendeklarasikan tipe objek Anda
Kotlin menggunakan inferensi untuk menyadari itu
int
Tetapi karena kedua bahasa menggunakan tipe statis ,
x
tidak dapat diubah dariint
. Bahasa tidak akan memungkinkan perubahan dinamis sepertisumber
'x' + 3
mungkinoperator+
kelebihan beban dan melakukan konversi tipe di belakang layar?Sudah dijawab beberapa kali, tetapi Python adalah bahasa yang sangat diketik:
Berikut ini dalam JavaScript:
Itulah perbedaan antara pengetikan lemah dan pengetikan kuat. Jenis yang lemah secara otomatis mencoba mengonversi dari satu jenis ke jenis lain, tergantung pada konteks (mis. Perl). Tipe yang kuat tidak pernah mengonversi secara implisit.
Kebingungan Anda terletak pada kesalahpahaman tentang bagaimana Python mengikat nilai ke nama (biasanya disebut sebagai variabel).
Dalam Python, nama tidak memiliki tipe, sehingga Anda dapat melakukan hal-hal seperti:
Dan nama dapat terikat pada apa pun:
Untuk bacaan lebih lanjut:
https://en.wikipedia.org/wiki/Dynamic_dispatch
dan yang sedikit terkait tetapi lebih maju:
http://effbot.org/zone/call-by-object.htm
sumber
"3"*4
dengan python juga. Hasilnya tentu saja, adalah"3333"
. Anda tidak akan mengatakan bahwa itu mengubah hal baik. Tentu saja itu bisa jadi hanya perdebatan semantik.float
dari kombinasifloat
danint
bahwa itu mengkonversi tipe secara implisit. Ada hubungan alami antara float dan int, dan memang, jenis heirarki menjelaskannya. Saya kira Anda bisa berargumen mempertimbangkan Javascript'3'+4
dan'e'+4
keduanya menjadi operasi yang terdefinisi dengan cara yang sama yang Python anggap3.0 + 4
didefinisikan dengan baik, tetapi pada saat itu maka benar-benar tidak ada yang namanya tipe kuat atau lemah, hanya (tidak) didefinisikan operasi.Variabel Python menyimpan referensi yang tidak diketik ke objek target yang mewakili nilai.
Setiap operasi penugasan berarti menetapkan referensi yang tidak diketik ke objek yang ditugaskan - yaitu objek dibagi melalui referensi asli dan yang baru (dihitung).
Jenis nilai terikat ke objek target, bukan ke nilai referensi. Pemeriksaan tipe (kuat) dilakukan ketika operasi dengan nilai dilakukan (run time).
Dengan kata lain, variabel (secara teknis) tidak memiliki tipe - tidak masuk akal untuk berpikir dalam bentuk tipe variabel jika seseorang ingin tepat. Tetapi referensi secara otomatis direferensikan dan kita benar-benar berpikir dalam hal jenis objek target.
sumber
Istilah "pengetikan kuat" tidak memiliki definisi yang pasti.
Oleh karena itu, penggunaan istilah tergantung pada dengan siapa Anda berbicara.
Saya tidak mempertimbangkan bahasa apa pun, di mana jenis variabel tidak dinyatakan secara eksplisit, atau diketik secara statis untuk diketik dengan kuat.
Pengetikan yang kuat tidak hanya menghalangi konversi (misalnya, "secara otomatis" mengkonversi dari integer ke string). Itu menghalangi tugas (yaitu, mengubah jenis variabel).
Jika kode berikut dikompilasi (ditafsirkan), bahasa tidak diketik dengan kuat:
Foo = 1 Foo = "1"
Dalam bahasa yang sangat diketik, seorang programmer dapat "mengandalkan" suatu jenis.
Misalnya, jika seorang programmer melihat deklarasi tersebut,
UINT64 kZarkCount;
dan dia tahu bahwa 20 baris kemudian, kZarkCount masih merupakan UINT64 (selama itu terjadi di blok yang sama) - tanpa harus memeriksa kode intervensi.
sumber
Saya baru saja menemukan cara ringkas yang hebat untuk menghafalnya:
sumber
saya pikir, contoh sederhana ini harus Anda jelaskan perbedaan antara pengetikan yang kuat dan dinamis:
Jawa:
sumber
Di atas akan menciptakan mimpi buruk dari kode yang tidak dapat dipertahankan dalam sistem besar selama jangka waktu yang lama. Sebut saja apa yang Anda inginkan, tetapi kemampuan untuk "secara dinamis" mengubah jenis variabel hanyalah ide yang buruk ...
sumber