paul@44 | 1 | Micropython: A minimal implementation of Python for constrained devices
|
paul@44 | 2 |
|
paul@153 | 3 | * "Full strength" Python:
|
paul@153 | 4 | * Introspection, interactivity, PEP/reference-compliance
|
paul@153 | 5 | * CPython, Jython, IronPython, PyPy, CLPython, etc.
|
paul@153 | 6 | * "Reduced strength" Python:
|
paul@153 | 7 | * Remove "luxury" semantics
|
paul@153 | 8 | * Shed Skin, RPython, etc.
|
paul@44 | 9 |
|
paul@44 | 10 | Motivations
|
paul@44 | 11 |
|
paul@44 | 12 | * Run Python programs in "small" devices
|
paul@94 | 13 | * Small programs plus few executed instructions
|
paul@94 | 14 | * Avoid expensive library code
|
paul@94 | 15 | (small footprint, lots of executed instructions)
|
paul@44 | 16 |
|
paul@44 | 17 | Python's flexibility comes at a cost
|
paul@44 | 18 |
|
paul@44 | 19 | * Modules, classes, instances are all objects
|
paul@44 | 20 | * Freedom to modify most objects at any time
|
paul@44 | 21 | * Difficult to predict eventual behaviour before execution
|
paul@44 | 22 | * Difficult to generate optimisations when compiling
|
paul@44 | 23 |
|
paul@94 | 24 | Not all things are dynamic/equal in Python
|
paul@94 | 25 |
|
paul@94 | 26 | * Locals, modules and classes are special in some way
|
paul@94 | 27 | * Locals don't tend to change unilaterally
|
paul@153 | 28 | * Parameter lists don't tend to change if fully specified
|
paul@94 | 29 | * Modules usually retain their identity
|
paul@94 | 30 | * Classes differ from objects (despite metaclasses)
|
paul@94 | 31 |
|
paul@44 | 32 | Attribute access
|
paul@44 | 33 |
|
paul@44 | 34 | * Must do a full lookup every time:
|
paul@44 | 35 | * Check instance dictionary
|
paul@44 | 36 | * Check class, superclasses
|
paul@44 | 37 | * Potentially lots of code
|
paul@44 | 38 | * Lots of executed instructions
|
paul@44 | 39 |
|
paul@62 | 40 | Improving attribute access performance
|
paul@62 | 41 |
|
paul@62 | 42 | * Achieve faster access using a different representation
|
paul@62 | 43 | * Must define attributes of objects in advance
|
paul@62 | 44 | * Restriction: modules, classes, instances are "closed"
|
paul@62 | 45 | * Evaluate the limitations: are they too disruptive?
|
paul@62 | 46 |
|
paul@62 | 47 | Consequences of revised attribute access
|
paul@62 | 48 |
|
paul@94 | 49 | * Cannot extend the range of attributes on objects of existing classes
|
paul@62 | 50 | * Further optimisations:
|
paul@62 | 51 | * Restriction: attempt to control modification of attributes
|
paul@62 | 52 | * Result: further optimisation of accesses
|
paul@62 | 53 |
|
paul@62 | 54 | Invocations
|
paul@62 | 55 |
|
paul@62 | 56 | * Target checking
|
paul@62 | 57 | * Number of arguments vs. number of parameters
|
paul@62 | 58 | * Keyword parameter resolution
|
paul@62 | 59 | * Defaults
|
paul@62 | 60 |
|
paul@44 | 61 | Other costly operations
|
paul@44 | 62 |
|
paul@44 | 63 | * Binary operators
|
paul@44 | 64 | * Comparisons
|
paul@44 | 65 |
|
paul@44 | 66 | Examples of rarely used/unnecessary flexibility
|
paul@44 | 67 |
|
paul@44 | 68 | * Can subclass dynamically:
|
paul@44 | 69 |
|
paul@44 | 70 | for cls in A, B:
|
paul@44 | 71 | class C(cls):
|
paul@44 | 72 | pass
|
paul@44 | 73 |
|
paul@44 | 74 | * Yet most people would relate to "class C"
|
paul@44 | 75 | * Not "the class currently known as C"
|
paul@44 | 76 |
|
paul@44 | 77 | Examples of occasionally used flexibility
|
paul@44 | 78 |
|
paul@44 | 79 | * Can evaluate classes and functions in dynamic contexts:
|
paul@44 | 80 |
|
paul@44 | 81 | if platform == 'posix':
|
paul@44 | 82 | class C:
|
paul@44 | 83 | ...
|
paul@44 | 84 | else:
|
paul@44 | 85 | class C:
|
paul@44 | 86 | ...
|
paul@44 | 87 |
|
paul@44 | 88 | * Seen quite often in the standard library with functions
|
paul@44 | 89 | * Dynamism used for configuration purposes
|
paul@44 | 90 |
|
paul@44 | 91 | Distinguish between "good" and "bad" dynamism
|
paul@44 | 92 |
|
paul@44 | 93 | * Dynamic class preparation
|
paul@44 | 94 | * Run-time choice of classes
|
paul@44 | 95 | * Assigning attributes to modules
|
paul@44 | 96 |
|
paul@44 | 97 | Run-time configuration
|
paul@44 | 98 |
|
paul@44 | 99 | * The source of a lot of "bad" dynamism
|
paul@44 | 100 | * Comparable to, but more robust than...
|
paul@44 | 101 | * Class loading tricks in Java
|
paul@44 | 102 | * Dynamic library loading magic in C/C++
|
paul@44 | 103 | * Has a place, but perhaps not in compiled, embedded programs
|
paul@49 | 104 |
|
paul@49 | 105 | Micropython modules
|
paul@49 | 106 |
|
paul@49 | 107 | * Modules contain attributes as with normal Python
|
paul@49 | 108 | * Inside the module:
|
paul@49 | 109 | * Attributes can be accessed and set as globals
|
paul@49 | 110 | * Classes and functions define module attributes
|
paul@49 | 111 | * Outside the module:
|
paul@49 | 112 | * Attributes can be accessed but not set
|
paul@49 | 113 | * Definition from within means more predictable content
|
paul@49 | 114 |
|
paul@49 | 115 | Micropython classes
|
paul@49 | 116 |
|
paul@49 | 117 | * Classes contain attributes and expose superclass attributes
|
paul@49 | 118 | * Inside the class:
|
paul@49 | 119 | * Attributes can be accessed and set in the class scope
|
paul@49 | 120 | * Functions define methods
|
paul@49 | 121 | * Outside the class:
|
paul@49 | 122 | * Attributes can be accessed but not set
|
paul@49 | 123 | * Definition from within means more predictable content
|
paul@49 | 124 |
|
paul@49 | 125 | Micropython instances
|
paul@49 | 126 |
|
paul@49 | 127 | * Instances contain attributes and expose class attributes
|
paul@49 | 128 | * Instance attributes must not shadow class attributes
|
paul@49 | 129 | * The set of attributes is detected by scanning the __init__ method
|
paul@49 | 130 |
|
paul@49 | 131 | Rationale for restrictions
|
paul@49 | 132 |
|
paul@49 | 133 | * Construct efficient run-time representations
|
paul@49 | 134 | * Predictable content means that access can be optimised
|
paul@49 | 135 | * No shadowing means that only a single lookup is necessary
|
paul@53 | 136 |
|
paul@53 | 137 | References, attributes and values
|
paul@53 | 138 |
|
paul@53 | 139 | * Almost everything can be considered as a kind of attribute:
|
paul@53 | 140 | * Module, class, instance
|
paul@53 | 141 | * Local variable is the exception
|
paul@53 | 142 | * Acquired attributes are "values":
|
paul@53 | 143 | * An object being manipulated
|
paul@53 | 144 | * Its context
|
paul@53 | 145 | * Most kinds of values have no real context:
|
paul@53 | 146 | * Module and class attributes, locals
|
paul@53 | 147 | * The exception:
|
paul@53 | 148 | * Instance attributes
|
paul@266 | 149 |
|
paul@266 | 150 | Wild idea: isn't AttributeError just evidence of a bug in the program?
|
paul@266 | 151 |
|
paul@266 | 152 | * Note down all attributes used by a particular name during its lifetime
|
paul@266 | 153 | * Upon recording name usage, record the location of usage
|
paul@266 | 154 | * Use the set of attributes to constrain the range of types that can be used
|
paul@266 | 155 | without an AttributeError being raised
|
paul@266 | 156 | * Convert all name usage to specific attribute usage (on the range of types
|
paul@266 | 157 | found) for all attribute accesses
|
paul@266 | 158 |
|
paul@266 | 159 | Attributes on locals
|
paul@266 | 160 |
|
paul@266 | 161 | * Control-flow can make attribute tracking awkward:
|
paul@266 | 162 |
|
paul@266 | 163 | obj.x # obj must have x
|
paul@266 | 164 | if ...: # (branch)
|
paul@266 | 165 | obj = ... # obj reset
|
paul@266 | 166 | obj.attr # obj must have attr
|
paul@266 | 167 | else: # (branch)
|
paul@266 | 168 | obj.name # obj must have x, name
|
paul@266 | 169 | # (merge)
|
paul@266 | 170 | # obj must have <nothing>
|
paul@266 | 171 |
|
paul@266 | 172 | Attributes on locals with loops
|
paul@266 | 173 |
|
paul@266 | 174 | * Loops complicate matters still further:
|
paul@266 | 175 |
|
paul@266 | 176 | obj.x # obj must have x
|
paul@266 | 177 | while ...: # (branch)
|
paul@266 | 178 | obj.y # obj must have x, y
|
paul@266 | 179 | obj = ... # obj reset
|
paul@266 | 180 | obj.z # obj must have z
|
paul@266 | 181 | # (re-branch)
|
paul@266 | 182 | # obj must have z, y (obj.y)
|
paul@266 | 183 | # obj reset (obj = ...)
|
paul@266 | 184 | # obj must have z, y (obj.z)
|
paul@266 | 185 | # (merge)
|
paul@266 | 186 | # obj must have <nothing>
|
paul@266 | 187 |
|
paul@266 | 188 | Attributes on attributes
|
paul@266 | 189 |
|
paul@266 | 190 | * Classes and modules should preserve single interpretations of attributes
|
paul@266 | 191 | * Attributes on such attributes should accumulate on the targets
|
paul@266 | 192 | * Tracking attributes on such targets is only useful for unknown targets
|
paul@266 | 193 | * Instances cannot be relied upon to refer to a coherent set of targets
|