파이썬3 바이블 - 제14장 연습문제

프리렉 - FREELEC

http://freelec.co.kr/book/catalogue_view.asp?UID=134

이강성저

1.

In [1]:
class MyStr:
    def __init__(self, s):
        self.s = s
    def __add__(self, s):
        return MyStr(self.s + str(s))
    def __sub__(self, o):
        try:
            k = self.s.index(o)
            return MyStr(self.s[:k]+self.s[k+len(o):])
        except ValueError:
            return self
    def __repr__(self):
        return "MyStr('{}')".format(self.s)
In [2]:
a = MyStr("I like python and python")
a
Out[2]:
MyStr('I like python and python')
In [3]:
a + " stuff"
Out[3]:
MyStr('I like python and python stuff')
In [4]:
a - "python"
Out[4]:
MyStr('I like  and python')

2.

In [5]:
class Square:
    def __init__(self, n):
        self.n = n
    def __getitem__(self, k):
        if 0 <= k <= self.n:
            return k*k
        raise IndexError("out of range {}".format(k))
In [6]:
s = Square(10)
s[2]
Out[6]:
4
In [7]:
s[9]
Out[7]:
81
In [8]:
list(s)
Out[8]:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
In [9]:
for ele in s:
    print (ele, end=' ')
0 1 4 9 16 25 36 49 64 81 100 

3.

In [10]:
class Counter:
    def __init__(self, n=0):
        self.n = n
        self.step = 1
    def incr(self):
        self.n += self.step
    def __repr__(self):
        return '{}'.format(self.n)
    def __str__(self):
        return '{}'.format(self.n)
    def __call__(self):
        self.incr()
        return self.n
In [11]:
c = Counter()
c.incr()
c
Out[11]:
1
In [12]:
c = Counter()
c()
Out[12]:
1
In [13]:
c()
Out[13]:
2

4.

우선 __new__ 메서드를 이용한 싱글톤은 436-437페이지 참조

아무 문제없이 동작하는 싱글톤을 작성하기는 쉽지 않다. 다양한 싱글톤 구현 방법이 있지만 또한 각자의 문제를 안고 있다. 여기서는 __new__ 메서드를 이용한 싱글톤과 장식자를 이용한 싱글톤을 살펴보자.

In [14]:
# __new__ 메서드를 이용한 싱글톤 - 다중 상속인 경우

class Singleton(object):
  _instance = None
  def __new__(class_, *args, **kwargs):
    if not isinstance(class_._instance, class_):
        class_._instance = object.__new__(class_, *args, **kwargs)
    return class_._instance


class BaseClass:
    pass

class MyClass(Singleton, BaseClass):
    pass

a = MyClass()
b = MyClass()
a is b
Out[14]:
True
In [15]:
# __new__ 메서드를 이용한 싱글톤 - 순서가 바뀌고 __new__ 메서드가 중복되면 싱글톤 기능을 하지 못할 수 도 있다.

class Singleton(object):
  _instance = None
  def __new__(class_, *args, **kwargs):
    if not isinstance(class_._instance, class_):
        class_._instance = object.__new__(class_, *args, **kwargs)
    return class_._instance


class BaseClass:
    def __new__(class_, *args, **kwargs):
        return object.__new__(class_, *args, **kwargs)

class MyClass(BaseClass, Singleton):
    pass

a = MyClass()
b = MyClass()
a is b
Out[15]:
False
In [16]:
def singleton(class_):
  instances = {}
  def getinstance(*args, **kwargs):
    if class_ not in instances:
        instances[class_] = class_(*args, **kwargs)
    return instances[class_]
  return getinstance

@singleton
class MyClass(BaseClass):
    pass

m1 = MyClass()
m2 = MyClass()

m1 is m2
Out[16]:
True
In [17]:
MyClass   # 클래스가 아닌 함수
Out[17]:
<function __main__.getinstance>
In [18]:
type(m2)  # 반면에 인스턴스 객체의 자료형은 클래스이다. 뭔가 불일치 발생
Out[18]:
__main__.MyClass
In [19]:
type(m2) == MyClass  # 따라서 이 것도 다를 수 밖에 없다.
Out[19]:
False
In [20]:
o = type(m2)()
m1 is o             # 이런..
Out[20]:
False

5.

In [21]:
class BNode:
    def __init__(self, value=None, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right
    def __repr__(self):
        sleft = repr(self.left).replace('\n', '\n    ')
        sright = repr(self.right).replace('\n', '\n    ')
        return '%s (\n    %s\n    %s)' % (self.value, sleft, sright)

root = BNode('root')
root.left = BNode('left')
root.right = BNode('right')
root.left.left = BNode('left-left')
root.left.right = BNode('left-right')
print (root)
root (
    left (
        left-left (
            None
            None)
        left-right (
            None
            None))
    right (
        None
        None))

In [22]:
class BNode:
    def __init__(self, value=None, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right
    def __repr__(self):
        indent = 4
        sleft = repr(self.left).replace('\n', '\n'+' '*indent)
        sright = repr(self.right).replace('\n', '\n'+' '*indent)
        return '{0} (\n{1}{2}\n{1}{3})'.format(self.value, ' '*indent, sleft, sright)
    
root = BNode('root')
root.left = BNode('left')
root.right = BNode('right')
root.left.left = BNode('left-left')
root.left.right = BNode('left-right')
print (root)    
root (
    left (
        left-left (
            None
            None)
        left-right (
            None
            None))
    right (
        None
        None))

In [22]: