# Genişletme/Ekleme SSS

İçerikler

- Genişletme/Ekleme SSS

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

## 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).