Python Programming: Class and Object Oriented Programming

  • Published on
    11-Apr-2017

  • View
    15

  • Download
    1

Embed Size (px)

Transcript

<ul><li><p>Python Intermediate Programming</p><p> (chanshik@gmail.com)</p><p>1</p></li><li><p>Python Intermediate Programming </p><p>2</p></li><li><p> class</p><p>3</p></li><li><p>class </p><p>(class) (instance) </p><p> (), ( ), () </p><p> class </p><p>class </p><p> self </p><p>4</p></li><li><p>class </p><p>class Account(object): num_accounts = 0 def __init__(self, name, balance): self.name = name self.balance = balance Account.num_accounts += 1 def __del__(self): Account.num_accounts -= 1 def deposit(self, amt): self.balance = self.balance + amt def withdraw(self, amt): self.balance = self.balance - amt def inquiry(self): return self.balance</p><p>num_accounts </p><p>5</p></li><li><p> __init__() </p><p>&gt;&gt;&gt; a = Account("Guido", 1000.00)&gt;&gt;&gt; a.balance1000.0&gt;&gt;&gt; a.deposit(100.00)&gt;&gt;&gt; a.balance1100.0&gt;&gt;&gt; Account.deposit(a, 100.00)&gt;&gt;&gt; a.balance1200.0</p><p>6</p></li><li><p>__init__() self (.) </p><p>def __init__(self, name, balance): self.name = name # name </p><p>name </p><p>&gt;&gt;&gt; b = Account("Bill", 2000.00)&gt;&gt;&gt; b.name'Bill'</p><p>(.) </p><p>7</p></li><li><p>&gt;&gt;&gt; class Foo(object):... def bar(self):... print("bar!")... def spam(self):... self.bar()... Foo.bar(self)... bar(self)...&gt;&gt;&gt; Foo().spam()bar!bar!Traceback (most recent call last): File "", line 1, in File "", line 7, in spamNameError: name 'bar' is not defined 8</p></li><li><p> C++ </p><p>C++ this self </p><p> self </p><p>self.a = 10 # a = 20 # </p><p>9</p></li><li><p>(inheritance) </p><p> : (base class) (superclass) : (derived class) (subclass)</p><p> class object </p><p>object </p><p>10</p></li><li><p>&gt;&gt;&gt; class SavingAccount(Account):... def withdraw(self, amt):... if self.balance - amt &gt;= 0:... self.balance -= amt... else:... raise ValueError("balance - amt &lt; 0")...&gt;&gt;&gt; s = SavingAccount("John", 10.00)&gt;&gt;&gt; s.deposit(10.0) # Account.deposit(s, 10.0)&gt;&gt;&gt; s.withdraw(30.0) # SavingAccount.withdraw(s, 30.0)Traceback (most recent call last): File "", line 1, in File "", line 6, in withdrawValueError: balance must be greater than zero</p><p>11</p></li><li><p>(.) </p><p>s.withdraw() SavingAccount </p><p>s.deposit() Account deposit() </p><p> __init__() </p><p> __init__() __init__() __init__() </p><p>12</p></li><li><p>class SavingAccount(Account): def __init__(self, name, balance, interest_rate): Account.__init__(self, name, balance) self.interest_rate = interest_rate</p><p>Account.__init__() </p><p> __init__() __init__() </p><p>&gt; </p><p>13</p></li><li><p> self </p><p>deposit() Account self </p><p>class BasicSavingAccount(SavingAccount): def deposit(self, amt): self.withdraw(1.00) # SavingAccount.deposit(self, amt) # </p><p>14</p></li><li><p> super() </p><p>Python 3</p><p>class BasicSavingAccount(SavingAccount): def deposit(self, amt): self.withdraw(1.00) super().deposit(amt)</p><p>Python 2</p><p>class BasicSavingAccount(SavingAccount): def deposit(self, amt): self.withdraw(1.00) super(BasicSavingAccount, self).deposit(amt)</p><p>super(cls, instance) </p><p>15</p></li><li><p> (multiple inheritance) </p><p>class DepositCharge(object): fee = 1.00 def deposit_fee(self): self.withdraw(self.fee) # self.fee 1.00 ?</p><p>class WithdrawCharge(object): fee = 2.00 def withdraw_fee(self): self.withdraw(self.fee) # self.fee 2.00 ?</p><p>class FreeSavingAccount(BasicSavingAccount, DepositCharge, WithdrawCharge): def deposit(self, amt): self.deposit_fee() super().deposit(amt) def withdraw(self, amt): super().withdraw(amt)</p><p>16</p></li><li><p>&gt;&gt;&gt; f = FreeSavingAccount("John", 100.0, 0.10)&gt;&gt;&gt; f.deposit_fee()&gt;&gt;&gt; f.balance99.0 # self.fee 1.00&gt;&gt;&gt; f.withdraw_fee()&gt;&gt;&gt; f.balance98.0 # self.fee 1.00</p><p>withdraw_fee() self.fee WithdrawCharge() DepositCharge() </p><p>17</p></li><li><p> __mro__ (Method Resolution Order)</p><p>&gt;&gt;&gt; FreeSavingAccount.__mro__(, , , , , , )</p><p>18</p></li><li><p>&gt;&gt;&gt; class X(object):... pass...&gt;&gt;&gt; class Y(X):... pass...&gt;&gt;&gt; class Z(X, Y):... pass...Traceback (most recent call last): File "", line 1, in TypeError: Cannot create a consistent method resolutionorder (MRO) for bases X, Y</p><p>19</p></li><li><p> Z TypeError</p><p> X Y Y X X Y </p><p> (mixin class) </p><p>DepositCharge, WithdrawCharge </p><p>20</p></li><li><p> (dynamic binding) </p><p>obj.attr </p><p> attr </p><p>21</p></li><li><p>obj.name name </p><p> (duck typing)" , , "</p><p>22</p><p>http://obj.name/</p></li><li><p> (static method) </p><p>@staticmethod self </p><p>&gt;&gt;&gt; class Foo(object):... @staticmethod... def add(x, y):... return x + y...&gt;&gt;&gt; Foo.add(1, 2)3&gt;&gt;&gt; Foo.add(3, 4)7&gt;&gt;&gt;</p><p> 23</p></li><li><p>&gt;&gt;&gt; import time&gt;&gt;&gt; class Date(object):... def __init__(self, year, month, day):... self.year = year... self.month = month... self.day = day... @staticmethod... def now():... t = time.localtime()... return Date(t.tm_year, t.tm_mon, t.tm_mday)... @staticmethod... def tomorrow():... t = time.localtime(time.time() + 86400)... return Date(t.tm_year, t.tm_mon, t.tm_mday)...&gt;&gt;&gt; d = Date(2017, 1, 1)&gt;&gt;&gt; d.year, d.month, d.day(2017, 1, 1)&gt;&gt;&gt; now = Date.now()&gt;&gt;&gt; now.year, now.month, now.day(2017, 1, 17)</p><p>24</p></li><li><p> (class method) </p><p>@classmethod cls </p><p>&gt;&gt;&gt; class Times(object):... factor = 1... @classmethod... def mul(cls, x):... return cls.factor * x...&gt;&gt;&gt;&gt;&gt;&gt; class TwoTimes(Times):... factor = 2...&gt;&gt;&gt; TwoTimes.mul(2) # Times.mul(TwoTimes, 2) 4&gt;&gt;&gt; TwoTimes.mul(4) # Times.mul(TwoTimes, 4) 8</p><p>25</p></li><li><p>Date EuroDate </p><p>&gt;&gt;&gt; class EuroDate(Date):... def __str__(self):... return "%02d/%02d/%04d" % (self.day, ... self.month, ... self.year)...</p><p>&gt;&gt;&gt; e = EuroDate(2017, 1, 1)&gt;&gt;&gt; type(e)</p><p>&gt;&gt;&gt; print(e)01/01/2017&gt;&gt;&gt; now = EuroDate.now()&gt;&gt;&gt; type(now)</p><p>&gt;&gt;&gt; print(now)</p><p>26</p></li><li><p>EuroDate.now(), EuroDate.tomorrow() EuroDate Date </p><p>&gt;&gt;&gt; class Date(object):... def __init__(self, year, month, day):... self.year = year... self.month = month... self.day = day... @classmethod... def now(cls):... t = time.localtime()... return cls(t.tm_year, t.tm_mon, t.tm_mday)... @classmethod... def tomorrow(cls):... t = time.localtime(time.time() + 86400)... return cls(t.tm_year, t.tm_mon, t.tm_mday)...</p><p>27</p></li><li><p>&gt;&gt;&gt; class Date(object):... def __init__(self, year, month, day):... self.year = year... self.month = month... self.day = day... def __str__(self):... return "%04d-%02d-%02d" % (self.year, self.month, self.day)... @classmethod... def now(cls):... t = time.localtime()... return cls(t.tm_year, t.tm_mon, t.tm_mday)... @classmethod... def tomorrow(cls):... t = time.localtime(time.time() + 86400)... return cls(t.tm_year, t.tm_mon, t.tm_mday)...&gt;&gt;&gt; print(Date.now())2017-01-17&gt;&gt;&gt; print(EuroDate.now())17/01/2017</p><p>28</p></li><li><p> , </p><p>&gt;&gt;&gt; d = Date(2017, 1, 1)&gt;&gt;&gt; now = d.now()&gt;&gt;&gt; print(now)2017-01-18</p><p>29</p></li><li><p>(property) </p><p>&gt;&gt;&gt; import math&gt;&gt;&gt; class Circle(object):... def __init__(self, radius):... self.radius = radius... @property... def area(self):... return math.pi * self.radius ** 2... @property... def perimeter(self):... return 2 * math.pi * self.radius...&gt;&gt;&gt; c = Circle(2.0)&gt;&gt;&gt; c.radius2.0</p><p>30</p></li><li><p> @property "()" </p><p>&gt;&gt;&gt; c.area12.566370614359172&gt;&gt;&gt; c.perimeter12.566370614359172&gt;&gt;&gt; c.area = 10Traceback (most recent call last): File "", line 1, in AttributeError: can't set attribute</p><p> AttributeError </p><p>31</p></li><li><p> (uniform access principle)</p><p> c.radius c.area()</p><p> "()" </p><p>32</p></li><li><p>&gt;&gt;&gt; class Foo(object):... def __init__(self, name):... self.__name = name... @property... def name(self):... return self.__name... @name.setter... def name(self, value):... if not isinstance(value, str):... raise TypeError("Must be a string")... self.__name = value... @name.deleter... def name(self):... raise TypeError("Can't delete name")...</p><p>33</p></li><li><p>&gt;&gt;&gt; f = Foo("John")&gt;&gt;&gt; f.name = "Jane"&gt;&gt;&gt; f.name = 42Traceback (most recent call last): File "", line 1, in File "", line 10, in nameTypeError: Must be a string&gt;&gt;&gt; del f.nameTraceback (most recent call last): File "", line 1, in File "", line 14, in nameTypeError: Can't delete name</p><p> name @property </p><p>@name.setter @name.deleter </p><p>34</p></li><li><p> private </p><p> (name mangling) __Foo ___Foo </p><p> private </p><p> private </p><p>35</p></li><li><p> private </p><p>class A(object): def __init__(self): self.__X = 3 # self._A__X def __spam(self): # _A__spam() print(self.__X) def bar(self): self.__spam()</p><p>class B(A): def __init__(self): A.__init__(self) self.__X = 37 # self._B__X def __spam(self): # _B__spam() print(self.__X) def bar(self): self.__spam()</p><p>36</p></li><li><p> private </p><p> private </p><p>&gt;&gt;&gt; a = A()&gt;&gt;&gt; a.bar()3&gt;&gt;&gt; b = B()&gt;&gt;&gt; b.bar()37&gt;&gt;&gt; dir(b)['_A__X', '_A__spam', '_B__X', '_B__spam', '__class__', ... &gt;&gt;&gt; b._A__X3</p><p>37</p></li><li><p> __new__() __init__() </p><p>&gt;&gt;&gt; class Circle(object):... def __init__(self, radius):... self.radius = radius...&gt;&gt;&gt; c = Circle(2.0)&gt;&gt;&gt; &gt;&gt;&gt; d = Circle.__new__(Circle, 2.0)&gt;&gt;&gt; if isinstance(c, Circle):... Circle.__init__(c, 2.0)&gt;&gt;&gt;&gt;&gt;&gt; c.radius2.0&gt;&gt;&gt; d.radius2.0...</p><p>38</p></li><li><p> __new__() __new__(cls, *args, **kwargs) </p><p> __new__() </p><p> , , </p><p> __new__() </p><p>&gt;&gt;&gt; class UpperStr(str):... def __new__(cls, value=""):... return str.__new__(cls, value.upper())...&gt;&gt;&gt; s = UpperStr("Hello, World!")&gt;&gt;&gt; s'HELLO, WORLD!'</p><p> 39</p></li><li><p> __del__() </p><p>del 0 __del__() close() </p><p>40</p></li><li><p> __dict__ </p><p>__dict__ </p><p>&gt;&gt;&gt; a = Account('Bill', 2000.0)&gt;&gt;&gt; a.__dict__{'name': 'Bill', 'balance': 2000.0}&gt;&gt;&gt; a.number=1&gt;&gt;&gt; a.__dict__{'name': 'Bill', 'balance': 2000.0, 'number': 1}</p><p> __dict__ </p><p>41</p></li><li><p> __class__ </p><p> __dict__ </p><p>&gt;&gt;&gt; a.__class__</p><p>&gt;&gt;&gt; Account.__dict__.keys()dict_keys(['__module__', 'num_accounts', '__init__', '__del__', 'deposit', 'withdraw', 'inquiry', '__dict__', '__weakref__', '__doc__'])</p><p>42</p></li><li><p> __bases__ </p><p>&gt;&gt;&gt; FreeSavingAccount.__bases__(, , )</p><p>43</p></li><li><p>obj.name = value obj.__setattr__("name", value) </p><p>del obj.name obj.__delattr__("name") </p><p>obj.name obj.__getattribute__("name") </p><p>obj.__getattribute__() </p><p> __dict__ __dict__ </p><p> __getattr__() AttributeError 44</p><p>http://obj.name/http://obj.name/http://obj.name/</p></li><li><p>class Circle(object): def __init__(self, radius): self.radius = radius def __getattr__(self, name): if name == 'area': return math.pi * self.radius ** 2 elif name == 'perimeter': return 2 * math.pi * self.radius else: return object.__getattribute__(self, name) def __setattr__(self, name, value): if name in ['area', 'perimeter']: raise TypeError("%s is readonly" % name) object.__setattr__(self, name, value)</p><p>45</p></li><li><p>&gt;&gt;&gt; c = Circle(2.0)&gt;&gt;&gt; c.area12.566370614359172&gt;&gt;&gt; c.perimeter12.566370614359172&gt;&gt;&gt; c.name = "Circle"&gt;&gt;&gt; c.area = 20Traceback (most recent call last): File "", line 1, in File "", line 13, in __setattr__TypeError: area is readonly</p><p>46</p></li><li><p>__slots__</p><p> __slots__ </p><p>class Stock(object): __slots__ = ("name", "qty") def __init__(self, name, qty): self.name = name self.qty = qty</p><p> AttributeError </p><p>&gt;&gt;&gt; s = Stock("pen", 100)&gt;&gt;&gt; s.tag = "pen"Traceback (most recent call last): File "", line 1, in AttributeError: 'Stock' object has no attribute 'tag'</p><p>47</p></li><li><p>__slots__</p><p> __slots__ </p><p>__slots__ </p><p>__slots__ __slots__ __dict__ </p><p>48</p></li><li><p> __add__() </p><p> ( )</p><p>class Complex(object): def __init__(self, real, imag=0): self.real = float(real) self.imag = float(imag) def __repr__(self): return "Complex(%s, %s)" % (self.real, self.imag) def __str__(self): return "(%g+%gj)" % (self.real, self.imag) def __add__(self, other): return Complex(self.real + other.real, self.imag + other.imag) def __sub__(self, other): return Complex(self.real - other.real, self.imag - other.imag)</p><p>49</p></li><li><p>__repr__() </p><p>__str__()</p><p>print() </p><p>__add__() "+" </p><p>__sub__() "" </p><p> Complex </p><p>50</p></li><li><p>&gt;&gt;&gt; a = Complex(3, 2)&gt;&gt;&gt; b = Complex(2, 3)&gt;&gt;&gt; a + bComplex(5.0, 5.0)&gt;&gt;&gt; a + 4.0Complex(7.0, 2.0)&gt;&gt;&gt; 4.0 + aTraceback (most recent call last): File "", line 1, in TypeError: unsupported operand type(s) for +: 'float' and 'Complex'</p><p> .real, .imag "+" Complex other </p><p>51</p></li><li><p>&gt;&gt;&gt; 4.0 + a</p><p> Complex </p><p> Complex </p><p> ... def __radd__(self, other): return Complex(self.real + other.real, self.imag + other.imag) def __rsub__(self, other): return Complex(self.real - other.real, self.imag - other.imag) ...</p><p>&gt;&gt;&gt; a = Complex(3, 2)&gt;&gt;&gt; 4.0 + aComplex(7.0, 2.0)</p><p>52</p></li><li><p>isinstance(obj, cname) obj cname cname True</p><p>class A(object): pass</p><p>class B(A): pass</p><p>class C(object):pass</p><p>&gt;&gt;&gt; type(a)</p><p>&gt;&gt;&gt; isinstance(a, A)True&gt;&gt;&gt; isinstance(b, A)True&gt;&gt;&gt; isinstance(b, C)False</p><p>53</p></li><li><p>issubclass(A, B) A B True </p><p>&gt;&gt;&gt; issubclass(B, A)True&gt;&gt;&gt; issubclass(C, A)False</p><p>54</p></li><li><p>class Foo(object): def spam(self, a, b): pass</p><p>class FooProxy(object): def __init__(self, f): self.f = f def spam(self, a, b): return self.f.spam(a, b)</p><p>&gt;&gt;&gt; f = Foo()&gt;&gt;&gt; g = FooProxy(f)&gt;&gt;&gt; isinstance(g, Foo)False</p><p>55</p></li><li><p> Foo Foo isinstance(), issubclass() </p><p>class IClass(object): def __init__(self): self.implementors = set() def register(self, C): self.implementors.add(C) def __subclasscheck__(self, sub): return any(c in self.implementors for c in sub.mro()) def __instancecheck__(self, x): return self.__subclasscheck__(type(x))</p><p>56</p></li><li><p> IClass </p><p>register(): </p><p>__instancecheck__(): isinstance __subclasscheck__(): issubclass </p><p>IFoo </p><p>&gt;&gt;&gt; IFoo = IClass()&gt;&gt;&gt; IFoo.register(Foo)&gt;&gt;&gt; IFoo.register(FooProxy)&gt;&gt;&gt; f = Foo()&gt;&gt;&gt; g = FooProxy(f)&gt;&gt;&gt; isinstance(f, IFoo)True&gt;&gt;&gt; isinstance(g, IFoo)True&gt;&gt;&gt; issubclass(FooProxy, IFoo)True</p><p>57</p></li><li><p> (abstract base class) </p><p>abc ABCMeta, @abstractmethod, @abstractproperty </p><p>class Foo: # Python 2 __metaclass__ = ABCMeta</p><p>from abc import ABCMeta, abstractmethod, abstractpropertyclass Foo(metaclass=ABCMeta): # Python 3 @abstractmethod def spam(self, a, b): pass @abstractproperty def name(self): pass</p><p>58</p></li><li><p> ABCMeta </p><p> @abstractmethod, @abstractproperty Foo </p><p>&gt;&gt;&gt; f = Foo()Traceback (most recent call last): File "", line 1, in TypeError: Can't instantiate abstract class Foo with abstract methods name, spam</p><p>Foo </p><p>59</p></li><li><p>60</p></li><li><p>class Grok(object): def spam(self, a, b): print("Grok.spam")</p><p>register() </p><p>&gt;&gt;&gt; Foo.register(Grok)</p><p>&gt;&gt;&gt; g = Grok()&gt;&gt;&gt; isinstance(g, Foo)True</p><p>61</p></li><li><p>&gt;&gt;&gt; class Foo(object):... pass......</p></li></ul>