Genişletme/Ekleme SSS

C’de kendi fonksiyonlarımı oluşturabilir miyim?

Evet, C’de fonksiyonlar, değişkenler, istisnalar ve hatta yeni tipler içeren yerleşik modüller oluşturabilirsiniz. Bu konu Python Yorumlayıcısını Genişletme ve Gömme dosyasında açıklanmıştır.

Çoğu orta veya ileri seviye Python kitabı da bu konuyu ele alacaktır.

C++’da kendi fonksiyonlarımı oluşturabilir miyim?

Evet, C++’da bulunan C uyumluluk özelliklerini kullanarak. extern "C" { ... } komutunu Python include dosyalarının etrafına yerleştirin ve Python yorumlayıcısı tarafından çağrılacak her fonksiyonun önüne extern "C" koyun. Yapıcıları olan global veya statik C++ nesneleri muhtemelen iyi bir fikir değildir.

C yazmak zor; başka alternatifler var mı?

Ne yapmaya çalıştığınıza bağlı olarak, kendi C uzantılarınızı yazmanın bir dizi alternatifi vardır.

Cython and its relative Pyrex are compilers that accept a slightly modified form of Python and generate the corresponding C code. Cython and Pyrex make it possible to write an extension without having to learn Python’s C API.

If you need to interface to some C or C++ library for which no Python extension currently exists, you can try wrapping the library’s data types and functions with a tool such as SWIG. SIP, CXX Boost, or Weave are also alternatives for wrapping C++ libraries.

C’den rastgele Python komutlarını nasıl çalıştırabilirim?

Bunu yapan en üst düzey fonksiyon PyRun_SimpleString() olup, __main__ modülü bağlamında çalıştırılmak üzere tek bir string argüman alır ve başarı için 0, bir istisna oluştuğunda (SyntaxError dahil) -1 döndürür. Daha fazla kontrol istiyorsanız, PyRun_String() kullanın; PyRun_SimpleString() için Python/pythonrun.c içindeki kaynağa bakın.

C’den rastgele Python komutlarını nasıl değerlendirebilirim?

Önceki sorudaki PyRun_String() fonksiyonunu Py_eval_input başlangıç sembolü ile çağırın; bu fonksiyon bir ifadeyi ayrıştırır, değerlendirir ve değerini döndürür.

Bir Python nesnesinden C değerlerini nasıl çıkarabilirim?

That depends on the object’s type. If it’s a tuple, PyTuple_Size() returns its length and PyTuple_GetItem() returns the item at a specified index. Lists have similar functions, PyList_Size() and PyList_GetItem().

For bytes, PyBytes_Size() returns its length and PyBytes_AsStringAndSize() provides a pointer to its value and its length. Note that Python bytes objects may contain null bytes so C’s strlen() should not be used.

Bir nesnenin türünü test etmek için, önce NULL olmadığından emin olun ve ardından PyBytes_Check(), PyTuple_Check(), PyList_Check() vb. kullanın.

Ayrıca Python nesneleri için ‘abstract’ arayüzü tarafından sağlanan üst düzey bir API de vardır – daha fazla ayrıntı için Include/abstract.h dosyasını okuyun. PySequence_Length(), PySequence_GetItem(), vb. gibi çağrıları kullanarak her türlü Python dizisi ile arayüz oluşturmanın yanı sıra sayılar (PyNumber_Index() ve diğerleri) ve PyMapping API’lerindeki eşlemeler gibi diğer birçok yararlı protokolü de sağlar.

İsteğe bağlı uzunlukta bir tuple oluşturmak için Py_BuildValue() işlevini nasıl kullanabilirim?

Bunu yapamazsınız. Bunun yerine PyTuple_Pack() kullanın.

C’de bir nesnenin metodunu nasıl çağırabilirim?

PyObject_CallMethod() fonksiyonu, bir nesnenin rastgele bir metodunu çağırmak için kullanılabilir. Parametreler nesne, çağrılacak yöntemin adı, Py_BuildValue() ile kullanılan gibi bir string ve değişken değerleridir:

PyObject *
PyObject_CallMethod(PyObject *object, const char *method_name,
                    const char *arg_format, ...);

Bu, ister yerleşik ister kullanıcı tanımlı olsun, yöntemleri olan herhangi bir nesne için geçerlidir. Sonunda dönüş değerini :Py_DECREF()‘lemekten siz sorumlusunuz.

Örneğin, bir dosya nesnesinin “seek” yöntemini 10, 0 argümanlarıyla çağırmak için (dosya nesnesi işaretçisinin “f” olduğunu varsayarak):

res = PyObject_CallMethod(f, "seek", "(ii)", 10, 0);
if (res == NULL) {
        ... an exception occurred ...
}
else {
        Py_DECREF(res);
}

PyObject_CallObject() her zaman argüman listesi için bir tuple istediğinden, argümansız bir fonksiyon çağırmak için format olarak “()” ve tek argümanlı bir fonksiyon çağırmak için argümanı parantez içine alın, örneğin “(i)”.

PyErr_Print() işlevinden (veya stdout/stderr’e yazdıran herhangi bir şeyden) gelen çıktıyı nasıl yakalayabilirim?

Python kodunda, write() metodunu destekleyen bir nesne tanımlayın. Bu nesneyi sys.stdout ve sys.stderr öğelerine atayın. Print_error’ı çağırın ya da sadece standart geri izleme mekanizmasının çalışmasına izin verin. Ardından, çıktı write() yönteminizin gönderdiği yere gidecektir.

Bunu yapmanın en kolay yolu io.StringIO sınıfını kullanmaktır:

