class Account: _total_deposits = 0 def __init__(self, initial_balance): self._balance = initial_balance Account._total_deposits += initial_balance def balance(self): return self._balance def deposit(self, amount): if amount < 0: raise ValueError("negative deposit") self._balance += amount Account._total_deposits += amount def withdraw(self, amount): if 0 <= amount <= self._balance: self._balance -= amount Account._total_deposits -= amount else: raise ValueError("bad withdrawal") @staticmethod def total_deposits(): return Account._total_deposits Account.__doc__ = """ >>> acct1 = Account(1000) >>> acct1.balance() 1000 >>> acct1.deposit(100) >>> acct1.balance() 1100 >>> acct1.withdraw(50) >>> acct1.balance() 1050 >>> acct2 = Account(200) >>> acct1.total_deposits() 1250 >>> acct2.total_deposits() 1250 >>> Account.total_deposits() 1250 """ # RATIONAL CLASS # An extended example with bells and whistles. from math import gcd import re # By convention, function names prefixed with a single "_" are private to # the file or class in which they appear. def _rational(n): """Returns N as a rational. Returns N itself if already rational. We use this rather than rational(n) to avoid creating new rational objects unnecessarily""" if type(n) is rational: return n else: return rational(n) class rational: # Literals and conversions def __init__(self, n, d=1): if type(n) is not int and d != 1: raise ValueError("improper conversion to rational") elif type(n) is float: n, d = n.as_integer_ratio() elif type(n) is str: self._init_from_str(n) return elif type(n) is rational: self._numer = n.numer self._denom = n.denom return if type(d) is not int or d == 0: raise ValueError("bad denominator") g = gcd(n, d) if d > 0 else -gcd(n, d) self._numer = n // g self._denom = d // g def __int__(self): """Convert me to type int, rounding towards 0.""" if self.numer > 0: return self.numer // self.denom else: return -((-self.numer) // self.denom) def __float__(self): """Converts to nearest floating-point number""" return self.numer / self.denom def __bool__(self): """Indicates which values are "true values". In this case, all non-zero values are true.""" return self.numer != 0 def __round__(self): """Result of rounding to nearest int, with ties rounding to even.""" q = self.numer // self.denom m = self.numer % self.denom return q+1 if 2*m + (q & 1) > q else q def __str__(self): """The printed version of self.""" if self.denom == 1: return str(self.numer) else: return "{}/{}".format(self.numer, self.denom) def __repr__(self): """A string giving an expression that evaluates to self.""" return "rational({}, {})".format(self.numer, self.denom) def _init_from_str(self, s): """Initializes self from the string S, a rational literal.""" m = re.match(r'(-?\d+)(?:/(\d+))', s) if not m: raise ValueError("invalid rational literal") n = int(m.group(1)) d = int(m.group(2)) or 1 self.__init__(n, d) # Accessors @property def numer(self): return self._numer @property def denom(self): return self._denom # Arithmetic def __add__(self, other): """ self + other """ other = _rational(other) return rational(self.numer * other.denom + other.numer * self.denom, self.denom * other.denom) def __sub__(self, other): """ self - other """ other = _rational(other) return rational(self.numer * other.denom - other.numer * self.denom, self.denom * other.denom) def __mul__(self, other): """ self * other """ other = _rational(other) return rational(self.numer * other.numer, self.denom * other.denom) def __truediv__(self, other): """ self / other """ other = _rational(other) return rational(self.numer * other.denom, self.denom * other.numer) def __floordiv__(self, other): """ self // other """ other = _rational(other) return rational((self.numer * other.denom) // (self.denom * other.numer)) def __divmod__(self, other): """ self // other, self % other """ return self // other, self % other def __neg__(self): """ -self """ return rational(-self.numer, self.denom) def __pos__(self): """ +self """ return self # The __r...__ operators are for cases such as 1 + rational(3,7), where # the type of the left operand does not implement the desired operator. # For example, in the expression 1 + rational(3,7), Python will call # rational(3, 7).__radd__(1), which does know how to handle an integer # argument. def __radd__(self, other): return self + other def __rsub__(self, other): return -self + other def __rmul__(self, other): return self * other def __rtruediv__(self, other): return rational(other) / self def __rfloordiv__(self, other): return rational(other) // self # Comparisons def __lt__(self, other): """ self < other """ other = _rational(other) return self.numer * other.denom < other.numer * self.denom def __gt__(self, other): """ self > other """ return other < self def __le__(self, other): """ self <= other """ other = _rational(other) return self.numer * other.denom <= other.numer * self.denom def __ge__(self, other): """ self >= other """ return other <= self def __eq__(self, other): """ self == other """ return self.numer == other.numer and self.denom == other.denom # Special def __hash__(self): return hash(self.numer) ^ hash(self.denom)