paul@69 | 1 | Invocations in classic Python:
|
paul@69 | 2 |
|
paul@69 | 3 | f(1, 2, 3) # positional
|
paul@69 | 4 | f(1, 2) # positional with defaults
|
paul@69 | 5 | f(1, 2, c=3) # keywords
|
paul@69 | 6 | f(1, c=3) # keywords with defaults
|
paul@69 | 7 | f(1, 2, 3, 4) # extra positional arguments
|
paul@69 | 8 | f(1, 2, 3, d=4) # extra keyword arguments
|
paul@69 | 9 | f(1, 2, *args) # positional bundles (possibly with defaults)
|
paul@69 | 10 | f(1, 2, **kw) # keyword bundles (possibly with defaults)
|
paul@69 | 11 |
|
paul@69 | 12 | Note that f is never fixed before run-time in Python.
|
paul@69 | 13 |
|
paul@92 | 14 | Comparison to invocations in C:
|
paul@69 | 15 |
|
paul@69 | 16 | f(1, 2, 3) # positional, f known at compile-time
|
paul@69 | 17 | f(1, 2, 3) # positional, f is appropriate function pointer
|
paul@69 | 18 | # ie. (*f)(A, B, C)
|
paul@69 | 19 |
|
paul@69 | 20 | Least expensive cases:
|
paul@69 | 21 |
|
paul@109 | 22 | f(1, 2, 3) # put arguments in frame
|
paul@69 | 23 | # if f is not known, add arguments vs. parameters check
|
paul@69 | 24 | f(1, 2) # to handle defaults, introduce default "filling" where
|
paul@69 | 25 | # not enough arguments are given
|
paul@69 | 26 | # if f is not known, this is obviously done at run-time
|
paul@69 | 27 |
|
paul@69 | 28 | More expensive cases:
|
paul@69 | 29 |
|
paul@109 | 30 | f(1, 2, c=3) # prepare frame using parameter details
|
paul@69 | 31 | # (provided c is a known parameter)
|
paul@69 | 32 | # if f is not known, this is obviously done at run-time
|
paul@69 | 33 | f(1, c=3) # as with the previous case, with default "filling" done
|
paul@69 | 34 | # where not enough arguments are given
|
paul@69 | 35 | # if f is not known, this is obviously done at run-time
|
paul@69 | 36 | # but with all defaults copied in before keywords are
|
paul@69 | 37 | # assigned (since their positions and thus the positions
|
paul@69 | 38 | # of missing parameters cannot be known)
|
paul@69 | 39 |
|
paul@69 | 40 | Awkward cases:
|
paul@69 | 41 |
|
paul@69 | 42 | f(1, 2, 3, 4) # extra positional arguments
|
paul@69 | 43 | f(1, 2, 3, d=4) # extra keyword arguments
|
paul@69 | 44 | f(1, 2, *args) # positional bundles (possibly with defaults)
|
paul@69 | 45 | f(1, 2, **kw) # keyword bundles (possibly with defaults)
|
paul@69 | 46 |
|
paul@69 | 47 | These cases require additional structures to be created, potentially at
|
paul@69 | 48 | run-time.
|
paul@92 | 49 |
|
paul@92 | 50 | Methods vs. functions:
|
paul@92 | 51 |
|
paul@92 | 52 | f(obj, 1, 2) # f known as function at compile-time:
|
paul@92 | 53 | # f(obj, 1, 2)
|
paul@92 | 54 | # f known as C.m at compile-time:
|
paul@92 | 55 | # m(obj "assert isinstance(obj, C)", 1, 2)
|
paul@98 | 56 | # f not known at compile-time:
|
paul@92 | 57 | # f(<context>, obj, 1, 2) for instance-accessed methods
|
paul@92 | 58 | # f(obj, 1, 2) for class-accessed methods
|
paul@92 | 59 | # f(obj, 1, 2) for functions
|
paul@92 | 60 |
|
paul@92 | 61 | (Could either have universal context usage even for functions, which would
|
paul@92 | 62 | ignore them, or attempt to remove contexts when functions are called.)
|
paul@92 | 63 |
|
paul@98 | 64 | Argument lists for functions:
|
paul@98 | 65 |
|
paul@98 | 66 | f(obj, 1, 2) # f known as function at compile-time
|
paul@98 | 67 |
|
paul@98 | 68 | f -> don't get any context information
|
paul@98 | 69 | obj -> argument #1
|
paul@98 | 70 | 1 -> argument #2
|
paul@98 | 71 | 2 -> argument #3
|
paul@98 | 72 |
|
paul@98 | 73 | Argument lists for methods:
|
paul@98 | 74 |
|
paul@98 | 75 | f(obj, 1, 2) # f known as C.m at compile-time (context is C)
|
paul@98 | 76 |
|
paul@98 | 77 | f -> C.m - don't get any context information
|
paul@98 | 78 | obj -> argument #1
|
paul@98 | 79 | 1 -> argument #2
|
paul@98 | 80 | 2 -> argument #3
|
paul@98 | 81 |
|
paul@98 | 82 | Argument lists for methods:
|
paul@98 | 83 |
|
paul@98 | 84 | f(obj, 1, 2) # f known as C.m at compile-time (context is an instance)
|
paul@98 | 85 |
|
paul@98 | 86 | f -> C.m
|
paul@98 | 87 | -> context is argument #1
|
paul@98 | 88 | obj -> argument #2
|
paul@98 | 89 | 1 -> argument #3
|
paul@98 | 90 | 2 -> argument #4
|
paul@98 | 91 |
|
paul@109 | 92 | Argument lists for classes:
|
paul@109 | 93 |
|
paul@109 | 94 | f(obj, 1, 2) # f known as C at compile-time
|
paul@109 | 95 |
|
paul@109 | 96 | f -> C.__new__ - don't get any context information
|
paul@109 | 97 | -> any __init__ method will be called from C.__new__
|
paul@109 | 98 | obj -> argument #1
|
paul@109 | 99 | 1 -> argument #2
|
paul@109 | 100 | 2 -> argument #3
|
paul@109 | 101 |
|
paul@98 | 102 | Argument lists for unknown callables:
|
paul@98 | 103 |
|
paul@98 | 104 | f(obj, 1, 2) # f not known at compile-time
|
paul@98 | 105 |
|
paul@98 | 106 | f -> f
|
paul@98 | 107 | -> load context for argument #1
|
paul@98 | 108 | obj -> argument #2
|
paul@98 | 109 | 1 -> argument #3
|
paul@98 | 110 | 2 -> argument #4
|
paul@98 | 111 |
|
paul@98 | 112 | Then, check the context and shift the frame if necessary:
|
paul@98 | 113 |
|
paul@98 | 114 | <context> is module or class:
|
paul@98 | 115 | (<context>, obj, 1, 2) -> (obj, 1, 2)
|
paul@98 | 116 |
|
paul@98 | 117 | <context> is instance: no change
|
paul@98 | 118 |
|
paul@110 | 119 | Defaults for unknown callables:
|
paul@110 | 120 |
|
paul@110 | 121 | f(obj) # f not known at compile-time
|
paul@110 | 122 |
|
paul@110 | 123 | f -> f
|
paul@110 | 124 | -> load context for argument #1
|
paul@110 | 125 | obj -> argument #2
|
paul@110 | 126 |
|
paul@110 | 127 | Then, check the number of arguments and the availability of defaults against
|
paul@110 | 128 | the details provided by the callable's structure.
|
paul@110 | 129 |
|
paul@92 | 130 | Functions as methods:
|
paul@92 | 131 |
|
paul@92 | 132 | def f(x, y, z): ...
|
paul@92 | 133 | class C:
|
paul@92 | 134 | m = f
|
paul@92 | 135 | c = C()
|
paul@92 | 136 | ...
|
paul@92 | 137 | f(obj, 1, 2) # no restrictions on obj
|
paul@92 | 138 | obj.m(1, 2) # f(obj, 1, 2)
|
paul@92 | 139 | C.m(obj, 1, 2) # f(obj "assert isinstance(obj, C)", 1, 2)
|