1 = Program Structure = 2 3 A program consists of a number of '''modules''' with each module providing its own namespace. Modules can be organised within '''packages''' which define a hierarchical relationship between them. However, the relationship between modules is not automatically exposed within the program: it is more appropriate to consider modules as independent entities that have a particular naming scheme. 4 5 Within each module a hierarchy of namespaces is provided by '''classes''', with each class potentially containing other classes, and so on. Also appearing within modules and classes are '''functions''', with those appearing within classes being regarded as '''methods'''. 6 7 Function namespaces are considered separately from module and class namespaces and are not considered part of the general namespace hierarchy, instead merely appearing as objects at the edges of that hierarchy. Functions may also be defined within functions, and such inner functions will be referenced within their parent functions, but no hierarchical relationship will exist between their namespaces. 8 9 Thus, a program provides a static namespace hierarchy consisting of modules containing classes (containing other classes, and so on) plus functions. Objects residing within namespaces are accessed via '''attributes''' of those namespaces. 10 11 {{{{#!table 12 {{{#!graphviz 13 //format=svg 14 //transform=notugly 15 digraph program { 16 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Program structure"]; 17 edge [tooltip="Program structure"]; 18 rankdir=LR; 19 20 program [label="program",shape=folder,style=filled,fillcolor=cyan]; 21 22 subgraph { 23 rank=same; 24 moduleM [label="module M",style=filled,fillcolor=gold]; 25 moduleN [label="module N\n(package)",style=filled,fillcolor=gold]; 26 } 27 28 subgraph { 29 rank=same; 30 classA [label="class A"]; 31 moduleNP [label="module N.P",style=filled,fillcolor=gold]; 32 } 33 34 subgraph { 35 rank=same; 36 functionF [label="function f",shape=ellipse]; 37 functionG [label="function g",shape=ellipse]; 38 classB [label="class B"]; 39 classC [label="class C"]; 40 } 41 42 subgraph { 43 rank=same; 44 functionJ [label="function j",shape=ellipse]; 45 functionH [label="function h",shape=ellipse]; 46 functionK [label="function k",shape=ellipse]; 47 } 48 49 program -> moduleM; 50 program -> moduleN; 51 52 moduleM -> classA; 53 moduleN -> moduleNP; 54 moduleNP -> classC; 55 56 classA -> functionF; 57 classA -> functionG; 58 classA -> classB; 59 classB -> functionH; 60 classC -> functionK; 61 62 functionG -> functionJ [style=dashed]; 63 } 64 }}} 65 || 66 {{{#!python numbers=disable 67 # module M 68 69 class A: 70 def f(...): pass 71 72 def g(...): 73 def j(...): pass 74 75 class B: 76 def h(...): pass 77 78 # module N 79 80 ... 81 82 # module N.P 83 84 class C: 85 def k(...): pass 86 }}} 87 }}}} 88 89 == Referencing the Structure == 90 91 Each part of the structure is catalogued using an '''object path''', indicating its location in the structure hierarchy, and a reference indicating its nature and origin. For example: 92 93 || '''Object Path''' || '''Reference''' || '''Explanation''' || 94 || `M.A` || `<class>:M.A` || The definition of class `A` in module `M` || 95 || `O.A` || `<class>:M.A` || A reference to `M.A`, a class || 96 || `N.P.C.k` || `<function>:N.P.C.k` || The definition of method `k` in class `C` of module `N.P` || 97 || `O.k` || `<function>:N.P.C.k` || A reference to `N.P.C.k`, a function || 98 || `O.values` || `<instance>:__builtins__.list.list` || An object identified as an instance of class `__builtins__.list.list` || 99 || `__main__.M` || `<module>:M` || A reference to module `M` || 100 || `__main__.counter` || `<var>` || An undetermined object called `counter` in the `__main__` module || 101 102 The reference therefore expresses the '''kind''' of object (class, function, instance, module or undetermined variable), possibly accompanied by an object type, and also possibly accompanied by an alias indicating where the reference was obtained. 103 104 == Classes == 105 106 Classes are regarded as statically-defined objects, meaning that they are only evaluated once and must not be defined within conditional sections or within functions. Base classes must be expressed using readily-identifiable class names, since any potential ambiguity or uncertainty with the identity of base classes could result in a class inheritance hierarchy that is effectively dynamic. 107 108 When '''instantiated''', classes provide '''instances''' that provide the attributes of each class's namespace plus any '''inherited''' attributes from base classes that would not be provided by the class itself. In addition, instances provide their own instance attributes. 109 110 == Functions == 111 112 Functions are regarded as statically-defined objects, but they may be defined either with names within other named functions or as '''lambdas''' (functions without names) within named functions or other lambdas. Thus, unlike classes, functions may be defined once but replicated many times, each time with different accompanying state information. Such state information needs to be provided via default parameters: it is not detected and propagated automatically. Closures are not supported: any state from enclosing scopes must be supplied at the point of definition of a function; it is not acquired from outer functions by name. 113 114 {{{#!python numbers=disable 115 def outer(a): 116 b = 2 117 def inner(c, a=a, b=b): 118 # a initialised using default from outer scope 119 # b also initialised using default from outer scope 120 return a, b, c 121 b = 4 122 123 outer(1)(3) # returns (1, 2, 3) not (1, 4, 3) 124 }}} 125 126 === Lambdas === 127 128 Lambdas are given special names for the purposes of identification within the program structure, being named relative to the scope in which they are defined. For example, the first lambda appearing within module `N` would have an object path of `N.$l0`, and a subsequent lambda within the same scope would have an object path of `N.$l1`. Lambdas may appear within classes and functions, including lambdas themselves. For example: 129 130 {{{#!python numbers=disable 131 def f(x): 132 return lambda y, x=x: lambda z, x=x, y=y: (x, y, z) 133 }}} 134 135 Here, within a module `M`, the outer lambda would have the object path `M.f.$l0` whereas the inner lambda would have the object path `M.f.$l0.$l0`.