]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | =================================== |
2 | Boost.Python_ Internals |(logo)|__ | |
3 | =================================== | |
4 | ||
5 | .. |(logo)| image:: ../../../boost.png | |
6 | :alt: Boost | |
7 | :class: boost-logo | |
8 | ||
9 | __ ../../../index.htm | |
10 | ||
11 | .. _`Boost.Python`: index.html | |
12 | ||
13 | .. _license: ../../../LICENSE_1_0.txt | |
14 | ||
15 | ||
16 | ------------------------------------------------------- | |
17 | A conversation between Brett Calcott and David Abrahams | |
18 | ------------------------------------------------------- | |
19 | ||
20 | :copyright: Copyright David Abrahams and Brett Calcott 2003. See | |
21 | accompanying license_ for terms of use. | |
22 | ||
23 | In both of these cases, I'm quite capable of reading code - but the | |
24 | thing I don't get from scanning the source is a sense of the | |
25 | architecture, both structurally, and temporally (er, I mean in what | |
26 | order things go on). | |
27 | ||
28 | 1) What happens when you do the following:: | |
29 | ||
30 | struct boring {}; | |
31 | ...etc... | |
32 | class_<boring>("boring") | |
33 | ; | |
34 | ||
35 | There seems to be a fair bit going on. | |
36 | ||
37 | - Python needs a new ClassType to be registered. | |
38 | - We need to construct a new type that can hold our boring struct. | |
39 | - Inward and outward converters need to be registered for the type. | |
40 | ||
41 | Can you gesture in the general direction where these things are done? | |
42 | ||
43 | I only have time for a "off-the-top-of-my-head" answer at the moment; | |
44 | I suggest you step through the code with a debugger after reading this | |
45 | to see how it works, fill in details, and make sure I didn't forget | |
46 | anything. | |
47 | ||
48 | A new (Python) subclass of Boost.Python.Instance (see | |
49 | libs/python/src/object/class.cpp) is created by invoking | |
50 | Boost.Python.class, the metatype:: | |
51 | ||
52 | >>> boring = Boost.Python.class( | |
53 | ... 'boring' | |
54 | ... , bases_tuple # in this case, just () | |
55 | ... , { | |
56 | ... '__module__' : module_name | |
57 | ... , '__doc__' : doc_string # optional | |
58 | ... } | |
59 | ... ) | |
60 | ||
61 | A handle to this object is stuck in the m_class_object field | |
62 | of the registration associated with ``typeid(boring)``. The | |
63 | registry will keep that object alive forever, even if you | |
64 | wipe out the 'boring' attribute of the extension module | |
65 | (probably not a good thing). | |
66 | ||
67 | Because you didn't specify ``class<boring, non_copyable, | |
68 | ...>``, a to-python converter for boring is registered which | |
69 | copies its argument into a value_holder held by the the | |
70 | Python boring object. | |
71 | ||
72 | Because you didn't specify ``class<boring ...>(no_init)``, | |
73 | an ``__init__`` function object is added to the class | |
74 | dictionary which default-constructs a boring in a | |
75 | value_holder (because you didn't specify some smart pointer | |
76 | or derived wrapper class as a holder) held by the Python | |
77 | boring object. | |
78 | ||
79 | ``register_class_from_python`` is used to register a | |
80 | from-python converter for ``shared_ptr<boring>``. | |
81 | ``boost::shared_ptr``\ s are special among smart pointers | |
82 | because their Deleter argument can be made to manage the | |
83 | whole Python object, not just the C++ object it contains, no | |
84 | matter how the C++ object is held. | |
85 | ||
86 | If there were any ``bases<>``, we'd also be registering the | |
87 | relationship between these base classes and boring in the | |
88 | up/down cast graph (``inheritance.[hpp/cpp]``). | |
89 | ||
90 | In earlier versions of the code, we'd be registering lvalue | |
91 | from-python converters for the class here, but now | |
92 | from-python conversion for wrapped classes is handled as a | |
93 | special case, before consulting the registry, if the source | |
94 | Python object's metaclass is the Boost.Python metaclass. | |
95 | ||
96 | Hmm, that from-python converter probably ought to be handled | |
97 | the way class converters are, with no explicit conversions | |
98 | registered. | |
99 | ||
100 | 2) Can you give a brief overview of the data structures that are | |
101 | present in the registry | |
102 | ||
103 | The registry is simple: it's just a map from typeid -> | |
104 | registration (see boost/python/converter/registrations.hpp). | |
105 | ``lvalue_chain`` and ``rvalue_chain`` are simple endogenous | |
106 | linked lists. | |
107 | ||
108 | If you want to know more, just ask. | |
109 | ||
110 | If you want to know about the cast graph, ask me something specific in | |
111 | a separate message. | |
112 | ||
113 | and an overview of the process that happens as a type makes its | |
114 | way from c++ to python and back again. | |
115 | ||
116 | Big subject. I suggest some background reading: look for relevant | |
117 | info in the LLNL progress reports and the messages they link to. | |
118 | Also, | |
119 | ||
120 | http://mail.python.org/pipermail/c++-sig/2002-May/001023.html | |
121 | ||
122 | http://mail.python.org/pipermail/c++-sig/2002-December/003115.html | |
123 | ||
124 | http://aspn.activestate.com/ASPN/Mail/Message/1280898 | |
125 | ||
126 | http://mail.python.org/pipermail/c++-sig/2002-July/001755.html | |
127 | ||
128 | from c++ to python: | |
129 | ||
130 | It depends on the type and the call policies in use or, for | |
131 | ``call<>(...)``, ``call_method<>(...)``, or ``object(...)``, if | |
132 | ``ref`` or ``ptr`` is used. There are also two basic | |
133 | categories to to-python conversion, "return value" conversion | |
134 | (for Python->C++ calls) and "argument" conversion (for | |
135 | C++->Python calls and explicit ``object()`` conversions). The | |
136 | behavior of these two categories differs subtly in various ways | |
137 | whose details I forget at the moment. You can probably find | |
138 | the answers in the above references, and certainly in the code. | |
139 | ||
140 | The "default" case is by-value (copying) conversion, which uses | |
141 | to_python_value as a to-python converter. | |
142 | ||
143 | Since there can sensibly be only one way to convert any type | |
144 | to python (disregarding the idea of scoped registries for the | |
145 | moment), it makes sense that to-python conversions can be | |
146 | handled by specializing a template. If the type is one of | |
147 | the types handled by a built-in conversion | |
148 | (builtin_converters.hpp), the corresponding template | |
149 | specialization of to_python_value gets used. | |
150 | ||
151 | Otherwise, to_python_value uses the ``m_to_python`` | |
152 | function in the registration for the C++ type. | |
153 | ||
154 | Other conversions, like by-reference conversions, are only | |
155 | available for wrapped classes, and are requested explicitly by | |
156 | using ``ref(...)``, ``ptr(...)``, or by specifying different | |
157 | CallPolicies for a call, which can cause a different to-python | |
158 | converter to be used. These conversions are never registered | |
159 | anywhere, though they do need to use the registration to find | |
160 | the Python class corresponding to the C++ type being referred | |
161 | to. They just build a new Python instance and stick the | |
162 | appropriate Holder instance in it. | |
163 | ||
164 | ||
165 | from python to C++: | |
166 | ||
167 | Once again I think there is a distinction between "return value" | |
168 | and "argument" conversions, and I forget exactly what that is. | |
169 | ||
170 | What happens depends on whether an lvalue conversion is needed | |
171 | (see http://mail.python.org/pipermail/c++-sig/2002-May/001023.html) | |
172 | All lvalue conversions are also registered in a type's rvalue | |
173 | conversion chain, since when an rvalue will do, an lvalue is | |
174 | certainly good enough. | |
175 | ||
176 | An lvalue conversion can be done in one step (just get me the | |
177 | pointer to the object - it can be ``NULL`` if no conversion is | |
178 | possible) while an rvalue conversion requires two steps to | |
179 | support wrapped function overloading and multiple converters for | |
180 | a given C++ target type: first tell me if a conversion is | |
181 | possible, then construct the converted object as a second step. | |
182 |