pythonctypes

What is the difference between ctypes.CDLL() and ctypes.cdll.LoadLibrary()?


Both methods seem to work (for me), but it seems the CDLL() method returns an object that has a _handle attribute, which can be used to unload the library via ctypes.windll.kernel32.FreeLibrary() (at least on Windows - I don't yet know how to do that on Linux).

What are the differences between these two methods - why would I choose one over the other?

Ultimately, my goal is to be able to load and unload libraries on both Windows on Linux (because I have a 3rd party library that seems to get into a broken state sometimes - I'm hoping unloading/reloading will reset it).


Solution

  • Everything is well explained in [Python.Docs]: ctypes - A foreign function library for Python:

    class ctypes.CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=0)
           Instances of this class represent loaded shared libraries. Functions in these libraries use the standard C calling convention, and are assumed to return int.

    ...

    class ctypes.LibraryLoader(dlltype)

    ...

    LoadLibrary(name)
          Load a shared library into the process and return it. This method always returns a new instance of the library.

    These prefabricated library loaders are available:

    ctypes.cdll
          Creates CDLL instances.

    As seen, the 2nd form is just a convenience wrapper over the 1st. Note that it loses any possible customizations - done via arguments (e.g.: use_errno). Check [SO]: Can't import dll module in Python (@CristiFati's answer) to see different behaviors that can be achieved by tuning the arguments.
    So, (if using 1st form default argument values) there's absolutely no functional difference between them, as shown below:

    Use whatever suits you best.
    2nd form (#2.2.) is shorter (I suppose this is its purpose).
    #1. and #2.1. are (almost) the same (#1. allows customizations, while #2.1. is probably more explanatory (as it has LoadLibrary)) and they allow you to load a library from a custom path, or with an extension different than the default.
    Personally, #1. is the one I prefer (as it's the most complete).

    For more details, you can take a look at [GitHub]: python/cpython - (master) cpython/Lib/ctypes/__init__.py, especially the LibraryLoader at implementation which (cdll actually is, and) is easy to understand.

    Just a heads-up (probably you already know what you're getting into): loading and unloading libraries can sometimes be tricky:

    You might also want to check [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer) for a common pitfall encountered when calling functions via CTypes.