Libraries

Dr Andy Evans

[Fullscreen]

Review

  • We've seen that a module is a file that can contain classes as well as its own variables.
  • We've seen that you need to import it to access the code, and then use the module name to refer to it.
    import module1
    a = module1.ClassName()

Packages

  • modules: usually single files to do some set of jobs
  • packages: modules with a namespace, that is, a unique way of referring to them
  • libraries: a generic name for a collection of code you can use to get specific types of job done.

Packages

  • The Standard Python Library comes with a number of other packages which are not imported automatically.
  • We need to import them to use them.

Import

  • How to import:
    import agentframework
    point_1 = agentframework.Agent()
  • This is a very explicit style. There is little ambiguity about which Agent we are after (if other imported modules have Agent classes).
  • This is safest as you have to be explicit about the module. Provided there aren't two modules with the same name and class, you are fine.
  • If you're sure there are no other Agent, you can:
    from agentframework import Agent
    point_1 = Agent()
    This just imports this one class.

NB

  • You will often see imports of everything in a module:
    from agentframework import *
  • This is easy, because it saves you having to import multiple classes, but it is dangerous: you have no idea what other classes are in there that might replace classes you have imported elsewhere.
  • In other languages, with, frankly better, documentation and file structures, it is easy to find out which classes are in libraries, so you see this a lot.
  • In Python, it is strongly recommended you don't do this. If you get code from elsewhere, change these to explicit imports.

As

  • If the module name is very long (it shouldn't be), you can do this:
    import agentbasedmodellingframework as abm
    agent_1 = abm.Agent()
  • If the classname is very long, you can:
    from abm import AgentsRepresentingPeople as Ag
    agent_1 = Ag()
  • Some people like this, but it does make the code harder to understand.
  • When importing, Python will import parent packages (but not other subpackages)
  • If hasn't been used before, will search import path, which is usually (but not exclusively) the system path.
  • If you're importing a package, don't have files with the same name (i.e. package_name.py) in the directory you're in, or they'll be imported rather than the package (even if you're inside them).

Interpreter

  • To reload a module:
    import importlib
    importlib.reload(modulename)
  • In Spyder, just re-run the module file. Remember to do this if you update it.

Modules and Packages

  • Modules are single files that can contain multiple classes, variables, and functions.
  • The main difference when thinking of module and scripts is that the former is generally imported, and the latter generally runs directly.
  • Packages are collections of modules structured using a directory tree.

Running module code

  • Although we've concentrated on classes, you can import and run module-level functions, and access variables.
    import module1
    print(module1.module_variable)

    module1.module_function()
    a = module1.ClassName()

Importing modules

  • Indeed, you have to be slightly careful when importing modules. Modules and the classes in them will run to a degree on import. Modules run incase there's anything that needs setting up (variables etc.) prior to functions or classes.
    # module
    print ("module loading") # Runs

    def m1():
        print ("method loading")

    class cls:
        print ("class loading") # Runs
        def m2():
            print("instance method loading")

Modules that run

  • If you're going to use this to run code, note that in general, code accessing a class or method has to be after if is defined:
    c = A()
    c.b()
    class A:
        def b (__self__) :
            print ("hello world")
  • Doesn't work, but:
    class A:
        def b (__self__) :
            print ("hello world")
    c = A()
    c.b()
    does.

Modules that run

  • This doesn't count for imported code. This works fine because the files has been scanned down to c= A() before it runs, so all the methods are recognised.
    class A:

        def __init__ (self):
            self.b()

        def b (self) :
            print ("hello world")

    -------------------------------

    c = A()

Modules that run

  • However, generally having large chunks of unnecessary code running is bad.
  • Setting up variables is usually ok, as assignment generally doesn't cause issues.
  • Under the philosophy of encapsulation, however, we don't really want code slooping around outside of methods/functions. The core encapsulation level for Python are the function and objects (with self; not the class).
  • It is therefore generally worth minimising this code.

Running a module

  • The best option is to have a 'double headed' file, that runs as a script with isolated code, but can also run as a module. As scripts run with a global __name__ variable in the runtime set to "__main__", the following code in a module will allow it to run either way without contamination.
    if __name__ == "__main__":
        # Imports needed for running.
        function_name()

Packages

  • Structure that constructs a dot delimited namespace based around a directory structure.
/abm
    __init__.py
    /general
        __init__.py
        agentframework.py
    /models
        __init__.py
        model.py
  • The __init__.py can be empty. They allow Python to recognise that the subdirectories are sub-packages. You can now:
    import abm.general.agentframework.Agent
    etc.
  • The base __init__.py can also include, e.g.
    __all__ = ["models", "general"]
    Which means that this will work:
    from abm import *
    If you want it to.

Running a package

  • Packages can be run by placing the startup code in a file called __main__.py
  • This could, for example use command line args to determine which model to run.
  • This will run if the package is run in this form:
    python -m packagename
    Relatively trivial to include a bat or sh file to run this.

Package Advantages

  • Structured approach, rather than having everything in one file.
  • Allows files to import each other without being limited to same directory.
  • Can set up the package to work together as an application.
  • The more detailed the namespace (e.g. including unique identifiers) the less likely your identifiers (classnames; function names; variables) are to clash with someone else's.