[C++-sig] Re: Presenting a Python embedding tutorial for Boost.Python
Dirk Gerrits
dirk at gerrits.homeip.net
Tue Dec 10 18:47:47 CET 2002
David Abrahams wrote:
> Dirk Gerrits <dirk at gerrits.homeip.net> writes:
>
>
>>David Abrahams wrote:
>
>
>>>I also confess to not having any idea what piece of code you're
>>>talking about ;-)
>>
>>The two code examples in the manual reference counting section. ;)
>
>
> Ah. It's really good to have that section somewhere in the tutorial or
> maybe in the rationale documentation, to show why you want a C++
> wrapper over the 'C' API.
Then I shall compress it so that it can become a sidebar or a part of
the rationale. With the upcoming embedding features of Boost.Python I
would really prefer not to document both the 'C'-way and the BPL-way of
doing everything. ;)
>>>See also http://www.mcmillan-inc.com/embed.html, FWIW.
>>
>>Thanks for the link. Taught me two things:
>>1) Any sane person will prefer Boost.Python over the Python C API ;)
>>2) It is possible to create multiple interpreters, even in different
>>threads. This could lead to a very cool python::interpreter class
>>indeed. :)
>
>
> That's a neat idea. I await your specific interface suggestions.
Well nothing concrete so far but I think you'll agree that the
constructor and destructor are the most vital parts of the class. They
do practically all the work of setting up/release (sub-)interpreters.
Furthermore, there should be a way to set/query the currently active
interpreter. Member functions like this:
bool is_current() const;
void make_current();
were the first things that came to mind.
I also thought about a free function along the lines of:
interpreter* current_interpreter();
But that would only make sense if the public class interface is
expanded. After all, is_current() on the current_interpreter() is always
true and make_current() is always a no-op, right? (Also, it would
probably not work too well with threading maybe?)
A pseudo-implementation of the constructor and destructor could look like:
interpreter()
{
// Create the main interpreter
if (interpreter_count == 0)
{
Py_Initialize();
...
}
// Create a sub-interpreter
else
{
...
}
interpreter_count++;
}
~interpreter()
{
// Release the main interpreter
if (interpreter_count == 1)
{
Py_Finalize();
...
}
// Release a sub-interpreter
else
{
...
}
interpreter_count--;
}
... treating the main interpreter and sub-interpreters equally as
python::interpreter instances. I'm not sure if this is the best solution
though, because there are some (very) subtle differences between the
main interpreter and sub-interpreters.
(http://www.python.org/doc/current/api/initialization.html#l2h-657)
Not making the distinction seems more natural though. ("Beautiful is
better than ugly." "Simple is better than complex." ;))
>>>>However, adding Boost.Python facilities for the PyRun_ functions
>>>>probably means adding a load of other Python C API facilites as
>>>>well.
>>
>>>Yup. It was always the intention to add these. Dave Hawkes made a
>>>valiant effort:
>>>http://mail.python.org/pipermail/c++-sig/2002-June/001503.html, but it
>>>was in some ways just too much to take into the library at once.
>>
>>I see. Pity. Let's see how the incremental approach will fare.
>
>
>
> OK!
>
> For reference you might want to look at Dave's work. I've attached
> a CVS log | cvslogfilter -b of his checkins at the bottom of the
> message.
Thanks. Downloaded the files to my harddrive for future reference. :)
>>>>I would like to have something like this in Boost.Python:
>>>>
>>>>object run_python_code(InputIterator begin, InputIterator end);
>>>
>>>These must have char as their value_type?
>>
>>I suppose so. At least I don't see any unicode/wchar_t in the Python C
>>API. ;) I was under the impression that Python supported unicode
>>source files though. How does that work then?
>
>
> Search me!
Searched for unicode (7 hits), wchar_t (no hits) and utf-8 (1 hit) on
the C++ Sig archive on ASPN but couldn't find it, sorry.
>>Also, while this interface is nicely STL-ish, it is probably not very
>>efficient. I don't see how this can be implemented without some
>>std::copy to std::vector<char> or std::string. Thoughts?
>
>
> I don't know. Based on your remarks I'm guessing that the interface is
> a case of premature generalization. Suppose we just do this:
>
> object run_python_code(object x);
>
> template <class T>
> object run_python_code(T const& x)
> {
> return run_python_code(object(x));
> }
>
> ??
>
> Now anything that can be converted to a Python string will work. Just
> a thought.
FWIW, I like it. :)
I think though that running code from a file would be at least as
important as running it from a string. So the implementation of
run_python_code (name might need work?) should IMHO check to see if x is
(convertable to) a Python file. If so, then it should use PyRun_File
with a FILE*, otherwise it should use PyRun_String with a char const*.
>>>>Also, it might be a good idea to wrap Py_Initialize and Py_Finalize in
>>>>a RAII class?
>>
>>>Absolutely. Just as soon as Py_Finalize becomes safe for us ;-)
>>>That might be a good project for you...
>>
>>I've been meaning to look into BPL's internals in more detail
>>anyway. :) I'm not sure if university will leave me with enough spare
>>time though. I think I should concentrate on the tutorial first.
>
>
> OK. BTW, this is not a hard problem to solve and it doesn't require a
> deep understanding of the internals. The first step is to identify all
> the places where static/global object or handle<> instances are
> created in the library or user code. There is also some global data in
> the registry. Then we'll need to set up some code for releasing the
> resources with Python's atexit() module.
Doesn't sound too hard. I'll get on it when I see the time (probably in
the weekend). Perhaps somebody reading this thread will beat me to it
though. ;)
Dirk Gerrits
More information about the Cplusplus-sig
mailing list