Differences between revisions 12 and 28 (spanning 16 versions)
Revision 12 as of 2006-11-29 01:30:05
Size: 6987
Editor: reflux
Comment: add the Type object
Revision 28 as of 2008-11-15 13:59:38
Size: 9459
Editor: localhost
Comment: converted to 1.6 markup
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
['''News Update:''' some ideas from this wiki page are being
incorporated into [[http://python.org/dev/peps/pep-3119/|PEP 3119]].]
Line 6: Line 9:
 * How to handle optional parameters, such as in the "sort" method on {{{MutableSequence}}}?
 * 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)?
 * 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? [+1 to drop 'cmp' completely and make 'key' the first positional arg]
 * What is the real relationship between Sequence, Mapping, Set, and Dict? Isn't a Sequence also a mapping (of integer index values to Object sequence values)? Isn't a Dict also a Set (of key values)?
 * 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()"). [+1 for mixin]
Line 9: Line 14:
 * In Py2, {{{Boolean}}} is a sub-type of Integer. Does this make sense? I've made it its own type in this list...
* Should {{{None}}} just be an instance of {{{Object}}}? Does {{{NoneType}}} need to exist?
 * Should {{{None}}} just be a very special instance of {{{Object}}}? Does the {{{Null}}} type need to exist?
Line 19: Line 23:
 # presumable for "is" we compare the ids of the two objects
 id () => Integer
 # presumably for "is" we compare the ids of the two objects
 id () => Comparable
Line 22: Line 26:
 # the __str__ method  # we rename __str__ to "printable_rendition"
Line 26: Line 30:
 getattr (String name) => Object
 setattr (String name, Object value)
 delattr (String name) => Object

TypeSequence (Sequence):
 # sequence of Type objects
Line 30: Line 40:
 supertypes () => Sequence  supertypes () => TypeSequence
Line 32: Line 42:
 interfaces () => Sequence

Ellipsis (Object):
 # contains only the single value represented by three dots
 ThreeDots
 interfaces () => TypeSequence
Line 39: Line 45:
 # only a single value of this type  # according to the language reference manual, the Null type contains only one value, "None"
Line 41: Line 47:

Exception (Object):
 args () => Sequence

ExceptionContext (Object):
 exception () => Exception
 traceback () => Traceback
Line 47: Line 60:
 # according to Jim Jewett, only < is currently used for ordering
Line 48: Line 62:
 greater_than (Object) => Boolean
Line 81: Line 94:
 # let's rename __iter__ to "iterator"
Line 83: Line 97:
StringIterable:
 # yields an iteration of String values

KeyValueIterable (Iterable):
 # yields an iteration of key-value pairs
Line 84: Line 104:
 next () => other

KeyValueIterable (Iterable):
 # yields iteration of key-value pairs
 next () => Object
Line 91: Line 108:
 len () => Integer  # we keep "len" as a mandatory method -- should we? And why isn't it "size"?
 len () => Integer
Line 93: Line 111:

Set (Container):
 # we rename __getitem__ to "get"
 get (Object key) => Object

MutableContainer (Container):
 # we rename __setitem__ to "add"
 # may quite easily raise KeyError when "key" is of the wrong type
 add (Object key, Object value)
 # we rename __delitem__ to "remove"
 remove (Object key)

Set:
Line 105: Line 132:
 contains (Sequence) => Sequence  # this "contains" method looks for sub-sequences
 # how do we differentiate it from the Container method "contains()"?
 # should it be called "subsequence"?
 covers (Sequence) => Boolean
Line 107: Line 137:
 slice1 (Integer) => Object
 # normal slice of range
 slice2 (Integer, Integer) => Sequence
 # slice with step K
 slice3 (Integer, Integer, Integer) => Sequence
 # "end" defaults to start, "step" defaults to 1
 slice (Integer start, Integer end = None, Integer step = None) => Sequence
Line 116: Line 143:

SequenceOfOrderable (Sequence):
Line 117: Line 146:
 min () => Object
 max () => Object

MutableSequence (Sequence):
 min () => Orderable
 max () => Orderable

MutableSequence (Sequence, MutableContainer):
 # append just calls "add(len(self), Object)"
Line 122: Line 152:
 insert (Integer position, Object) => self
Line 124: Line 153:
 replace (Integer position, Object) => self  replace (Object, Integer position) => self
Line 126: Line 155:
 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
 replace (Iterable, Integer start, Integer end, Integer step = 1) => self
Line 132: Line 159:
 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
 index (Object, Integer start = 0, Integer end = len(self)) => Integer
 pop (Integer position = 0) => Object
 push (Object, Integer position = 0) => self
 delete (Integer start, Integer end = start, Integer step = 1) => self
 sort (Function comparison_fn = None, Function key_fn = None, Boolean reverse = False) => self
Line 158: Line 179:
 get (Object key) => Object
 get_with_
default (Object key, Object default) => Object
 set (Object key, Object value)
 # extra version of "get" which takes a default value
 ge
t (Object key, Object default = None) => Object
Line 164: Line 184:
 copy () => Mapping  # shallow copy of mapping
 shallow_
copy () => Mapping
Line 175: Line 196:
 # yet another form takes no positional parameters, and arbitrary keyword arguments
 # I need a notation for this kind of method
 update (KWDS) => self
Line 178: Line 202:
Dict (Object, Mapping, Container): Dict (Object, Mapping, MutableContainer):
Line 187: Line 211:
 flush ()
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
Line 190: Line 224:

OutputStream (Stream):
 flush()

BinaryOutputStream (OutputStream):
Line 192: Line 231:
RandomAccessStream (Stream):
 # do we really need to continue to mimic the low-level UNIX seek and tell?
 # why not use Python sequence-style indices for offset?
 seek (Integer offset)
 tell () => Integer

TextStream (Stream):
TextStream:
 encoding () => String

TextOutputStream (OutputStream, TextStream):
 writeline (String) => Boolean
 writelines (StringIterable) => Boolean

TextInputStream (Stream, TextStream)
Line 200: Line 240:
 readlines () => Sequence
 writeline (String) => Boolean
 writelines (Sequence) => Boolean
 encoding () => String

OpenFile (RandomAccessStream):
 # it would be great if this had a "mimetype" method
 readlines () => StringIterable

DiskFile (RandomAccessStream):
Line 212: Line 248:
  BinaryOpenFile (Object, Stream, OpenFile, Iterable, ExecutionContext):

TextOpenFile (Object, TextStream, OpenFile, Iterable, ExecutionContext):
 # It would be nice to have another method, "mimetype", which would try to guess
 # the MIME type for the file, and if it can it would return two strings, the MIME major
 # type and minor type for the file. It would return None, None if it couldn't figure it out.
 # I'd suggest UNIX implementation just use "file", while Windows implementations
 # use registry and file extensions.
 # something like: mimetype () => String, String
Line 218: Line 256:
----
CategoryLanguage

Possible Python 3K Class Tree?

[News Update: some ideas from this wiki page are being incorporated into PEP 3119.]

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? [+1 to drop 'cmp' completely and make 'key' the first positional arg]

  • What is the real relationship between Sequence, Mapping, Set, and Dict? Isn't a Sequence also a mapping (of integer index values to Object sequence values)? Isn't a Dict also a Set (of key values)?
  • 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()"). [+1 for mixin]

  • 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
 # presumably for "is" we compare the ids of the two objects
 id () => Comparable
 true () => Boolean
 # we rename __str__ to "printable_rendition"
 printable () => String
 class () => Type
 implements (Type) => Boolean
 getattr (String name) => Object
 setattr (String name, Object value)
 delattr (String name) => Object

TypeSequence (Sequence):
 # sequence of Type objects

Type (Object):
 name () => String
 # supertypes yields list of immediate parent types (what's in __bases__)
 supertypes () => TypeSequence
 # interfaces yields flattened list of all interface types this implements
 interfaces () => TypeSequence

Null (Object):
 # according to the language reference manual, the Null type contains only one value, "None"
 None

Exception (Object):
 args () => Sequence

ExceptionContext (Object):
 exception () => Exception
 traceback () => Traceback

Boolean (Object):
 True
 False

Orderable:
 # according to Jim Jewett, only < is currently used for ordering
 less_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:
 # let's rename __iter__ to "iterator"
 iterator () => Iteration

StringIterable:
 # yields an iteration of String values

KeyValueIterable (Iterable):
 # yields an iteration of key-value pairs 

Iteration (Object, Iterable):
 next () => Object

# should Container be Iterable, or should that be reserved for real types, like Tuple?
Container (Iterable):
 # we keep "len" as a mandatory method -- should we?  And why isn't it "size"?
 len () => Integer   
 contains (Object) => Boolean
 # we rename __getitem__ to "get"
 get (Object key) => Object

MutableContainer (Container):
 # we rename __setitem__ to "add"
 # may quite easily raise KeyError when "key" is of the wrong type
 add (Object key, Object value)
 # we rename __delitem__ to "remove"
 remove (Object key)

Set:
 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):
 # this "contains" method looks for sub-sequences
 # how do we differentiate it from the Container method "contains()"?
 # should it be called "subsequence"?
 covers (Sequence) => Boolean
 # normal access via index
 # "end" defaults to start, "step" defaults to 1
 slice (Integer start, Integer end = None, Integer step = None) => Sequence
 # return self + other Sequence
 concatenate (Sequence) => Sequence
 # N shallow copies of self
 multiply (Integer) => Sequence

SequenceOfOrderable (Sequence):
 # do "min" and "max" make sense over arbitrary sequences?  Should really only apply to sequences of "Orderable"
 min () => Orderable
 max () => Orderable

MutableSequence (Sequence, MutableContainer):
 # append just calls "add(len(self), Object)"
 append (Object) => self
 # value at I is replaced with Object
 replace (Object, Integer position) => self
 # slice from I to J is replaced with values of Iterator
 replace (Iterable, Integer start, Integer end, Integer step = 1) => self
 extend (Object) => self
 count (Object) => Integer
 reverse ()
 index (Object, Integer start = 0, Integer end = len(self)) => Integer
 pop (Integer position = 0) => Object
 push (Object, Integer position = 0) => self
 delete (Integer start, Integer end = start, Integer step = 1) => self
 sort (Function comparison_fn = None, Function key_fn = None, Boolean reverse = False) => 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:
 # extra version of "get" which takes a default value
 get (Object key, Object default = None) => Object
 # should delete return the deleted value?  Why not.  That removes the need for "pop".
 delete (Object key) => Object
 clear ()
 # shallow copy of mapping
 shallow_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, MutableContainer):
 # 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 (Stream):
 flush()

BinaryOutputStream (OutputStream):
 write (ByteSequence) => Integer

TextStream:
 encoding () => String

TextOutputStream (OutputStream, TextStream):
 writeline (String) => Boolean
 writelines (StringIterable) => Boolean

TextInputStream (Stream, TextStream)
 readline () => String
 readlines () => StringIterable

DiskFile (RandomAccessStream):
 fileno () => Integer
 filename () => String
 isatty () => Boolean
 truncate (Integer size)
 mode () => String
 # It would be nice to have another method, "mimetype", which would try to guess
 # the MIME type for the file, and if it can it would return two strings, the MIME major
 # type and minor type for the file.  It would return None, None if it couldn't figure it out.
 # I'd suggest UNIX implementation just use "file", while Windows implementations
 # use registry and file extensions.
 # something like:  mimetype () => String, String

AbstractBaseClasses (last edited 2008-11-15 13:59:38 by localhost)

Unable to edit the page? See the FrontPage for instructions.