Jika Anda pernah bekerja dengan bahasa tingkat rendah seperti C atau C ++, Anda mungkin pernah mendengar tentang pointer. Mereka memungkinkan Anda untuk sangat meningkatkan efektivitas potongan kode yang berbeda. Tetapi mereka juga dapat membingungkan pemula - dan bahkan pengembang yang berpengalaman - dan menyebabkan bug manajemen memori. Apakah ada pointer di Python, bisakah saya meniru mereka?
Pointer banyak digunakan dalam C dan C ++. Bahkan, ini adalah variabel yang berisi alamat memori di mana variabel lain berada. Untuk membaca petunjuk, baca
ulasan ini.
Berkat artikel ini, Anda akan lebih memahami model objek dengan Python dan mencari tahu mengapa pointer sebenarnya tidak ada dalam bahasa ini. Jika Anda perlu mensimulasikan perilaku pointer, Anda akan belajar cara meniru mereka tanpa mimpi buruk yang menyertai manajemen memori.
Dengan artikel ini, Anda:
- Pelajari mengapa Python tidak memiliki petunjuk.
- Pelajari perbedaan antara variabel C dan nama dalam Python.
- Belajar meniru pointer dengan Python.
- Gunakan
ctypes
bereksperimen dengan pointer nyata.
Catatan : Di sini, istilah "Python" diterapkan pada implementasi Python di C, yang dikenal sebagai CPython. Semua diskusi perangkat bahasa berlaku untuk CPython 3.7, tetapi mungkin tidak sesuai dengan iterasi berikutnya.
Mengapa tidak ada pointer di Python?
Saya tidak tahu. Bisakah pointer ada di Python secara asli? Mungkin, tetapi tampaknya, petunjuknya bertentangan dengan konsep
Zen Python , karena mereka memprovokasi perubahan implisit alih-alih yang eksplisit. Pointer seringkali cukup kompleks, terutama untuk pemula. Selain itu, mereka mendorong Anda ke keputusan yang gagal atau untuk melakukan sesuatu yang sangat berbahaya, seperti membaca dari area memori, di mana Anda seharusnya tidak membacanya.
Python mencoba untuk mengabstraksi detail implementasi dari pengguna, seperti alamat memori. Seringkali dalam bahasa ini, penekanannya pada kegunaan, bukan kecepatan. Oleh karena itu pointer dengan Python tidak masuk akal. Tapi jangan khawatir, bahasa default memberi Anda beberapa manfaat menggunakan pointer.
Untuk memahami pointer dalam Python, mari kita membahas fitur implementasi bahasa secara singkat. Secara khusus, Anda perlu memahami:
- Apa itu benda yang bisa berubah dan tidak berubah.
- Bagaimana variabel / nama diatur dalam Python.
Pegang alamat memori Anda, ayo pergi!
Objek dalam Python
Segala sesuatu di Python adalah objek. Misalnya, buka REPL dan lihat bagaimana
isinstance()
:
>>> isinstance(1, object) True >>> isinstance(list(), object) True >>> isinstance(True, object) True >>> def foo(): ... pass ... >>> isinstance(foo, object) True
Kode ini menunjukkan bahwa segala sesuatu di Python sebenarnya adalah objek. Setiap objek mengandung setidaknya tiga jenis data:
- Penghitung referensi.
- Jenis
- Nilai.
Penghitung referensi digunakan untuk mengelola memori. Rincian tentang manajemen ini ditulis dalam
Memory Management in Python . Jenis ini digunakan pada tingkat CPython untuk memberikan keamanan jenis selama runtime. Dan nilai adalah nilai aktual yang terkait dengan objek.
Tetapi tidak semua benda itu sama. Ada satu perbedaan penting: objek bisa berubah dan tidak berubah. Memahami perbedaan antara jenis-jenis objek ini akan membantu Anda lebih memahami lapisan pertama bawang yang disebut "pointer di Python."
Benda yang bisa berubah dan tidak berubah
Ada dua jenis objek di Python:
- Objek yang tidak dapat diubah (tidak dapat diubah);
- Objek yang dapat dimodifikasi (dapat berubah).
Menyadari perbedaan ini adalah kunci pertama untuk melakukan perjalanan melalui dunia pointer di Python. Berikut ini adalah karakterisasi ketidakmampuan dari beberapa tipe yang populer:
Seperti yang Anda lihat, banyak tipe primitif yang umum digunakan tidak berubah. Anda dapat memverifikasi ini dengan menulis beberapa kode Python. Anda akan membutuhkan dua alat dari perpustakaan standar:
id()
mengembalikan alamat memori objek;
is
mengembalikan True
jika dan hanya jika dua objek memiliki alamat memori yang sama.
Anda dapat menjalankan kode ini di lingkungan REPL:
>>> x = 5 >>> id(x) 94529957049376
Di sini kita mengatur variabel
x
ke
5
. Jika Anda mencoba mengubah nilai menggunakan tambahan, Anda akan mendapatkan objek baru:
>>> x += 1 >>> x 6 >>> id(x) 94529957049408
Walaupun sepertinya kode ini hanya mengubah nilai
x
, pada kenyataannya Anda mendapatkan objek
baru sebagai jawaban.
Jenis
str
juga tidak berubah:
>>> s = "real_python" >>> id(s) 140637819584048 >>> s += "_rocks" >>> s 'real_python_rocks' >>> id(s) 140637819609424
Dan dalam hal ini,
s
setelah operasi
+=
mendapatkan alamat memori yang
berbeda .
Bonus : Operator
+=
menerjemahkan ke berbagai panggilan metode.
Untuk beberapa objek, seperti daftar,
+=
convert ke
__iadd__()
(append lokal). Ini akan berubah sendiri dan mengembalikan ID yang sama. Namun,
str
dan
int
tidak memiliki metode ini, dan sebagai hasilnya,
__add__()
akan dipanggil alih-alih
__iadd__()
.
Lihat
dokumentasi model data Python
untuk lebih jelasnya .Ketika kami mencoba untuk secara langsung mengubah nilai string dari
s
kami mendapatkan kesalahan:
>>> s[0] = "R"
Jejak balik (panggilan terbaru ditampilkan terakhir):
File "<stdin>", line 1, in <mdule> TypeError: 'str' object does not support item assignment
Kode di atas lumpuh dan laporan Python bahwa
str
tidak mendukung perubahan ini, yang sesuai dengan definisi kekekalan dari tipe
str
.
Bandingkan dengan objek yang bisa berubah, misalnya, dengan daftar:
>>> my_list = [1, 2, 3] >>> id(my_list) 140637819575368 >>> my_list.append(4) >>> my_list [1, 2, 3, 4] >>> id(my_list) 140637819575368
Kode ini menunjukkan perbedaan utama antara kedua jenis objek. Awalnya,
my_list
memiliki ID. Bahkan setelah menambahkan
4
ke daftar,
my_list
masih memiliki ID yang
sama . Alasannya adalah bahwa
list
jenis bisa berubah.
Berikut ini adalah demonstrasi lain dari daftar yang dapat diubah menggunakan penugasan:
>>> my_list[0] = 0 >>> my_list [0, 2, 3, 4] >>> id(my_list) 140637819575368
Dalam kode ini, kami mengubah
my_list
dan menetapkannya ke
0
sebagai elemen pertama. Namun, daftar tersebut mempertahankan ID yang sama setelah operasi ini. Langkah selanjutnya di jalur kami untuk
belajar Python adalah menjelajahi ekosistemnya.
Kami berurusan dengan variabel
Variabel dalam Python secara fundamental berbeda dari variabel dalam C dan C ++. Pada dasarnya, mereka tidak ada di Python.
Alih-alih variabel, ada nama .
Mungkin kedengarannya luar biasa, dan sebagian besar memang demikian. Paling sering, Anda bisa menggunakan nama dalam Python sebagai variabel, tetapi Anda harus memahami perbedaannya. Ini sangat penting ketika Anda mempelajari topik yang sulit seperti petunjuk.
Untuk membuatnya lebih mudah bagi Anda untuk memahami, mari kita lihat bagaimana variabel bekerja di C, apa yang mereka wakili, dan kemudian membandingkannya dengan karya nama dalam Python.
Variabel dalam C
Ambil kode yang mendefinisikan variabel
x
:
int x = 2337;
Eksekusi garis pendek ini melewati beberapa tahap yang berbeda:
- Mengalokasikan cukup memori untuk suatu nomor.
- Penugasan
2337
ke lokasi memori ini.
- Pemetaan yang
x
menunjukkan nilai ini.
Memori yang disederhanakan mungkin terlihat seperti ini:

