On 26Nov2017 01:09, Greg Tibbet <gtibbe...@msn.com> wrote: >I've got a small program that uses PIL to create an image, draw some >primitives (rectanges, ellipses, etc...) and save it. Works fine... >no issues. > >I've found in the past, the best way to "really learn" the language >was to "dig into the guts" and understand it,.. I thought I was making >progress, but when looking into the PIL library to see what's going on >behind the scenes, I find the following code in ImageDraw.py > >def ellipse(self, xy, fill=None, outline=None): > """Draw an ellipse.""" > ink, fill = self._getink(outline, fill) > if fill is not None: > self.draw.draw_ellipse(xy, fill, 1) ><...snipped...> > >ellipse() uses the method self.draw.draw_ellipse() Okay, fine... >but WHERE is draw_ellipse defined?? What magic is happening there? >I've searched the entire PIL directory tree, and the ONLY two places >draw_ellipse is mentioned are right there in the ellipse() function... >WHAT am I missing??
"ellispse()" is a method in the ImageDraw class. Looking at the __init__ method of that class we see: self.draw = Image.core.draw(self.im, blend) so "self.draw" in your code above is the result of "Image.core.draw(self.im, blend)". "Image" is the Image module imported at the top of ImageDraw.py. So we hop over to Image.py, which has this code: try: # If the _imaging C module is not present, you can still use # the "open" function to identify files, but you cannot load # them. Note that other modules should not refer to _imaging # directly; import Image and use the Image.core variable instead. import _imaging core = _imaging del _imaging except ImportError, v: core = _imaging_not_installed() if str(v)[:20] == "Module use of python" and warnings: # The _imaging C module is present, but not compiled for # the right version (windows only). Print a warning, if # possible. warnings.warn( "The _imaging extension was built for another version " "of Python; most PIL functions will be disabled", RuntimeWarning ) Now the import works (because you'd get exceptions otherwise), so code which matters is that the top of that: import _imaging core = _imaging del _imaging So "core" is a reference to the "_imaging" module (and the name "_imaging" has been discarded). So... The name Image.core is now a reference to that module. So back in ImageDraw, the call to "Image.core.draw()" called the function "draw" from the _imaging module, which presumably returns some kind of drawing object, and _that_ object has a "draw_ellispe" method. Now, dynamic languages like Python don't lend themselves to screamingly fast compute, so expensive stuff like drawing graphics is usually done by hooking into special purpose libraries written in C or something that compiles to efficient machine level code (C++, Go, what have you). You can ship C code with Python to be compiled on the target and presented to Python as a library, and by convention such modules are named with a leading underscore. So we can expect that _imaging is a C code module. And if you go up a level you'll find _imaging.c, with a draw_ellipse function inside it. Cheers, Cameron Simpson <c...@cskk.id.au> (formerly c...@zip.com.au) -- https://mail.python.org/mailman/listinfo/python-list