117
Comment:
|
8327
factored file interfaces further
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
This page is about a re-factoring of the base and built-in Python types into a set of Abstract Base Classes (ABCs). | = Possible Python 3K Class Tree? = This page contain an incomplete thinking-out-loud description of a re-factoring of the base and built-in Python types into a set of Abstract Base Classes (ABCs) and concrete types. This would probably be a good time to enumerate the exceptions various basic operations can raise, as well. Some questions: * How to handle optional and keyword parameters to methods, such as the ''cmp'' parameter to the "sort" method on {{{MutableSequence}}}? Are they different methods with and without the parameter? Are they just keyword methods, and don't affect the method differentiation? * Should the {{{MutableSequence}}} interface be further broken up -- for instance, a {{{deque}}} may not be appropriate for sorting? * Currently, {{{Boolean}}} is a subtype of {{{Integer}}}, which is odd. But we still want a way to test any {{{Object}}} for "trueness". Should {{{Boolean}}} be an abstract type that's mixed-in to {{{Object}}}, or a concrete type that inherits from {{{Object}}} (thus implying that non-Boolean {{{Object}}}s may exist)? I've added a "true()" method to {{{Object}}}, which is simply a way of coercing it to a {{{Boolean}}} value (perhaps it should be called "boolean()"). * Should destructive operations on {{{MutableSequence}}} return the sequence? They don't currently, but this would be very useful. I've made it so in this list... * Should {{{None}}} just be a very special instance of {{{Object}}}? Does the {{{Null}}} type need to exist? * If a file is opened in binary mode, should its iterator be over bytes instead of lines? Should "readline()" even work on a binary file? {{{ Comparable: equals (Comparable) => Boolean Object (Comparable): hash () => Integer # presumable for "is" we compare the ids of the two objects id () => Integer true () => Boolean # the __str__ method printable () => String class () => Type implements (Type) => Boolean Type (Object): name () => String # supertypes yields list of immediate parent types (what's in __bases__) supertypes () => Sequence # interfaces yields flattened list of all interface types this implements interfaces () => Sequence Ellipsis (Object): # contains only the single value represented by three dots ThreeDots Null (Object): # only a single value of this type None Exception (Object): args () => Sequence ExceptionContext (Object): exception () => Exception traceback () => Traceback Boolean (Object): True False Orderable: less_than (Object) => Boolean greater_than (Object) => Boolean Numeric: add (Numeric) => Numeric subtract (Numeric) => Numeric product (Numeric) => Numeric quotient (Numeric) => Numeric floored_quotient (Numeric) => Numeric remainder (Numeric) => Numeric negate (Numeric) => Numeric absolute_value () => Numeric exponentiate (Numeric) => Numeric magnitude () => Numeric Integer (Object, Orderable, Numeric): or (Integer) => Integer xor (Integer) => Integer and (Integer) => Integer shift (Integer) => Integer invert (Integer) => Integer real () => Real Real (Object, Orderable, Numeric): floor () => Integer ceiling () => Integer Complex (Object, Orderable, Numeric): conjugate () => Complex Decimal (Object, Orderable, Numeric): TBD Iterable: iterator () => Iteration StringIterable: # yields an iteration of String values KeyValueIterable (Iterable): # yields an iteration of key-value pairs Iteration (Object, Iterable): next () => other # should Container be Iterable, or should that be reserved for real types, like Tuple? Container (Iterable): len () => Integer contains (Object) => Boolean Set (Container): is_subset (Set) => Boolean is_superset (Set) => Boolean union_with (Set) => Set intersection_with (Set) => Set difference (Set) => Set symmetric_difference (Set) => Set # should this be "multiply" to match Sequence? shallow_copy () => Set Sequence (Container): contains (Sequence) => Sequence # normal access via index slice1 (Integer) => Object # normal slice of range slice2 (Integer, Integer) => Sequence # slice with step K slice3 (Integer, Integer, Integer) => Sequence # return self + other Sequence concatenate (Sequence) => Sequence # N shallow copies of self multiply (Integer) => Sequence # do "min" and "max" make sense over arbitrary sequences? Should really only apply to sequences of "Orderable" min () => Object max () => Object MutableSequence (Sequence): append (Object) => self insert (Integer position, Object) => self # value at I is replaced with Object replace (Integer position, Object) => self # slice from I to J is replaced with values of Iterator replace2 (Integer start, Integer end, Iterable) => self # slice from I to J with step K is replaced by Iterator replace3 (Integer start, Integer end, Integer step, Iterable) => self extend (Object) => self count (Object) => Integer reverse () index1 (Object) => Integer index2 (Object, Integer start, Integer end) => Object pop1 () => Object pop2 (Integer position) => Object delete1 (Integer position) => self delete2 (Integer start, Integer end) => self delete3 (Integer start, Integer end, Integer step) => self sort0 () => self sort1 (Function comparison_fn) => self sort2 (Function comparison_fn, Function key_fn) => self sort3 (Function comparison_fn, Function key_fn, Boolean reverse) => self ByteSequence (Object, Sequence): # should this be a MutableSequence? Buffer (Object, MutableSequence): # is this just mutable version of ByteSequence? String (Object, Sequence): TBD Tuple (Object, Sequence): List (Object, MutableSequence): Mapping: get (Object key) => Object get_with_default (Object key, Object default) => Object set (Object key, Object value) # should delete return the deleted value? Why not. That removes the need for "pop". delete (Object key) => Object clear () copy () => Mapping contains (Object key) => Boolean # items returns a value which is guaranteed to satisfy both the Set interface and the KeyValueIterable interface items () => (Set and KeyValueIterable) keys () => Set values () => Set # get_or_set is the current "setdefault" get_or_set (Object key, Object value) => Object update (Mapping) => self # alternate form of "update" takes Iterable of key-value pairs update (KeyValueIterable) => self # yet another form takes no positional parameters, and arbitrary keyword arguments # I need a notation for this kind of method update (KWDS) => self # do we really need fromkeys? fromkeys (Sequence keys, Object initial_value) => Mapping Dict (Object, Mapping, Container): # should some methods (e.g., "fromkeys") be here instead of in Mapping? ExecutionContext: enter () => ExecutionContext exit (ExceptionContext) => Boolean Stream: close () RandomAccessStream: # do we really need to continue to mimic the low-level UNIX seek and tell? # why not use Python sequence-style indices for offset? Positive int for relative # to start, negative int for relative to end, and just call tell() and add an offset # if you want to seek relative to the current location, for heaven's sake. seek (Integer offset) tell () => Integer BinaryInputStream (Stream): # read tries to read the whole file, but may return just a part of it read () => ByteSequence read (Integer) => ByteSequence OutputStream: flush() BinaryOutputStream: write (ByteSequence) => Integer TextStream: encoding () => String TextOutputStream (OutputStream, TextStream): writeline (String) => Boolean writelines (StringIterable) => Boolean TextInputStream (InputStream, TextStream) readline () => String readlines () => StringIterable DiskFile (RandomAccessStream): fileno () => Integer filename () => String isatty () => Boolean truncate (Integer size) mode () => String # returns two strings, the MIME major type and minor type for the file # return None, None if it can't figure it out. Suggest UNIX implementation just # uses "file", while Windows implementation uses registry and file extensions. mimetype () => String, String }}} ---- CategoryLanguage |
Possible Python 3K Class Tree?
This page contain an incomplete thinking-out-loud description of a re-factoring of the base and built-in Python types into a set of Abstract Base Classes (ABCs) and concrete types. This would probably be a good time to enumerate the exceptions various basic operations can raise, as well.
Some questions:
How to handle optional and keyword parameters to methods, such as the cmp parameter to the "sort" method on MutableSequence? Are they different methods with and without the parameter? Are they just keyword methods, and don't affect the method differentiation?
Should the MutableSequence interface be further broken up -- for instance, a deque may not be appropriate for sorting?
Currently, Boolean is a subtype of Integer, which is odd. But we still want a way to test any Object for "trueness". Should Boolean be an abstract type that's mixed-in to Object, or a concrete type that inherits from Object (thus implying that non-Boolean Objects may exist)? I've added a "true()" method to Object, which is simply a way of coercing it to a Boolean value (perhaps it should be called "boolean()").
Should destructive operations on MutableSequence return the sequence? They don't currently, but this would be very useful. I've made it so in this list...
Should None just be a very special instance of Object? Does the Null type need to exist?
- If a file is opened in binary mode, should its iterator be over bytes instead of lines? Should "readline()" even work on a binary file?
Comparable: equals (Comparable) => Boolean Object (Comparable): hash () => Integer # presumable for "is" we compare the ids of the two objects id () => Integer true () => Boolean # the __str__ method printable () => String class () => Type implements (Type) => Boolean Type (Object): name () => String # supertypes yields list of immediate parent types (what's in __bases__) supertypes () => Sequence # interfaces yields flattened list of all interface types this implements interfaces () => Sequence Ellipsis (Object): # contains only the single value represented by three dots ThreeDots Null (Object): # only a single value of this type None Exception (Object): args () => Sequence ExceptionContext (Object): exception () => Exception traceback () => Traceback Boolean (Object): True False Orderable: less_than (Object) => Boolean greater_than (Object) => Boolean Numeric: add (Numeric) => Numeric subtract (Numeric) => Numeric product (Numeric) => Numeric quotient (Numeric) => Numeric floored_quotient (Numeric) => Numeric remainder (Numeric) => Numeric negate (Numeric) => Numeric absolute_value () => Numeric exponentiate (Numeric) => Numeric magnitude () => Numeric Integer (Object, Orderable, Numeric): or (Integer) => Integer xor (Integer) => Integer and (Integer) => Integer shift (Integer) => Integer invert (Integer) => Integer real () => Real Real (Object, Orderable, Numeric): floor () => Integer ceiling () => Integer Complex (Object, Orderable, Numeric): conjugate () => Complex Decimal (Object, Orderable, Numeric): TBD Iterable: iterator () => Iteration StringIterable: # yields an iteration of String values KeyValueIterable (Iterable): # yields an iteration of key-value pairs Iteration (Object, Iterable): next () => other # should Container be Iterable, or should that be reserved for real types, like Tuple? Container (Iterable): len () => Integer contains (Object) => Boolean Set (Container): is_subset (Set) => Boolean is_superset (Set) => Boolean union_with (Set) => Set intersection_with (Set) => Set difference (Set) => Set symmetric_difference (Set) => Set # should this be "multiply" to match Sequence? shallow_copy () => Set Sequence (Container): contains (Sequence) => Sequence # normal access via index slice1 (Integer) => Object # normal slice of range slice2 (Integer, Integer) => Sequence # slice with step K slice3 (Integer, Integer, Integer) => Sequence # return self + other Sequence concatenate (Sequence) => Sequence # N shallow copies of self multiply (Integer) => Sequence # do "min" and "max" make sense over arbitrary sequences? Should really only apply to sequences of "Orderable" min () => Object max () => Object MutableSequence (Sequence): append (Object) => self insert (Integer position, Object) => self # value at I is replaced with Object replace (Integer position, Object) => self # slice from I to J is replaced with values of Iterator replace2 (Integer start, Integer end, Iterable) => self # slice from I to J with step K is replaced by Iterator replace3 (Integer start, Integer end, Integer step, Iterable) => self extend (Object) => self count (Object) => Integer reverse () index1 (Object) => Integer index2 (Object, Integer start, Integer end) => Object pop1 () => Object pop2 (Integer position) => Object delete1 (Integer position) => self delete2 (Integer start, Integer end) => self delete3 (Integer start, Integer end, Integer step) => self sort0 () => self sort1 (Function comparison_fn) => self sort2 (Function comparison_fn, Function key_fn) => self sort3 (Function comparison_fn, Function key_fn, Boolean reverse) => self ByteSequence (Object, Sequence): # should this be a MutableSequence? Buffer (Object, MutableSequence): # is this just mutable version of ByteSequence? String (Object, Sequence): TBD Tuple (Object, Sequence): List (Object, MutableSequence): Mapping: get (Object key) => Object get_with_default (Object key, Object default) => Object set (Object key, Object value) # should delete return the deleted value? Why not. That removes the need for "pop". delete (Object key) => Object clear () copy () => Mapping contains (Object key) => Boolean # items returns a value which is guaranteed to satisfy both the Set interface and the KeyValueIterable interface items () => (Set and KeyValueIterable) keys () => Set values () => Set # get_or_set is the current "setdefault" get_or_set (Object key, Object value) => Object update (Mapping) => self # alternate form of "update" takes Iterable of key-value pairs update (KeyValueIterable) => self # yet another form takes no positional parameters, and arbitrary keyword arguments # I need a notation for this kind of method update (KWDS) => self # do we really need fromkeys? fromkeys (Sequence keys, Object initial_value) => Mapping Dict (Object, Mapping, Container): # should some methods (e.g., "fromkeys") be here instead of in Mapping? ExecutionContext: enter () => ExecutionContext exit (ExceptionContext) => Boolean Stream: close () RandomAccessStream: # do we really need to continue to mimic the low-level UNIX seek and tell? # why not use Python sequence-style indices for offset? Positive int for relative # to start, negative int for relative to end, and just call tell() and add an offset # if you want to seek relative to the current location, for heaven's sake. seek (Integer offset) tell () => Integer BinaryInputStream (Stream): # read tries to read the whole file, but may return just a part of it read () => ByteSequence read (Integer) => ByteSequence OutputStream: flush() BinaryOutputStream: write (ByteSequence) => Integer TextStream: encoding () => String TextOutputStream (OutputStream, TextStream): writeline (String) => Boolean writelines (StringIterable) => Boolean TextInputStream (InputStream, TextStream) readline () => String readlines () => StringIterable DiskFile (RandomAccessStream): fileno () => Integer filename () => String isatty () => Boolean truncate (Integer size) mode () => String # returns two strings, the MIME major type and minor type for the file # return None, None if it can't figure it out. Suggest UNIX implementation just # uses "file", while Windows implementation uses registry and file extensions. mimetype () => String, String