ctypes - Başlangıç


102

Ac kitaplığını bir python sınıfına "sarma" görevim var. Dokümanlar bu konuda inanılmaz derecede belirsiz. Görünüşe göre, yalnızca gelişmiş python kullanıcılarının ctype uygulamalarını bekliyorlar. Python'da acemiyim ve yardıma ihtiyacım var.

Adım adım yardım harika olurdu.

Bu yüzden c kütüphanem var. Ben ne yaparım? Hangi dosyaları nereye koyarım? Kitaplığı nasıl içe aktarırım? Python'a "otomatik kaydırmanın" bir yolu olabileceğini okudum.

(Bu arada python.net'te ctypes eğitimini yaptım ve işe yaramıyor. Yani, adımların geri kalanını doldurabileceğimi varsayıyorlar.

Aslında, kodlarında aldığım hata bu:

File "importtest.py", line 1
   >>> from ctypes import *
   SyntaxError: invalid syntax

Bu konuda gerçekten adım adım yardım kullanabilirim! Teşekkürler ~


10
Eğer var mı >>> importtest.py içinde? İnsanlar >>> her satırda bulunan kodu gönderdiklerinde, bu, etkileşimli kabukta çalıştırıldığını gösterir. Bir dosyadan çalıştırmak için, >>> göründüğü her yerden kaldırın (bu 3> işaret ve boşluktur).
Chinmay Kanchi

4
Yazmayın >>>s. Bunlar etkileşimli kabuk tarafından yazdırılır ve kaynak dosyanızın dışında bırakılmalıdır.
nmichaels

8
>>>.py dosyasında! OUCH! Bunu daha önce hiç görmedim!
David Heffernan

4
Açıkçası, ctypes ile uğraşmaya başlamadan önce biraz Python (en azından biraz) öğrenin. Sen edilmektedir asla temel Python bilmiyorum varsayılmaktadır ctypes bir öğretici bulacağız.
Chinmay Kanchi

3
@spentak: Yardım isterseniz yeterli bilgi verin. En azından bize bahsettiğiniz kodun son sürümünü gösterin. Örneğin "3. satır" da ne var?
Francesco

Yanıtlar:


230

İşte hızlı ve kirli bir ctype öğreticisi.

Önce C kitaplığınızı yazın. İşte basit bir Merhaba dünya örneği:

testlib.c

#include <stdio.h>

void myprint(void);

void myprint()
{
    printf("hello world\n");
}

Şimdi onu paylaşılan bir kitaplık olarak derleyin ( mac düzeltmesi burada bulunur ):

$ gcc -shared -Wl,-soname,testlib -o testlib.so -fPIC testlib.c

# or... for Mac OS X 
$ gcc -shared -Wl,-install_name,testlib.so -o testlib.so -fPIC testlib.c

Ardından, ctypes kullanarak bir sarmalayıcı yazın:

testlibwrapper.py

import ctypes

testlib = ctypes.CDLL('/full/path/to/testlib.so')
testlib.myprint()

Şimdi uygulayın:

$ python testlibwrapper.py

Ve çıktıyı görmelisin

Hello world
$

Zaten bir kitaplığınız varsa, öğreticinin python olmayan kısmını atlayabilirsiniz. Ctype'lerin kitaplığı /usr/libveya başka bir standart dizine koyarak bulabileceğinden emin olun . Bunu yaparsanız, sarmalayıcıyı yazarken tam yolu belirtmeniz gerekmez. Bunu seçerseniz, sen gerekir çağrılırken kütüphanenin tam yolunu sağlamak ctypes.CDLL().

Burası daha kapsamlı bir öğreticinin yeri değil, ancak bu sitedeki belirli sorunlarla ilgili yardım isterseniz, topluluğun size yardımcı olacağına eminim.

Not: Kullandığınız için Linux'ta olduğunuzu varsayıyorum ctypes.CDLL('libc.so.6'). Başka bir işletim sistemindeyseniz, işler biraz değişebilir (veya oldukça fazla).


1
@ Chinmay: Windows için benzer bir kod alabilir miyim ve C yerine lütfen görsel bir c ++ örneği verebilir misiniz? Kitaplığımı yükleyebiliyorum, ancak işlevlerime .dll dosyasından erişemiyorum. Her zaman "işlev 'xyz' bulunamadı" der. Bana bunun etrafında bir yol önerebilir misin? Şerefe.
Neophile

Windows geliştirme hakkında pek bir şey bilmiyorum, ancak Windows riskli bir şey yapıyor gibi görünüyor, belki farklı bir arama kuralı kullanıyor? Belki "extern C" kullanarak C ++ işlevlerinizi dışa aktarmaya bakabilirsiniz?
Chinmay Kanchi

Evet, bunu yaptım ama şimdiye kadar şansım olmadı.
Neophile

6
Ctype'ın temel işlevlerini gösteren, takip etmesi kolay eğitim için teşekkürler
okysabeni

1
hızlı ve kirli her zaman en iyi öğreticilerdir
lurscher

56

Chinmay Kanchi'nin cevabı mükemmel ancak değişkenleri / dizileri C ++ koduna geçiren ve döndüren bir işlev örneği istedim. Başkaları için yararlı olması durumunda buraya eklemeyi düşündüm.

Bir tamsayı geçirme ve döndürme

Bir tamsayı alan ve döndürülen değere bir ekleyen bir işlevin C ++ kodu,

extern "C" int add_one(int i)
{
    return i+1;
}

Dosya olarak kaydedildiğinde test.cpp, gerekli harici "C" yi not edin (bu, C kodu için kaldırılabilir). Bu, Chinmay Kanchi cevabına benzer argümanlarla g ++ kullanılarak derlenmiştir,

g++ -shared -o testlib.so -fPIC test.cpp

Python kodu kullanımları load_librarygelen numpy.ctypeslibPython komut ile aynı dizinde paylaşılan kitaplığa varsayarak yola,

import numpy.ctypeslib as ctl
import ctypes

libname = 'testlib.so'
libdir = './'
lib=ctl.load_library(libname, libdir)

py_add_one = lib.add_one
py_add_one.argtypes = [ctypes.c_int]
value = 5
results = py_add_one(value)
print(results)

Bu beklendiği gibi 6 yazdırır.

Bir diziyi iletme ve yazdırma

Ayrıca dizileri aşağıdaki gibi iletebilirsiniz, bir C kodunun bir dizinin öğesini yazdırması için,

extern "C" void print_array(double* array, int N)
{
    for (int i=0; i<N; i++) 
        cout << i << " " << array[i] << endl;
}

daha önce olduğu gibi derlenir ve aynı şekilde içe aktarılır. Bu işlevi kullanmak için ekstra Python kodu şu şekilde olacaktır:

import numpy as np

py_print_array = lib.print_array
py_print_array.argtypes = [ctl.ndpointer(np.float64, 
                                         flags='aligned, c_contiguous'), 
                           ctypes.c_int]
A = np.array([1.4,2.6,3.0], dtype=np.float64)
py_print_array(A, 3)

burada print_arraydiziyi, hizalanmış bir Numpy dizisine işaretçi olarak ilk argüman , c_contiguous 64 bit kayar ve ikinci argüman C koduna Numpy dizisindeki elemanların sayısını söyleyen bir tamsayı olarak belirtiriz. Bu daha sonra aşağıdaki gibi C kodu ile yazdırılır,

1.4
2.6
3.0

5
Bu harika bir tamamlayıcı cevap - ayıp iki işaretlenmiş cevap olamaz :(
jtlz2

Çok açık olup olmadığından emin değilim, ancak kodda bir hata var. Eksik import numpy as np. Aksi takdirde bulamaz np.float64ve diğer şeyler.
Ben

11

İlk olarak: >>>python örneklerinde gördüğünüz kod, Python kodu olduğunu göstermenin bir yoludur. Python kodunu çıktıdan ayırmak için kullanılır. Bunun gibi:

>>> 4+5
9

Burada, ile başlayan satırın >>>Python kodu olduğunu ve 9 ile sonuçlandığını görüyoruz . Bir Python yorumlayıcısı başlattığınızda tam olarak böyle görünüyor, bu yüzden böyle yapılır.

Parçayı asla >>>bir .pydosyaya girmezsiniz.

Bu, sözdizimi hatanızla ilgilenir.

İkinci olarak, ctypes, Python kitaplıklarını sarmalamanın birkaç yolundan yalnızca biridir. Diğer yolu vardır yudum Python kütüphanede bakmak ve C API ortaya bir Python C uzantısı modülünü oluşturur. Başka bir yol da Cython kullanmaktır .

Hepsinin yararları ve dezavantajları vardır.

SWIG yalnızca C API'nizi Python'a gösterir. Bu, herhangi bir nesne veya hiçbir şey almayacağınız anlamına gelir, bunu yapmak için ayrı bir Python dosyası oluşturmanız gerekir. Ancak "wowza" adlı bir modül ve C API'sinin etrafındaki sarmalayıcı olan "_wowza" adlı bir SWIG modülüne sahip olmak yaygındır. Bu, işleri yapmanın güzel ve kolay bir yoludur.

Cython, bir C-Extension dosyası oluşturur. Yazdığınız tüm Python kodunun C'ye dönüştürülmesi avantajına sahiptir, bu nedenle yazdığınız nesneler de C'dir, bu bir performans artışı olabilir. Ancak C ile nasıl arayüz oluşturduğunu öğrenmeniz gerekecek, bu yüzden onu nasıl kullanacağınızı öğrenmek için biraz fazladan iş.

ctypes, derlenecek C kodunun olmaması avantajına sahiptir, bu nedenle başka biri tarafından yazılmış standart kitaplıkları sarmak için kullanmak çok güzel ve Windows ve OS X için ikili sürümlerde zaten var.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.