>>> import io, sys
>>> sys.stdout = io.StringIO()
>>> print('foo')
>>> print('hello world!')
>>> sys.stderr.write(sys.stdout.getvalue())
foo
hello world!

Aynı şeyi yapan özel bir nesne şöyle görünecektir:

>>> import io, sys
>>> class StdoutCatcher(io.TextIOBase):
...     def __init__(self):
...         self.data = []
...     def write(self, stuff):
...         self.data.append(stuff)
...
>>> import sys
>>> sys.stdout = StdoutCatcher()
>>> print('foo')
>>> print('hello world!')
>>> sys.stderr.write(''.join(sys.stdout.data))
foo
hello world!

Python’da yazılmış bir modüle C’den nasıl erişebilirim?

Modül nesnesine aşağıdaki gibi bir işaretçi alabilirsiniz:

module = PyImport_ImportModule("<modulename>");

Modül henüz içe aktarılmamışsa (yani sys.modules içinde henüz mevcut değilse), bu modülü başlatır; aksi takdirde sadece sys.modules["<modulename>"] değerini döndürür. Modülü herhangi bir isim alanına girmediğine dikkat edin – sadece başlatıldığından ve sys.modules içinde saklandığından emin olur.

Daha sonra modülün özniteliklerine (yani modülde tanımlanan herhangi bir isme) aşağıdaki şekilde erişebilirsiniz:

attr = PyObject_GetAttrString(module, "<attrname>");

Modüldeki değişkenlere atamak için PyObject_SetAttrString() çağrısı da çalışır.

Python’dan C++ nesnelerine nasıl arayüz oluşturabilirim?

Gereksinimlerinize bağlı olarak, birçok yaklaşım vardır. Bunu manuel olarak yapmak için the “Extending and Embedding” belgesini okuyarak başlayın. Python çalışma zamanı sistemi için, C ve C++ arasında çok fazla fark olmadığının farkına varın – bu nedenle bir C yapı (işaretçi) türü etrafında yeni bir Python türü oluşturma stratejisi C++ nesneleri için de işe yarayacaktır.

C++ kütüphaneleri için bakınız C yazmak zor; başka alternatifler var mı?.

Kurulum dosyasını kullanarak bir modül ekledim ve derleme başarısız oldu; neden?

Kurulum bir satır sonu ile bitmelidir, eğer satır sonu yoksa derleme işlemi başarısız olur. (Bunu düzeltmek için biraz biçimsiz shell script düzenlemesi gerekir ve bu hata o kadar küçük ki çabaya değmez gibi görünüyor)

Bir uzantıda nasıl hata ayıklayabilirim?

Dinamik olarak yüklenen uzantılarla GDB kullanırken, uzantınız yüklenene kadar uzantınızda bir kesme noktası ayarlayamazsınız.

.gdbinit dosyanıza (veya etkileşimli olarak) şu komutu ekleyin:

br _PyImport_LoadDynamicModule

Sonra, GDB’yi çalıştırdığınızda:

$ gdb /local/bin/python
gdb) run myscript.py
gdb) continue # repeat until your extension is loaded
gdb) finish   # so that your extension is loaded
gdb) br myfunction.c:50
gdb) continue

Linux sistemimde bir Python modülü derlemek istiyorum, ancak bazı dosyalar eksik. Neden?

Python’un paketlenmiş sürümlerinin çoğu, Python uzantılarını derlemek için gerekli çeşitli dosyaları içeren /usr/lib/python2.x/config/ dizinini içermez.

Red Hat için, gerekli dosyaları almak için python-devel RPM yükleyin.

Debian için apt-get install python-dev komutunu çalıştırın.

“Eksik girdi” ile “geçersiz girdi’yi nasıl ayırt edebilirim?

Bazen Python etkileşimli yorumlayıcısının davranışını taklit etmek istersiniz; girdi eksik olduğunda size bir devam istemi verir (örneğin, bir “if” deyiminin başlangıcını yazdınız veya parantezlerinizi veya üçlü dize tırnaklarınızı kapatmadınız), ancak girdi geçersiz olduğunda size hemen bir sözdizimi hata mesajı verir.

Python’da, ayrıştırıcının davranışına yeterince yaklaşan codeop modülünü kullanabilirsiniz. Örneğin IDLE bunu kullanır.

Bunu C’de yapmanın en kolay yolu PyRun_InteractiveLoop() çağırmak (belki ayrı bir iş parçacığında) ve Python yorumlayıcısının girdiyi sizin için işlemesine izin vermektir. Ayrıca PyOS_ReadlineFunctionPointer() ‘ı özel girdi fonksiyonunuza işaret edecek şekilde ayarlayabilirsiniz. Daha fazla ipucu için Modules/readline.c ve Parser/myreadline.c dosyalarına bakın.

Tanımlanmamış g++ sembolleri __builtin_new veya __pure_virtual’ı nasıl bulabilirim?

G++ uzantı modüllerini dinamik olarak yüklemek için Python’u yeniden derlemeli, g++ kullanarak yeniden bağlamalı (Python Modules Makefile’da LINKCC’yi değiştirin) ve uzantı modülünüzü g++ kullanarak bağlamalısınız (örneğin, g++ -shared -o mymodule.so mymodule.o).

Bazı yöntemleri C’de, bazı yöntemleri Python’da (örneğin miras yoluyla) uygulanan bir nesne sınıfı oluşturabilir miyim?

Evet, int, list, dict, vb. gibi yerleşik sınıflardan miras alabilirsiniz.

Boost Python Kütüphanesi (BPL, http://www.boost.org/libs/python/doc/index.html) bunu C++’dan yapmanın bir yolunu sağlar (yani BPL’yi kullanarak C++’da yazılmış bir uzantı sınıfından miras alabilirsiniz).