diff options
-rwxr-xr-x | Demo/classes/Complex.py | 73 | ||||
-rwxr-xr-x | Demo/classes/Dbm.py | 71 | ||||
-rw-r--r-- | Demo/classes/README | 11 | ||||
-rwxr-xr-x | Demo/classes/Range.py | 72 | ||||
-rwxr-xr-x | Demo/classes/Rat.py | 86 | ||||
-rwxr-xr-x | Demo/classes/Vec.py | 65 | ||||
-rwxr-xr-x | Demo/classes/class.doc | 110 |
7 files changed, 488 insertions, 0 deletions
diff --git a/Demo/classes/Complex.py b/Demo/classes/Complex.py new file mode 100755 index 0000000..5880c64 --- /dev/null +++ b/Demo/classes/Complex.py @@ -0,0 +1,73 @@ +# Complex numbers + + +from math import sqrt + + +def complex(re, im): + return Complex().init(re, im) + + +class Complex: + + def init(self, re, im): + self.re = float(re) + self.im = float(im) + return self + + def __repr__(self): + return 'complex' + `self.re, self.im` + + def __cmp__(a, b): + a = a.__abs__() + b = b.__abs__() + return (a > b) - (a < b) + + def __float__(self): + if self.im: + raise ValueError, 'cannot convert complex to float' + return float(self.re) + + def __long__(self): + return long(float(self)) + + def __int__(self): + return int(float(self)) + + def __abs__(self): + # XXX overflow? + return sqrt(self.re*self.re + self.im*self.im) + + def __add__(a, b): + return complex(a.re + b.re, a.im + b.im) + + def __sub__(a, b): + return complex(a.re - b.re, a.im - b.im) + + def __mul__(a, b): + return complex(a.re*b.re - a.im*b.im, a.re*b.im + a.im*b.re) + + def __div__(a, b): + q = (b.re*b.re + b.im*b.im) + re = (a.re*b.re + a.im*b.im) / q + im = (a.im*b.re - b.im*a.re) / q + return complex(re, im) + + def __neg__(self): + return complex(-self.re, -self.im) + + +def test(): + a = complex(2, 0) + b = complex(3, 4) + print a, b + print a+b, a-b, a*b, a/b + print b+a, b-a, b*a, b/a + i = complex(0, 1) + print i, i*i, i*i*i, i*i*i*i + j = complex(1, 1) + print j, j*j, j*j*j, j*j*j*j + print abs(j), abs(j*j), abs(j*j*j), abs(j*j*j*j) + print i/-i + +test() diff --git a/Demo/classes/Dbm.py b/Demo/classes/Dbm.py new file mode 100755 index 0000000..8fccb6a --- /dev/null +++ b/Demo/classes/Dbm.py @@ -0,0 +1,71 @@ +# A wrapper around the (optional) built-in class dbm, supporting keys +# and values of almost any type instead of just string. +# (Actually, this works only for keys and values that can be read back +# correctly after being converted to a string.) + + +def opendbm(filename, mode, perm): + return Dbm().init(filename, mode, perm) + + +class Dbm: + + def init(self, filename, mode, perm): + import dbm + self.db = dbm.open(filename, mode, perm) + return self + + def __repr__(self): + s = '' + for key in self.keys(): + t = `key` + ': ' + `self[key]` + if s: t = t + ', ' + s = s + t + return '{' + s + '}' + + def __len__(self): + return len(self.db) + + def __getitem__(self, key): + return eval(self.db[`key`]) + + def __setitem__(self, key, value): + self.db[`key`] = `value` + + def __delitem__(self, key): + del self.db[`key`] + + def keys(self): + res = [] + for key in self.db.keys(): + res.append(eval(key)) + return res + + def has_key(self, key): + return self.db.has_key(`key`) + + +def test(): + d = opendbm('@dbm', 'rw', 0666) + print d + while 1: + try: + key = eval(raw_input('key: ')) + if d.has_key(key): + value = d[key] + print 'currently:', value + value = eval(raw_input('value: ')) + if value == None: + del d[key] + else: + d[key] = value + except KeyboardInterrupt: + print '' + print d + except EOFError: + print '[eof]' + break + print d + + +test() diff --git a/Demo/classes/README b/Demo/classes/README new file mode 100644 index 0000000..c10001f --- /dev/null +++ b/Demo/classes/README @@ -0,0 +1,11 @@ +Examples of classes that implement special operators (see class.doc): + +Complex.py Complex numbers +Dbm.py Wrapper around built-in dbm, supporting arbitrary values +Range.py Example of a generator: re-implement built-in range() +Rat.py Rational numbers +Vec.py A simple vector class + +(For straightforward examples of basic class features, such as use of +methods and inheritance, see the library code -- especially the window +modules are full of them.) diff --git a/Demo/classes/Range.py b/Demo/classes/Range.py new file mode 100755 index 0000000..b8bc9be --- /dev/null +++ b/Demo/classes/Range.py @@ -0,0 +1,72 @@ +# Example of a generator: re-implement the built-in range function +# without actually constructing the list of values. (It turns out +# that the built-in function is about 20 times faster -- that's why +# it's built-in. :-) + + +# Wrapper function to emulate the complicated range() arguments + +def range(*a): + if len(a) == 1: + start, stop, step = 0, a[0], 1 + elif len(a) == 2: + start, stop = a + step = 1 + elif len(a) == 3: + start, stop, step = a + else: + raise TypeError, 'range() needs 1-3 arguments' + return Range().init(start, stop, step) + + +# Class implementing a range object. +# To the user the instances feel like immutable sequences +# (and you can't concatenate or slice them) + +class Range: + + # initialization -- should be called only by range() above + def init(self, start, stop, step): + if step == 0: + raise ValueError, 'range() called with zero step' + self.start = start + self.stop = stop + self.step = step + self.len = max(0, int((self.stop - self.start) / self.step)) + return self + + # implement `x` and is also used by print x + def __repr__(self): + return 'range' + `self.start, self.stop, self.step` + + # implement len(x) + def __len__(self): + return self.len + + # implement x[i] + def __getitem__(self, i): + if 0 <= i < self.len: + return self.start + self.step * i + else: + raise IndexError, 'range[i] index out of range' + + +# Small test program + +def test(): + import time, builtin + print range(10), range(-10, 10), range(0, 10, 2) + for i in range(100, -100, -10): print i, + print + t1 = time.millitimer() + for i in range(1000): + pass + t2 = time.millitimer() + for i in builtin.range(1000): + pass + t3 = time.millitimer() + print t2-t1, 'msec (class)' + print t3-t2, 'msec (built-in)' + + +test() diff --git a/Demo/classes/Rat.py b/Demo/classes/Rat.py new file mode 100755 index 0000000..0b2519d --- /dev/null +++ b/Demo/classes/Rat.py @@ -0,0 +1,86 @@ +# Rational numbers + + +def rat(num, den): + return Rat().init(num, den) + + +def gcd(a, b): + while b: + a, b = b, a%b + return a + + +class Rat: + + def init(self, num, den): + if den == 0: + raise ZeroDivisionError, 'rat(x, 0)' + g = gcd(num, den) + self.num = num/g + self.den = den/g + return self + + def __repr__(self): + return 'rat' + `self.num, self.den` + + def __cmp__(a, b): + c = a-b + if c.num < 0: + return -1 + if c.num > 0: + return 1 + return 0 + + def __float__(self): + return float(self.num) / float(self.den) + + def __long__(self): + return long(self.num) / long(self.den) + + def __int__(self): + return int(self.num / self.den) + + def __coerce__(a, b): + t = type(b) + if t == type(0): + return a, rat(b, 1) + if t == type(0L): + return a, rat(b, 1L) + if t == type(0.0): + return a.__float__(), b + raise TypeError, 'Rat.__coerce__: bad other arg' + + def __add__(a, b): + return rat(a.num*b.den + b.num*a.den, a.den*b.den) + + def __sub__(a, b): + return rat(a.num*b.den - b.num*a.den, a.den*b.den) + + def __mul__(a, b): + return rat(a.num*b.num, a.den*b.den) + + def __div__(a, b): + return rat(a.num*b.den, a.den*b.num) + + def __neg__(self): + return rat(-self.num, self.den) + + +def test(): + print rat(-1L, 1) + print rat(1, -1) + a = rat(1, 10) + print int(a), long(a), float(a) + b = rat(2, 5) + l = [a+b, a-b, a*b, a/b] + print l + l.sort() + print l + print rat(0, 1) + print rat(1, 0) + print a+1 + print a+1L + print a+1.0 + +test() diff --git a/Demo/classes/Vec.py b/Demo/classes/Vec.py new file mode 100755 index 0000000..6e2bc47 --- /dev/null +++ b/Demo/classes/Vec.py @@ -0,0 +1,65 @@ +# A simple vector class + + +def vec(*v): + return apply(Vec().init, v) + + +class Vec: + + def init(self, *v): + self.v = [] + for x in v: + self.v.append(x) + return self + + + def fromlist(self, v): + self.v = [] + if type(v) <> type([]): + raise TypeError + self.v = v[:] + return self + + + def __repr__(self): + return 'vec(' + `self.v`[1:-1] + ')' + + def __len__(self): + return len(self.v) + + def __getitem__(self, i): + return self.v[i] + + def __add__(a, b): + # Element-wise addition + v = [] + for i in range(len(a)): + v.append(a[i] + b[i]) + return Vec().fromlist(v) + + def __sub__(a, b): + # Element-wise subtraction + v = [] + for i in range(len(a)): + v.append(a[i] - b[i]) + return Vec().fromlist(v) + + def __mul__(self, scalar): + # Multiply by scalar + v = [] + for i in range(len(self.v)): + v.append(self.v[i]*scalar) + return Vec().fromlist(v) + + + +def test(): + a = vec(1, 2, 3) + b = vec(3, 2, 1) + print a + print b + print a+b + print a*3.0 + +test() diff --git a/Demo/classes/class.doc b/Demo/classes/class.doc new file mode 100755 index 0000000..fddc60b --- /dev/null +++ b/Demo/classes/class.doc @@ -0,0 +1,110 @@ +New features of classes +======================= + +A class can implement certain operations that are invoked by special +syntax (such as subscription or arithmetic operations) by defining +methods with special names. + + +Special methods for any type +---------------------------- + +__repr__(self) --> string + +Used by the print statement and conversions (reverse quotes) to +compute the string representation of an object. + +__cmp__(self, other) --> int + +Used by all comparison operations. Should return -1 if self<other, 0 +if self==other, +1 if self>other. Due to limitations in the +interpreter, exceptions raised by comparisons are ignored, and the +objects will be considered equal in this case. + + +Special methods for sequence and mapping types +---------------------------------------------- + +__len__(self) --> int + +Used by the built-in function len(). Should return the length of the +object, which should be >= 0. Also, an object whose __len__() method +returns 0 + +__getitem__(self, key) --> value + +Used to implement value = self[key]. Note that the special +interpretation of negative keys (if the class wishes to emulate a +sequence type) is up to the __getitem__ method. + +__setitem__(self, key, value) + +Used to implement self[key] = value. Same note as for __getitem__. + +__delitem__(self, key) + +Used to implement del self[key]. Same note as for __getitem__. + + +Special methods for sequence types +---------------------------------- + +__getslice__(self, i, j) --> sequence + +Used to implement self[i:j]. Note that missing i or j are replaced by +0 or len(self), respectively, and len(self) has been added to negative +i or j. + +__setslice__(self, i, j, sequence) + +Used to implement self[i:j] = value. Same note as for __getslice__. + +__delslice__(self, i, j) + +Used to implement del self[i:j]. Same note as for __getslice__. + + +Special methods for numeric types +--------------------------------- + +__add__, __sub__, __mul__, __div__, __mod__, __divmod__, __pow__, +__lshift__, __rshift__, __and__, __xor__, __or__ + +Used to implement the binary arithmetic operations (divmod and pow are +called by built-in functions). All have the call pattern +func(self, other) --> number. + +__neg__, __pos__, __abs__, __invert__ + +Used to implement the unary arithmetic operations (-, +, abs and ~). +All have the call pattern func(self) --> number. + +__nonzero__(self) --> int + +Used to implement boolean testing. An alternative name for this +method is __len__. + +__coerce__(self, other) --> (self1, other1) or None + +Used to implement "mixed-mode" numeric arithmetic. Either return a +tuple containing self and other converted to some common type, or None +if no way of conversion is known. When the common type would be the +type of other, it is sufficient to return None, since the interpreter +will also ask the other object to attempt a coercion (but sometimes, +if the implementation of the other type cannot be changed, it is +useful to do the conversion to the other type here). + +__int__(self) --> int +__long__(self) --> long +__float__(self) --> float + +Used to implement the built-in functions int(), long() and float(). + + +Notes +----- + +Except for __repr__ and __cmp__, when no appropriate method is +defined, attempts to execute the operation raise an exception. For +__repr__ and __cmp__, the traditional interpretations are used +in this case. |