Di sini, variabel
x
memiliki alamat palsu
0x7f1
dan nilai
2337
. Jika nanti Anda ingin mengubah nilai
x
, Anda dapat melakukan ini:
x = 2338;
Kode ini menetapkan variabel
x
nilai baru
2338
, sehingga menimpa nilai
sebelumnya . Ini berarti bahwa variabel
x
berubah . Skema memori yang diperbarui untuk nilai baru:

Harap dicatat bahwa lokasi
x
tidak berubah, hanya nilainya sendiri. Ini penting. Ini memberitahu kita bahwa
x
adalah
tempat di memori , dan bukan hanya nama.
Anda juga dapat mempertimbangkan masalah ini sebagai bagian dari konsep kepemilikan. Di satu sisi,
x
memiliki tempat dalam memori. Pertama,
x
adalah kotak kosong yang hanya bisa berisi satu bilangan bulat, di mana nilai integer dapat disimpan.
Saat Anda menetapkan
x
beberapa nilai, Anda memasukkan nilai ke dalam kotak milik
x
. Jika Anda ingin memperkenalkan variabel baru
y
, Anda dapat menambahkan baris ini:
int y = x;
Kode ini menciptakan kotak baru bernama
y
dan menyalin nilai dari
x
ke dalamnya. Sekarang sirkuit memori terlihat seperti ini:

