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 Extending and
Embedding the Python Interpreter 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?
=========================================================

Bu, nesnenin türüne bağlıdır.  Eğer bir tuple ise, "PyTuple_Size()"
uzunluğunu döndürür ve "PyTuple_GetItem()" belirtilen indeksteki öğeyi
döndürür.  Listelerin de benzer fonksiyonları vardır, "PyListSize()"
ve "PyList_GetItem()".

Baytlar için, "PyBytes_Size()" uzunluğunu döndürür ve
"PyBytes_AsStringAndSize()" değerine ve uzunluğuna bir işaretçi
sağlar.  Python bayt nesnelerinin null bayt içerebileceğini unutmayın,
bu nedenle C'nin "strlen()" özelliği kullanılmamalıdır.

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.

However sometimes you have to run the embedded Python interpreter in
the same thread as your rest application and you can't allow the
"PyRun_InteractiveLoop()" to stop while waiting for user input.  The
one solution then is to call "PyParser_ParseString()" and test for
"e.error" equal to "E_EOF", which means the input is incomplete.
Here's a sample code fragment, untested, inspired by code from Alex
Farber:

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>
   #include <node.h>
   #include <errcode.h>
   #include <grammar.h>
   #include <parsetok.h>
   #include <compile.h>

   int testcomplete(char *code)
     /* code should end in \n */
     /* return -1 for error, 0 for incomplete, 1 for complete */
   {
     node *n;
     perrdetail e;

     n = PyParser_ParseString(code, &_PyParser_Grammar,
                              Py_file_input, &e);
     if (n == NULL) {
       if (e.error == E_EOF)
         return 0;
       return -1;
     }

     PyNode_Free(n);
     return 1;
   }

Another solution is trying to compile the received string with
"Py_CompileString()". If it compiles without errors, try to execute
the returned code object by calling "PyEval_EvalCode()". Otherwise
save the input for later. If the compilation fails, find out if it's
an error or just more input is required - by extracting the message
string from the exception tuple and comparing it to the string
"unexpected EOF while parsing".  Here is a complete example using the
GNU readline library (you may want to ignore **SIGINT** while calling
readline()):

   #include <stdio.h>
   #include <readline.h>

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>
   #include <object.h>
   #include <compile.h>
   #include <eval.h>

   int main (int argc, char* argv[])
   {
     int i, j, done = 0;                          /* lengths of line, code */
     char ps1[] = ">>> ";
     char ps2[] = "... ";
     char *prompt = ps1;
     char *msg, *line, *code = NULL;
     PyObject *src, *glb, *loc;
     PyObject *exc, *val, *trb, *obj, *dum;

     Py_Initialize ();
     loc = PyDict_New ();
     glb = PyDict_New ();
     PyDict_SetItemString (glb, "__builtins__", PyEval_GetBuiltins ());

     while (!done)
     {
       line = readline (prompt);

       if (NULL == line)                          /* Ctrl-D pressed */
       {
         done = 1;
       }
       else
       {
         i = strlen (line);

         if (i > 0)
           add_history (line);                    /* save non-empty lines */

         if (NULL == code)                        /* nothing in code yet */
           j = 0;
         else
           j = strlen (code);

         code = realloc (code, i + j + 2);
         if (NULL == code)                        /* out of memory */
           exit (1);

         if (0 == j)                              /* code was empty, so */
           code[0] = '\0';                        /* keep strncat happy */

         strncat (code, line, i);                 /* append line to code */
         code[i + j] = '\n';                      /* append '\n' to code */
         code[i + j + 1] = '\0';

         src = Py_CompileString (code, "<stdin>", Py_single_input);

         if (NULL != src)                         /* compiled just fine - */
         {
           if (ps1  == prompt ||                  /* ">>> " or */
               '\n' == code[i + j - 1])           /* "... " and double '\n' */
           {                                               /* so execute it */
             dum = PyEval_EvalCode (src, glb, loc);
             Py_XDECREF (dum);
             Py_XDECREF (src);
             free (code);
             code = NULL;
             if (PyErr_Occurred ())
               PyErr_Print ();
             prompt = ps1;
           }
         }                                        /* syntax error or E_EOF? */
         else if (PyErr_ExceptionMatches (PyExc_SyntaxError))
         {
           PyErr_Fetch (&exc, &val, &trb);        /* clears exception! */

           if (PyArg_ParseTuple (val, "sO", &msg, &obj) &&
               !strcmp (msg, "unexpected EOF while parsing")) /* E_EOF */
           {
             Py_XDECREF (exc);
             Py_XDECREF (val);
             Py_XDECREF (trb);
             prompt = ps2;
           }
           else                                   /* some other syntax error */
           {
             PyErr_Restore (exc, val, trb);
             PyErr_Print ();
             free (code);
             code = NULL;
             prompt = ps1;
           }
         }
         else                                     /* some non-syntax error */
         {
           PyErr_Print ();
           free (code);
           code = NULL;
           prompt = ps1;
         }

         free (line);
       }
     }

     Py_XDECREF(glb);
     Py_XDECREF(loc);
     Py_Finalize();
     exit(0);
   }


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.

The Boost Python Library (BPL,
http://www.boost.org/libs/python/doc/index.html) provides a way of
doing this from C++ (i.e. you can inherit from an extension class
written in C++ using the BPL).