Perhatikan lokasi baru
y
-
0x7f5
. Meskipun nilai
x
disalin ke
x
, variabel
y
memiliki alamat baru di memori. Oleh karena itu, Anda dapat menimpa nilai
y
tanpa mempengaruhi
x
:
y = 2339;
Sekarang sirkuit memori terlihat seperti ini:

Saya ulangi: Anda mengubah nilai
y
, tetapi bukan lokasi. Selain itu, Anda tidak memengaruhi variabel asli
x
.
Dengan nama dalam Python, situasinya benar-benar berbeda.
Nama dengan Python
Tidak ada variabel dalam Python, hanya nama. Anda dapat menggunakan istilah "variabel" sesuai kebijaksanaan Anda, namun penting untuk mengetahui perbedaan antara variabel dan nama.
Mari kita ambil kode yang setara dari contoh C di atas dan tulis dengan Python:
>>> x = 2337
Seperti dalam C, kode melewati beberapa langkah terpisah selama eksekusi ini:
- PyObject dibuat.
- Nomor untuk PyObject diberikan kode ketik.
2337
diberi nilai untuk PyObject.
- Nama
x
dibuat. x
menunjuk ke PyObject baru.- Jumlah referensi PyObject bertambah 1.
Catatan :
PyObject tidak sama dengan objek dalam Python, entitas ini khusus untuk CPython dan mewakili struktur dasar dari semua objek Python.
PyObject didefinisikan sebagai struktur-C, jadi jika Anda bertanya-tanya mengapa Anda tidak bisa langsung memanggil kode ketik atau penghitung referensi, maka alasannya adalah bahwa Anda tidak memiliki akses langsung ke struktur. Metode
panggilan seperti
sys.getrefcount () dapat membantu mendapatkan beberapa hal internal.
Jika kita berbicara tentang memori, maka akan terlihat seperti ini:

Di sini, sirkuit memori sangat berbeda dari sirkuit di C yang ditunjukkan di atas. Alih-alih memiliki
x
memiliki blok memori yang menyimpan nilai
2337
, objek Python yang baru dibuat memiliki memori yang hidup di
2337
. Nama Python
x
tidak secara langsung memiliki alamat di memori, seperti halnya variabel C memiliki sel statis.
Jika Anda ingin menetapkan
x
nilai baru, coba kode ini:
>>> x = 2338
Perilaku sistem akan berbeda dari apa yang terjadi di C, tetapi itu tidak akan terlalu berbeda dari ikatan asli dengan Python.
Dalam kode ini:
- PyObject baru dibuat.
- Nomor untuk PyObject diberikan kode ketik.
2
diberi nilai untuk PyObject.
x
menunjuk ke PyObject baru.
- Jumlah referensi dari PyObject baru bertambah 1.
- Jumlah referensi dari PyObject lama dikurangi sebesar 1.
Sekarang sirkuit memori terlihat seperti ini:

Ilustrasi ini menunjukkan bahwa
x
menunjuk ke referensi ke objek dan tidak memiliki area memori seperti sebelumnya. Anda juga melihat bahwa perintah
x = 2338
bukan tugas, tetapi lebih merupakan pengikatan nama
x
ke tautan.
Selain itu, objek sebelumnya (berisi nilai
2337
) sekarang ada dalam memori dengan jumlah referensi 0, dan akan dihapus
oleh pengumpul sampah .
Anda dapat memasukkan nama baru
y
, seperti dalam contoh C:
>>> y = x
Nama baru akan muncul di memori, tetapi tidak harus berupa objek baru:

Sekarang Anda melihat bahwa objek Python baru
belum dibuat, hanya nama baru yang dibuat yang menunjuk ke objek yang sama. Selain itu, penghitung referensi objek bertambah 1. Anda dapat memeriksa kesetaraan identitas objek untuk mengonfirmasi identitas mereka:
>>> y is x True
Kode ini menunjukkan bahwa
x
dan
y
adalah satu objek. Tapi jangan salah: Anda masih abadi. Misalnya, Anda dapat melakukan operasi tambahan dengan
y
:
>>> y += 1 >>> y is x False
Setelah penambahan dipanggil, Anda akan mengembalikan objek Python baru. Sekarang memori terlihat seperti ini:

Objek baru telah dibuat, dan sekarang Anda menunjuk ke sana. Sangat mengherankan bahwa kita akan mendapatkan keadaan akhir yang persis sama jika kita secara langsung menautkan
y
ke
2339
:
>>> y = 2339
Setelah ungkapan ini, kami memperoleh memori terakhir, seperti dalam operasi penambahan. Biarkan saya mengingatkan Anda bahwa dengan Python Anda tidak menetapkan variabel, tetapi ikat nama ke tautan.
Tentang magang di Python
Sekarang Anda mengerti bagaimana objek baru dibuat dengan Python dan bagaimana nama dilampirkan. Sudah waktunya untuk berbicara tentang objek yang diinternir.
Kami memiliki kode Python ini:
>>> x = 1000 >>> y = 1000 >>> x is y True
Seperti sebelumnya,
x
dan
y
adalah nama yang menunjuk ke objek Python yang sama. Tetapi objek ini yang berisi nilai
1000
tidak selalu dapat memiliki alamat memori yang sama. Misalnya, jika Anda menambahkan dua angka dan mendapatkan 1000, Anda akan mendapatkan alamat lain:
>>> x = 1000 >>> y = 499 + 501 >>> x is y False
Kali ini, string
x is y
mengembalikan
False
. Jika Anda malu, jangan khawatir. Inilah yang terjadi ketika kode ini dieksekusi:
- Objek Python dibuat (
1000
).
- Itu diberi nama
x
.
- Objek Python dibuat (
499
).
- Objek Python dibuat (
501
).
- Dua objek ini bertambah.
- Objek Python baru dibuat (
1000
).
- Dia diberi nama
y
.
Penjelasan Teknis : Langkah-langkah yang dijelaskan hanya terjadi ketika kode ini dijalankan di dalam REPL. Jika Anda mengambil contoh di atas, tempel ke file dan jalankan, maka baris
x is y
akan mengembalikan
True
.
Alasannya adalah kecerdasan cepat dari kompiler CPython, yang mencoba melakukan
optimasi lubang intip yang membantu untuk menyimpan langkah-langkah eksekusi kode sebanyak mungkin. Detail dapat ditemukan dalam
kode sumber CPython optimizer peyphole .
Tapi bukankah itu boros? Ya, tapi Anda membayar harga ini untuk semua manfaat besar Python. Anda tidak perlu berpikir untuk menghapus objek perantara tersebut, dan Anda bahkan tidak perlu tahu tentang keberadaannya! Leluconnya adalah bahwa operasi ini dilakukan relatif cepat, dan Anda tidak akan mengetahuinya sampai saat itu.
Pembuat Python dengan bijaksana memperhatikan overhead ini dan memutuskan untuk membuat beberapa optimasi. Hasilnya adalah perilaku yang mungkin mengejutkan pemula:
>>> x = 20 >>> y = 19 + 1 >>> x is y True
Dalam contoh ini, kodenya hampir sama seperti di atas, kecuali kita mendapatkan
True
. Ini semua tentang benda yang diinternir. Python pra-membuat subset objek tertentu dalam memori dan menyimpannya dalam namespace global untuk penggunaan sehari-hari.
Objek mana yang bergantung pada implementasi Python? Dalam CPython 3.7, interniran adalah:
- Bilangan bulat mulai dari
-5
hingga 256
.
- String yang hanya berisi huruf, angka, atau garis bawah ASCII.
Ini karena variabel-variabel ini sangat sering digunakan dalam banyak program. Dengan magang, Python mencegah alokasi memori untuk objek yang persisten.
Baris dengan ukuran kurang dari 20 karakter dan berisi huruf, angka, atau garis bawah ASCII akan diinternir karena seharusnya digunakan sebagai pengidentifikasi:
>>> s1 = "realpython" >>> id(s1) 140696485006960 >>> s2 = "realpython" >>> id(s2) 140696485006960 >>> s1 is s2 True
Di sini
s1
dan
s2
menunjuk ke alamat yang sama dalam memori. Jika kami tidak memasukkan huruf, angka, atau garis bawah ASCII, kami akan mendapatkan hasil yang berbeda:
>>> s1 = "Real Python!" >>> s2 = "Real Python!" >>> s1 is s2 False
Contoh ini menggunakan tanda seru, sehingga string tidak diinternir dan objek yang berbeda dalam memori.
Bonus : Jika Anda ingin objek ini merujuk ke objek yang diinternir yang sama, Anda dapat menggunakan
sys.intern()
. Salah satu cara untuk menggunakan fitur ini dijelaskan dalam dokumentasi:
Pemanggangan string berguna untuk sedikit meningkatkan kinerja pencarian kamus: jika kunci dalam kamus dan kunci yang akan dicari diinternir, maka perbandingan kunci (setelah hashing) dapat dilakukan dengan membandingkan pointer daripada string. ( Sumber )
Internee sering membingungkan programmer. Ingatlah bahwa jika Anda mulai ragu, Anda selalu dapat menggunakan
id()
dan untuk menentukan kesetaraan objek.
Emulasi Pointer Python
Fakta bahwa pointer tidak ada secara asli di Python tidak berarti bahwa Anda tidak dapat memanfaatkan pointer. Sebenarnya ada beberapa cara untuk meniru pointer dengan Python. Di sini kita melihat dua di antaranya:
- Gunakan sebagai pointer ke tipe yang bisa berubah.
- Menggunakan objek Python yang disiapkan khusus.
Gunakan sebagai pointer jenis bisa berubah
Anda sudah tahu jenis apa yang bisa berubah. Berkat mutabilitas mereka, kita dapat meniru perilaku pointer. Katakanlah Anda perlu mereplikasi kode ini:
void add_one(int *x) { *x += 1; }
Kode ini membawa pointer ke angka (
*x
) dan menambah nilainya dengan 1. Berikut adalah fungsi utama untuk mengeksekusi kode:
Dalam fragmen di atas, kami menetapkan
y
ke
2337
, menampilkan nilai saat ini, meningkatkannya dengan 1, dan kemudian menampilkan nilai baru. Berikut ini muncul di layar:
y = 2337 y = 2338
Salah satu cara untuk mereplikasi perilaku ini dengan Python adalah dengan menggunakan tipe yang bisa berubah. Misalnya, terapkan daftar dan ubah elemen pertama:
>>> def add_one(x): ... x[0] += 1 ... >>> y = [2337] >>> add_one(y) >>> y[0] 2338
Di sini
add_one(x)
merujuk ke elemen pertama dan meningkatkan nilainya dengan 1. Menggunakan daftar berarti bahwa sebagai hasilnya kita mendapatkan nilai yang diubah. Jadi ada pointer di Python? Tidak. Perilaku yang dijelaskan menjadi mungkin karena daftar adalah tipe yang bisa berubah. Jika Anda mencoba menggunakan tuple, Anda mendapatkan kesalahan:
>>> z = (2337,) >>> add_one(z)
Jejak balik (panggilan terbaru terakhir):
File "<stdin>", line 1, in <module> File "<stdin>", line 2, in add_one TypeError: 'tuple' object does not support item assignment
Kode ini menunjukkan ketidakstabilan tuple, sehingga tidak mendukung penetapan elemen.
list
bukan satu-satunya tipe yang bisa berubah, pointer bagian juga ditiru menggunakan
dict
.
Misalkan Anda memiliki aplikasi yang harus melacak terjadinya peristiwa menarik. Ini dapat dilakukan dengan membuat kamus dan menggunakan salah satu elemennya sebagai penghitung:
>>> counters = {"func_calls": 0} >>> def bar(): ... counters["func_calls"] += 1 ... >>> def foo(): ... counters["func_calls"] += 1 ... bar() ... >>> foo() >>> counters["func_calls"] 2
Dalam contoh ini, kamus menggunakan penghitung untuk melacak jumlah panggilan fungsi. Setelah memanggil
foo()
penghitung bertambah 2, seperti yang diharapkan. Dan semua berkat
dict
.
Jangan lupa, ini hanya
emulasi dari perilaku pointer, ini tidak ada hubungannya dengan pointer nyata di C dan C ++. Kita dapat mengatakan bahwa operasi ini lebih mahal daripada jika dilakukan dalam C atau C ++.
Menggunakan Objek Python
dict
adalah cara yang bagus untuk meniru pointer dengan Python, tetapi terkadang membosankan untuk mengingat nama kunci yang Anda gunakan. Terutama jika Anda menggunakan kamus di berbagai bagian aplikasi. Kelas Python khusus dapat membantu di sini.
Katakanlah Anda perlu melacak metrik dalam suatu aplikasi. Cara terbaik untuk mengabaikan detail yang menjengkelkan adalah membuat kelas:
class Metrics(object): def __init__(self): self._metrics = { "func_calls": 0, "cat_pictures_served": 0, }
Kode ini mendefinisikan kelas
Metrics
. Masih menggunakan kamus untuk menyimpan data terbaru yang terletak pada
_metrics
anggota
_metrics
. Ini akan memberi Anda mutabilitas yang diperlukan. Sekarang Anda hanya perlu mengakses nilai-nilai ini. Anda dapat melakukan ini menggunakan properti:
class Metrics(object):
Di sini kita menggunakan
@ properti . Jika Anda baru mengenal dekorator, baca artikel
Primer tentang Python Dekorator . Dalam hal ini, dekorator
@property
memungkinkan Anda untuk mengakses
func_calls
dan
cat_pictures_served
, seolah-olah mereka adalah atribut:
>>> metrics = Metrics() >>> metrics.func_calls 0 >>> metrics.cat_pictures_served 0
Fakta bahwa Anda dapat merujuk nama-nama ini sebagai atribut berarti bahwa Anda disarikan dari fakta bahwa nilai-nilai ini disimpan dalam kamus. Selain itu, Anda membuat nama atribut lebih eksplisit. Tentu saja, Anda harus dapat meningkatkan nilai:
class Metrics(object):
:
inc_func_calls()
inc_cat_pics()
metrics
. , , :
>>> metrics = Metrics() >>> metrics.inc_func_calls() >>> metrics.inc_func_calls() >>> metrics.func_calls 2
func_calls
inc_func_calls()
Python. , -
metrics
, .
: ,
inc_func_calls()
inc_cat_pics()
@property.setter
int
, .
Metrics
:
class Metrics(object): def __init__(self): self._metrics = { "func_calls": 0, "cat_pictures_served": 0, } @property def func_calls(self): return self._metrics["func_calls"] @property def cat_pictures_served(self): return self._metrics["cat_pictures_served"] def inc_func_calls(self): self._metrics["func_calls"] += 1 def inc_cat_pics(self): self._metrics["cat_pictures_served"] += 1
ctypes
, - Python, CPython? ctypes , C. ctypes,
Extending Python With C Libraries and the ยซctypesยป Module .
, , . -
add_one()
:
void add_one(int *x) { *x += 1; }
,
x
1. , (shared) . ,
add.c
, gcc:
$ gcc -c -Wall -Werror -fpic add.c $ gcc -shared -o libadd1.so add.o
C
add.o
.
libadd1.so
.
libadd1.so
. ctypes Python:
>>> import ctypes >>> add_lib = ctypes.CDLL("./libadd1.so") >>> add_lib.add_one <_FuncPtr object at 0x7f9f3b8852a0>
ctypes.CDLL ,
libadd1
.
add_one()
, , Python-. , . Python , .
, ctypes :
>>> add_one = add_lib.add_one >>> add_one.argtypes = [ctypes.POINTER(ctypes.c_int)]
, C. , , :
>>> add_one(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> ctypes.ArgumentError: argument 1: <class 'TypeError'>: \ expected LP_c_int instance instead of int
Python ,
add_one()
, . , ctypes . :
>>> x = ctypes.c_int() >>> x c_int(0)
x
0
. ctypes
byref()
, .
:
.
, . , .
add_one()
:
>>> add_one(ctypes.byref(x)) 998793640 >>> x c_int(1)
Hebat! 1. , Python .
Kesimpulan
Python . , Python.
Python:
Python .