160
PYTHON 객객객객 객객객객 Moon Yong Joon

파이썬+객체지향+이해하기 20160131

Embed Size (px)

Citation preview

PYTHON객체지향 이해하기Moon Yong Joon

기술적접근

객체

왜 모든 것을 객체로 관리하나 ?

모든 것은 객체

값 문자열컨테이너

함수클래스

튜플리스트

딕션너리

집합

파이썬은 모든 것을 객체로 인식한다 . 데이터 구조가 다 객체이므로 클래스를 가지고 생성시 참조를 가지고 있음

파일모듈 패키지

모듈

객체로 구성했나 ?실제 오퍼페이터를 내부적으로 메소드로 정의되어 있어서 메소드 처리로 인식되고 테이터 타입을 명확히 맞춰서 계산처리 됨

1.+(1) 1

__add__( 객체 )

>>> 1+12>>> >>> 1.+12.0>>> int(1.+1)2>>> >>> p=1>>> p.__add__(1)2>>>

클래스 정의

Class Notation파이썬 언어에서 객체를 만드는 타입을 Class 를 정의하여 사용

클래스 명변수

메소드

class 클래스이름 [( 상속 클래스명 )]:

< 클래스 변수 1> < 클래스 변수 2> ... def 인스턴스 메소드 (self[, 인수 1, 인수 2,,,]): < 수행할 문장 1> < 수행할 문장 2> ... def 클래스메소드 (cls[, 인수 1, 인수 2,,,]): < 수행할 문장 1> < 수행할 문장 2> ... def 정적메소드 ([, 인수 1, 인수 2,,,]): < 수행할 문장 1> < 수행할 문장 2> ...

Instance Notation인스턴스 객체는 실제 클래스 객체가 생성시 할당인스턴스 변수와 메소드는 런타임 즉 실행시 등록하여 사용할 수 있음

인스턴스명 : 클래스명인스턴스 변수

인스턴스 메소드( 인스턴스 바인딩 경우 )

class 클래스이름 [( 상속 클래스명 )]: def __init__(self[, 인수 1, 인수 2,,,]): self. 변수명 = 인수 1 …… < 수행할 문장 2> ... def 인스턴스메소드 (self[, 인수 1, 인수 2,,,]): < 수행할 문장 1> < 수행할 문장 2> ... ...

Instance 명 = 클래스명 ( 초기인자들 )

Class 로 Instance 처리파이썬 언어에서 객체를 만드는 타입을 Class 로 생성해서 처리Class 는 객체를 만드는 하나의 틀로 이용자바 언어와의 차이점은 Class 도 Object 로 인식

Class Object

Instance Object 1

Instance Object 2

Instance Object 3

instanciate

클래스에서 객체 생성하기

Class Member

Class MemberClass Object 는 클래스 메소드 , 정적메소드 , 클래스 내부 변수 등을 관리한다 .

class Class_Member : cls_var = 0 @classmethod def cls_method(cls) : cls.cls_var = 1 print("call cls_method ", cls.cls_var)

@staticmethod def sta_method() : cls_var = 100 print("call sta_method ", cls_var)

def ins_method(self) : self.ins_var = 1 print('call ins method ', self.ins_var)

c = Class_Member()c.ins_method()print(c.__dict__)

클래스 변수클래스 객체 메소드클래스 정적 메소드

# 처리결과('call cls_method ', 1)('call sta_method ', 100)#Class_Member 내부 관리 영역{'sta_method': <staticmethod object at 0x0215A650>, '__module__': '__main__', 'ins_method': <function ins_method at 0x029D2270>, 'cls_method': <classmethod object at 0x01D92070>, 'cls_var': 1, '__doc__': None}

인스턴스 메소드

Predefined Class At-tributes

Attribute Type Read/Write Description

__dict__ dictionary R/W The class name space.

__name__ string R/O The name of the class.

__bases__ tuple of classes R/O The classes from which this class inherits.

__doc__ string OR None R/W The class documentation string

__module__ string R/W The name of the module in which this class was defined.

Instance MemberInstance 생성시 self 로 정의된 변수만 인스턴스 영역에서 관리하고 인스턴스 메소드는 클래스에서 관리함

class Class_Member : cls_var = 0 @classmethod def cls_method(cls) : cls.cls_var = 1 print("call cls_method ", cls.cls_var) @staticmethod def sta_method() : cls_var = 100 print("call sta_method ", cls_var)

def ins_method(self) : self.ins_var = 1 print('call ins method ', self.ins_var)

c = Class_Member()c.ins_method()print(c.__dict__)

인스턴스 변수

# 처리결과('call ins method ', 1){'ins_var': 1} # 인스턴스 객체 관리 영역

Predefined Instance Attributes

Attribute Type Read/Write Description

__dict__ dictionary R/W The instance name space.

__class__ Base class R The base class

__doc__ string OR None R/W The instance documentation string

클래스와 인스턴스 구조

Object Namespace 흐름Base class

class

in-stance

in-stance

in-stance

상속

인스턴스 생성

Dict{}

Dict{}

Dict{} Dict{} Dict{}

Namespace 검색

객체는 자신들이 관리하는 Namespace 공간을 생성하며 객체 내의 속성이나 메소드 호출시 이를 검색해서 처리

Class & instance scopeClass Object 는 인스턴스를 만드는 기준을 정리한다 . 클래스를 정의한다고 하나의 저장공간 (Namespace) 기준이 되는 것은 아니다 . - 클래스 저장공간과 인스턴스 저장공간이 분리된다

User de-finedClass

Instance

Instance

Instance

Built-inClass

상속 인스턴스화

Object Scope

Object Namespace

Class/Instance 관계 매핑 Class 키워드로 클래스 정의 상속은 class 키워드 다음 () 내에 상속할 클래스 정의 인스턴스 생성은 클래스명에 () 연산자 사용

Super ClassClassinstance

상속인스턴스화

class A(object): def whoami(self): return self.__class__.__name__

a = A()

Class/Instance 관계 보기 내장 변수를 이용해서 Class 와 Instance 관계를 확인

class A(object): def whoami(self): return self.__class__.__name__

a = A()

print a.whoami()print a.__class__.__base__.__name__

인스턴스의 클래스 이름: A

인스턴스의 클래스의 상속 클래스 이름: object

생성자와 소멸자

생성자 처리 구조파이썬은 생성자는 클래스이 __init__() 메소드를 binding 하여 처리

Instance = ClassA( 인자 ) ClassA.__init__(instance, 인자 )

ClassA( 상위클래스 ) : def __init__(self, 인자 ) : # 생성자로직

Source code Execute code

생성자 -Creating Instance 파이썬 생성자 __init__() 함수를 오버라이딩한 후클래스이름 ( 파라미터 ) 를 이용하여 객체 생성생성자 함수는 자동으로 연계됨

class Employee: 'Common base class for all employees' empCount = 0

def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1

"This would create first object of Employee class"emp1 = Employee("Zara", 2000)"This would create second object of Employee class"emp2 = Employee("Manni", 5000)

생성자 정의

인스턴스 객체 생성생성자와 자동으로 연계

소멸자 - Destroying Objects클래스의 생성된 인스턴스를 삭제하는 메소드

#!/usr/bin/python

class Point: def __init( self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print class_name, "destroyed"

pt1 = Point()pt2 = pt1pt3 = pt1print id(pt1), id(pt2), id(pt3) # prints the ids of the obejctsdel pt1del pt2del pt3

소멸자 정의

소멸자 활용

인스턴스 생성과 인스턴스 호출

__init__ 과 __call__ 메소드 차이클래스 생성자에 따른 인스턴스 생성 및 인스턴스 호출에 대한 내장메소드 처리

class A: def __init__(self): print "init“ def __call__(self): print "call"

A() # initA()() # init call

a = A() #inita() # call

생성자와 인스턴스 호출 메소드 정의

생성자와 인스턴스 호출 메소드 정의

인스턴스 속성 미정의 후 생성클래스 생성자에 인스턴스 속성을 미정의하고 인스턴스를 호출시 실제 인스턴스가 없으므로 오류처리

>>> class A: ... def __init__(self): ... print "From init ... " ... >>> a = A()From init ...>>> a() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: A instance has no __call__ method>>>

인스턴스 속성 미정의 후 호출인스턴스 속성 미정의할 경우 반드시 인스턴스 처리하는 __call__ 메소드를 정의하여 처리해야 함

>>> class B:... def __init__(self):... print "From init ... "... def __call__(self):... print "From call ... "... >>> b = B()From init ... >>> b()From call ... >>>

Class decorator : 기본 생성자에서 함수 전달 , 인스턴스 호출에서 함수의 파라미터 전달 전달함수 실행시 생성자 실행 및 인스턴스 실행

# 테코레이터 클래스 정의하고 생성자에 전달class decoratorWithoutArguments(object): def __init__(self, f): print ("Inside __init__()") self.f = f

# 호출하는 곳에 내부함수 처리 로직 처리 def __call__(self, *args): print( "Inside __call__()") self.f(*args) print( "After self.f(*args)")

# 데코레이터 정의 및 전달함수 정의@decoratorWithoutArgumentsdef sayHello(a1, a2, a3, a4): print( 'sayHello arguments:', a1, a2, a3, a4)

데코레이터 클래스 정의 전달 함수 정의 함수 실행# 데코레이터 호출 print ("Preparing to call sayHello()")

sayHello("say", "hello", "argument", "list")

print ("After first sayHello() call")

sayHello("a", "different", "set of", "argu-ments")

print ("After second sayHello() call"))

메소드 접근자

Class 멤버 접근자 - cls클래스 객체의 변수나 메소드 접근을 위해 cls 키워드 사용

Instance 멤버 접근자 -self인스턴스객체 메소드의 첫 인자는 Self 를 사용하여 각 인스턴스별로 메소드를 호출하여 사용할 수 있도록 정의

Method- Instance클래스 객체에서 생성되는 모든 인스턴스 객체에서 활용되므로 클래스 이름공간에서 관리메소드 첫 파라미터에 self 라는 명칭을 정의

Method- 클래스 decorator클래스 객체에서 처리되는 메소드를 정의한다 . 클래스 메소드는 첫번째 파라미터에 cls 를 전달한다 .

장식자 @classmethod : 클래스 함수 위에 표시 -Python 2.x함수 classmethod() : 별도 문장으로 표시 – Python 3.x

인스턴스 객체도 호출이 가능

Method- 정적 decorator클래스 객체로 생성된 모든 인스턴스 객체가 공유하여 사용할 수 있다 .

장식자 @staticmethod : 정적함수 위에 표시 – Python 2.x함수 staticmethod() 는 별도의 문장으로 표시 – Python 3.x

정적메소드는 파라미터에 별도의 self, cls, 등 객체에 대한 참조값을 전달하지 않아도 됨 인스턴스 객체에서도 호출이 가능

Accessing Members클래스를 정의한 후에 인스턴스를 생성하고 메소드 호출 및 클래스 변수를 직접 호출하여 출력

class Employee: 'Common base class for all employees‘ empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.emp-Count def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary

Class 정의# 인스턴스 객체 생성 : 생성자 호출emp1 = Employee("Zara", 2000) # 인스턴스 메소드 호출emp1.displayEmployee()

# 인스턴스 객체 생성 : 생성자 호출emp2 = Employee("Manni", 5000) # 인스턴스 메소드 호출emp2.displayEmployee()

# 클래스 변수 호출 및 출력print "Total Employee %d" % Employee.empCount

Instance 생성 및 호출

Method Bound/unbound(1)클래스이름과 인스턴스이름으로 메소드를 호출하면 bounding 처리 됨메소드 선언시 인자로 self, cls 를 정의되어 있음

>>> class Preson() :... def printP(self) :... print(' instance method ')... def printC(cls) :... print(' class method')… >>> p = Preson() # 인스턴스 생성>>> p.printP() # 인스턴스 메소드 bounding instance method >>> Preson.printP(p) # 인스턴스 메소드 unbounding instance method >>>

인스턴스를 생성하고 인스턴스 메소드 호출시는 bounding 처리 클래스로 인스턴스 메소드 호출시는 인자로 인스턴스 객체를 전달해서 unbounding

Method Bound/unbound(2)메소드 선언시 인자로 self, cls 를 정의되어 있는 것에 따라 매칭시켜야 됨

Transformation Called from an Object Called from a Class

Instance method f(*args) f(obj,*args)

Static method f(*args) f(*args)

Class method f(cls, *args) f(*args)

Class Inheritance

Inheritance상속은 상위 클래스를 하나 또는 여러 개를 사용하는 방법 class 상위 클래스명 : pass class 클래스명 ( 상위 클래스명 ) : pass

상속 정의시 파라미터로 상위 클래스명을 여러 개 작성시 멀티 상속이 가능함 class 클래스명 ( 상위 클래스명 , 상위 클래스명 ) : pass

Class 구조 클래스는 슈퍼클래스를 상속

Super ClassClass

상속

class A(object): def __init__(self) : self.instanceS = " static instance member" def whoami(self): return self.__class__.__name__

클래스 구조 예시 (1)>>> one = 1>>> type(one)<type 'int'>>>> type(type(one))<type 'type'>>>> type(one).__bases__(<type 'object'>,)>>> >>> object <type 'object'>>>> type <type 'type'> >>> type(object) <type 'type'>>>> object.__class__ <type 'type'>>>> object.__bases__ ()>>> type.__class__ <type 'type'>>>> type.__bases__ (<type 'object'>,)>>> isinstance(object, object) True>>> isinstance(type, object) True>>> isinstance(object, type)True

objecttype

int float str

클래스 구조

클래스 구조 예시 (2)

>>> list <type 'list'>>>> list.__class__ <type 'type'>>>> list.__bases__ (<type 'object'>,)>>> tuple.__class__, tuple.__bases__ (<type 'type'>, (<type 'object'>,))>>> dict.__class__, dict.__bases__ (<type 'type'>, (<type 'object'>,))>>>>>> mylist = [1,2,3] >>> mylist.__class__ <type 'list'>

데이터 타입은 상속을 받을 때 타입 객체를 바로 받지만 base 는 object 클래스를 처리 객체 생성 예시

메타클래스 클래스 인스턴스

type object

list mylist

Inheritance- scope

상속된 클래스도 검색하는 순서가 파라미터를 정리한 순서대로 변수나 메소드를 검색하여 처리됨상속된 클래스에 동일한 이름이 변수나 메소드가 존재시 첫번째 검색된 것으로 처리함class 클래스명 ( 상위 클래스명 , 상위 클래스명 ) : pass

Inheritance - 예시

class Parent: # define parent class parentAttr = 100 def __init__(self): print "Calling parent constructor“ def parentMethod(self): print 'Calling parent method' def setAttr(self, attr): Parent.parentAttr = attr def getAttr(self): print "Parent attribute :", Parent.parentAttr

class Child(Parent): # define child class def __init__(self): print "Calling child constructor" def childMethod(self): print 'Calling child method'

c = Child() # instance of childc.childMethod() # child calls its method c.-parentMethod() # calls parent's method c.se-tAttr(200) # again call parent's method c.getAttr() # again call parent's method

# 결과값Calling child constructor Calling child method Calling parent method Parent attribute : 200

Class 정의 인스턴스 생성 및 호출

Mixin기존 상속구조에 대한 변경을 최소화하기 위해 메소드기반의 클래스 생성하여 상속받아 처리하는 방법

class Mixin : def add(self,x,y) : return self.x + self.y def sub(self,x,y) : if isinstance(self, String) : return " String no support" else : return self.x - self.y

class Number(Mixin) : def __init__(self, x,y) : self.x = x self.y = y

class String(Mixin) : def __init__(self, x,y) : self.x = x self.y = y

n1 = Number(5,6)n1.add(n1.x,n1.y)n1.sub(n1.x,n1.y)

s1 = String("hello ", "world")print s1.add(s1.x, s1.y)print s1.sub(s1.x, s1.y)

인스턴스 생성 및 호출

상속구조 확인하기

MRO 처리Method resolution order 는 상속에 대한 처리 순서를 명확히 표시

class test1 : print " test1 “

print test1.mro()

# 실행 결과AttributeError: class test1 has no attribute 'mro'

class test1(object) : print " test1 "

print test1.mro()

# 실행 결과 test1 [<class '__main__.test1'>, <type 'object'>]'

상속 : __mro__, mro()상속인 경우 클래스 객체들이 우선순서를 확인하는 속성과 메소드

class Base1(object): def amethod(self): print "Base1"

class Base2(Base1): pass

class Base3(object): def amethod(self): print "Base3"

class test(Base2,Base3) : A = 'aaaa‘

instance = test() instance.amethod() print test.__mro__ print test.mro()

# 실행 결과Base1(<class '__main__.test'>, <class '__main__.Base2'>, <class '__main__.Base1'>, <class '__main__.Base3'>, <type 'object'>)[<class '__main__.test'>, <class '__main__.Base2'>, <class '__main__.Base1'>, <class '__main__.Base3'>, <type 'object'>]

Super() 함수 (2.x)Super( 클래스 , 서브클래스 또는 인스턴스 )Class 변수를 호출하였지만 mro() 순성 따라 A.bar 가 호출되어 처리됨

class A(object) : bar = 100 def foo(self) : pass class B(object) : bar = 0 class C(A,B) : xyz = 'abc' print " super function ", super(C,C())

print C.mro()print super(C,C()).__self__print super(C,C()).barprint super(B,B()).__self__print super(B,B()).__self__.bar

# 실행 결과super function <super: <class 'C'>, <C object>>[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>]<__main__.C object at 0x0F01BA10>100 A.bar 의 값<__main__.B object at 0x0F01B6B0>0 B.bar 의 값

Super() 함수의 binding(2.x)Super( 클래스 , 인스턴스 ). 메소드 () 은 클래스 .메소드 ( 인스턴스 ) 로 연결되는 구조이므로 파라미터가 빠지면 binding 이 되지 않는다 .

print super(C) # 실행 결과<super: <class 'C'>, NULL>

print super(C).fooFoo 는 인스턴스 함수이라서 binding 에러# 실행 결과AttributeError: 'super' object has no attribute 'foo'

Super() 을 이용한 접근 (2.x)Super( 클래스 , 인스턴스 ) 객체에 __get__ 메소드가 구현되어 있어 재상속 후에 처리시 에러없이 상위 클래스를 접근 가능

class A(object) : bar = 100 def foo(self) : pass class B(object) : bar = 0 class C(A,B) : xyz = 'abc‘

class D(C) : sup = super(C) print D().supprint D().sup.fooprint super(C,D()).fooprint D().sup.bar

# 실행 결과<super: <class 'C'>, <D object>><bound method D.foo of <__main__.D object at 0x0F01BF90>><bound method D.foo of <__main__.D object at 0x0F01BF90>>100

D().sup 일때 상위 클래스 C 와 하위 인스턴스 D() 가 있어 매핑되어 처리 가능D().sup.foo == Super(C,D()).foo 로 바인딩한 것과 같다

Super(C).__get__(D(), ‘foo’) 처럼 인식

Super() 함수 (3.x)파이썬 3.x 버전부터 super() 함수이 파라미터가 없어도 자동으로 스택프레임에서 검색하여 처리함

Overriding

Overriding메소드를 이름으로 검색하므로 하위 클래스에 동일한 메소드가 존재하면 인스턴스 호출시 하위 클래스 메소드 부터 호출하므로 Overriding 처리 class 상위 클래스명 : def method(self) : pass class 클래스명 ( 상위 클래스명 ) : def method(self) : pass

Overriding 구조 동일한 메소드를 instance/Class/Super Class 에 다 정의할 경우 실행시 instance 부터 호출이 되는 구조

Super ClassClassinstance

상속인스턴스화

클래스 정의 시 메소드클래스 정의 시 슈퍼 클래스메소드 재정의Runtime 시 클래스 및 슈퍼클래스 메소드 정의

Overriding 발생 Overriding 발생

연산자 Overriding 예시Super ClassClassinstance

상속인스턴스화

Overriding 발생

class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other): return Vector(self.a + other.a, self.b + other.b)

# __init__ 생성자 메소드 overridingv1 = Vector(2,10) v2 = Vector(5,-2)

# __add__ 메소드 overriding print v1 + v2

# __str__ 메소드 overriding print v1

__getattr__/__setattr__ 메소드인스턴스에서 상속된 부모 클래스의 속성을 조회 및 갱신이 가능

>>> dir(dict)['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', ….']>>>

dict 클래스에서 보관하는 속성을 조회

>>> # dict 인스턴스 생성하고 dict 내 >>> # 매소드 호출>>> d = {'a': 1}>>> d.__getattribute__('__class__')<type 'dict'>>>>

dict 클래스의 인스턴스로 클래스 내부의 속성을 조회

./[] 연사자 overriding다른 클래스를 만들어서 연산자를 다양하게 사용하기 위해 오버라이딩 처리

class Test1(dict) : def __getattr__(self,name) : return self[name] def __setattr__(self,name, value) : self[name] = value

t1 = Test1()t1.a= 10t1['btest'] = 100

print t1.aprint t1['btest']print t1.__dict__print t1

# 결과값10100{}{'a': 10, 'btest': 100}

Super Class

Classinstance

상속인스턴스화

Overriding 발생

./[] 연사자 overriding - 설명부모 클래스의 메소드를 재정의해서 현재 클래스의 메소드가 호출되도록 처리

class Test1(dict) :

def __getattr__(self,name) : return self[name]

def __setattr__(self,name, value) : self[name] = value

1. dict 클래스의 __getattr__, __setattr__ 메소드에 대한 오버라이딩 처리

2. dict 타입이라서 실제 self 내부 데이터 타입에 저장됨

인스턴스 생성 기초

Instance 구조 클래스는 슈퍼클래스를 상속하고 인스턴스를 만들어서 실제 기능들을 동작시킨다 .

Super ClassClassinstance

상속인스턴스화

Instance 생성 방식 클래스명에 파라미터에 인스턴스 변수값을 정의해서 인스턴스를 생성함 인스턴스 생성시 생성자가 호출되어 처리됨

변수명 = 클래스명 ( 인스턴스 변수값 , 인스턴스 변수값 )def __init__(self, 인스턴스 변수값 , 인스턴스 변수값 ) : self. 인스턴스 변수 = 인스턴스변수값 매칭호출시 매칭됨

Instance 생성 예시 Class 키워드로 클래스 정의 상속은 class 키워드 다음 () 내에 상속할 클래스 정의 인스턴스 생성은 클래스명에 () 연산자 사용

Super ClassClassinstance

상속인스턴스화

class A(object): def whoami(self): return self.__class__.__name__

a = A()

Instance Scope 객체들간의 관계 ( 상속 및 instance 생성 등 ) 에 따라 객체 멤버들에 대한 접근을 처리검색 순서 : 인스턴스 > 클래스 > 상속클래스 >builtin Class

상속이 많아지면 다양한 상위 멤버들을 접근하여 처리할 수 있다 .

Predefined Instance Attributes

Attribute Type Read/Write Description__dict__ dictionary R/W The instance name space__class__ class R/W The class of this instance

클래스와 인스턴스 접근

Members( 변수 ) AccessClass/Instance 객체에 생성된 변수에 대한 구조 및 접근 방법

>>> # class 정의 >>> class C(object): ... classattr = "attr on class“... >>> # 객체 생성 후 멤버 접근>>> cobj = C() >>> cobj.instattr = "attr on instance" >>> >>> cobj.instattr 'attr on instance' >>> cobj.classattr 'attr on class‘

멤버접근연사자 (.) 를 이용하여 접근

C

classattr

cobj:C

instattr

cobj = C()

Members( 변수 ) Access - 세부Class/Instance 객체는 내장 __dict__ 멤버 ( 변수 )에 내부 정의 멤버들을 관리함

>>> # 내장 __dict__ 를 이용한 멤버 접근 >>> # Class 멤버>>> C.__dict__['classattr'] 'attr on class' >>> # Instance 멤버>>> cobj.__dict__['instattr'] 'attr on instance' >>>>>> C.__dict__ {'classattr': 'attr on class', '__module__': '__main__', '__doc__': None}>>>>>>>>> cobj.__dict__ {'instattr': 'attr on instance'} >>>

C

cobj:C

cobj = C()

__dict__:dict

classattr

__dict__:dict

classattr

내장 객체

내장 객체

Members( 메소드 ) AccessClass 정의시 인스턴스 메소드 정의를 하면 Class 영역에 설정

>>> #Class 생성>>> class C(object): ... classattr = "attr on class“... def f(self):... return "function f" ... >>> # 객체 생성>>> cobj = C() >>> # 변수 비교>>> cobj.classattr is C.__dict__['classattr'] True

변수 비교

C

classattr

f

cobj:C

instattr

cobj = C()

Members( 메소드 ) Access- 세부인스턴스에서 인스턴스메소드 호출하면 실제 인스턴스 메소드 실행환경은 인스턴스에 생성되어 처리

>>> # 인스턴스에서 실행될 때 바운드 영역이 다름>>> # is 연산자는 동일 객체 체계>>> cobj.f is C.__dict__['f'] False >>>>>> C.__dict__ {'classattr': 'attr on class', '__mod-ule__': '__main__', '__doc__': None, 'f': <function f at 0x008F6B70>} >>> 인스턴스에 수행되는 메소드 주소가 다름>>> cobj.f <bound method C.f of <__main__.C instance at 0x008F9850>> >>> # 인스턴스 메소드는 별도의 영역에 만들어짐>>> # 인스턴스 내에 생성된 메소드를 검색>>> C.__dict__['f'].__get__(cobj, C) <bound method C.f of <__main__.C instance at 0x008F9850>>

C

cobj:C

cobj = C()

__dict__:dict

classattr

f

__dict__:dict

classattr

f

내장 객체

내장 객체

Controlling Attribute AccessInstance 의 Attribute 에 대한 접근을 할 수 있는 내부 함수__getattr__(self, name)__setattr__(self, name, value)__delattr__(self, name)__getattribute__(self, name)

Controlling Attribute Access인스턴스의 속성에 대한 접근을 내부 함수로 구현하여 접근

class A() : __slots__ =['person_id', 'name'] def __init__(self, person_id, name) : self.person_id = person_id self.name = name def __getattr__(self, name) : return self.__dict__[name] def __setattr__(self, name, value): if name in A.__slots__ : self.__dict__[name] = value else: raise Exception(" no match attribute") def __delattr__(self, name) : del self.__dict__[name]

def __getattribute__(self, name): return self.__dict__[name]

a = A(1,'dahl')

print a.__getattr__('name')print a.__getattr__('person_id')

print a.__dict__

print a.__setattr__('name','moon')print a.__setattr__('person_id',2)

print a.__getattr__('name')print a.__getattr__('person_id')

print a.__delattr__('name')print a.__dict__

a.name = 'gahl'

#a.s = 1

print a.__dict__

Association

Association객체간에 관계를 구성하여 처리객체내부에 관계 객체를 생성하여 해당 객체의 기능을 처리

AB

Association:Object Chain

#class 정의하고 인스턴스에서 타 객체를 호출class A: def __init__(self ): print 'a' self.b = B()

#object chain 을 하는 class 생성class B: def __init__(self ): print 'b' def bbb(self): print "B instance method " a = A()

print a.b.bbb()

객체들간의 연결고리 (Association, Composite 관계 ) 가 있을 경우 메소드 결과값을 객체로 받아 연속적으로 실행하도록 처리

객체 . 내부객체 .메소드 처리# 결과값abB instance method None

Dependency객체간에 관계를 구성하여 처리객체내부에 관계 객체로써 메소드 등에서 일회성으로 해당 객체를 생성하여 기능을 처리

AB

Dependency: Method Chain

class C: def __init__(self ): print 'a' self.b = B() def ccc(self, b) : return b.bbb()

#object chain 을 하는 class 생성class B: def __init__(self ): print 'b' def bbb(self): print "B instance method " a = C()

print a.b.bbb()

print a.ccc(B())

객체의 관계가 일회성 적으로 처리가 되는 관계

객체 . 메소드 (인스턴스객체 ) 처리# 결과값abB instance method NonebB instance method None

Self Method Chain

class Person: def name(self, value): self.name = value return self def age(self, value): self.age = value return self def introduce(self): print "Hello, my name is", self.name, "and I am", self.age, "years old."

person = Person() # 객체의 메소드를 연속적으로 호출하여 처리person.name("Peter").age(21).introduce()

객체 내의 메소드의 결과를 자기자신으로 리턴하여 메소드를 연속해 호출하여 처리

타 객체 Method Chain

class A: def __init__(self ): print 'a' self.b = B() class B: def __init__(self ): self.c = C() print 'b' def bbb(self): print "B instance method " return self.c class C: def __init__(self ): print 'c' def ccc(self): print "C instance method "

클래스 정의시 내부에서 인스턴스를 가진 경우 chain 처리를 위해 return 으로 해당 객체를 전달

# 결과값acbB instance method C instance method None

a = A()

print a.b.bbb().ccc()

Class 확인 방법

issubclass/isinstance 함수

>>> issubclass(list,object)True>>> list.__bases__(<type 'object'>,)>>> issubclass(list, type)False>>>

issubclass() : __bases__ 기준으로 상속관계 isinstance() : __ class__ 기준으로 인스턴스 객체 관계

>>> isinstance(list, type)True>>> list.__class__<type 'type'>>>> >>> isinstance(list, object)True>>>

issubclass 처리 isinstance 처리

Class & instance namespaceClass Object 는 클래스 메소드 , 정적메소드 , 클래스 내부 변수 등을 관리한다 .파이썬은 변수나 메소드 검색 기준이 인스턴스 > 클래스 > Built-in Class 순으로 매칭시키므로 . 연산자를 이용하여 인스턴스도 메소드 호출이 가능하다 .

>>> class Simple : ... pass... >>> Simple<class __main__.Simple at 0x0212B228>>>> Simple.__name__'Simple‘>>> Simple.__dict__{'__module__': '__main__', '__doc__': None}

>>> s = Simple()>>> s.__dict__{}>>> s.name = "Simple instance">>> s.__dict__{'name': 'Simple instance'}

Instance 생성 및 인스턴스 멤버 추가Class 정의

Descriptor Protocol

Descriptor설명은 그 속성 접근 기술자 프로토콜의 방법에 의해 무시되었다 " 바인딩 행동 " 을 가진 객체 속성 중 하나입니다 __get__(self, instance, owner),__set__(self,instance, value),__delete__(self, instance).

Descriptor 종류Method descriptor 와 Data descripter 로 구분

Method descriptor 는 __get__(self, instance, owner) 구현

Data descriptor 는 __get__(self, instance, owner) __set__(self,instance, value),

__delete__(self, instance) 구현

Descriptor : int.__add__Method descriptor 로 구현되어 __get__(self, instance, owner) 가지고 있다

P =1# 직접 호출p.__add__(3) # 결과값 4# 인스턴스에서 호출type(p).__add__.__get__(p,int)(3) # 결과값 4#class 에서 호출int.__add__.__get__(1,int)(3)

Descriptor : binding behavior

binding 하는 방법Direct Call

Instance Bind-ing

Class Binding

Super Binding

class D(object) : def __init__(self, x) : self.x = x def __get__(self,instance=None,cls=None) : return self.x class D1(D) : def __init__(self, x) : D.__init__(self,x)

d = D(1)print " d"print d.__dict__print d.xprint " direct call",d.__get__()print " Class binding call ",D.__get__(d,d)print "instance binding",type(d).__get__(d,d)d1 = D1(2)print " d1"print d1.__dict__print d1.xprint " direct call",d1.__get__()print " Class binding call ", D1.__get__(d1,d1)print "instance binding",type(d1).__get__(d1,d1)print D1.mro()print "super binding",super(D1,d1).__get__(d1,d1)

Creating data descriptorData Descriptor 클래스를 생성해서 처리하는 방법

class Descriptor(object): def __init__(self): self._name = '' def __get__(self, instance, owner): print "Getting: %s" % self._name return self._name def __set__(self, instance, name): print "Setting: %s" % name self._name = name.title() def __delete__(self, instance): print "Deleting: %s" %self._name del self._name

class Person(object): name = Descriptor()

>>> user = Person() >>> user.name = 'john smith' Setting: john smith >>> user.name Getting: John Smith 'John Smith‘>>> del user.name Deleting: John Smith

Creating Property- 객체 직접 정의 (1)

인스턴스 객체의 변수 접근을 메소드로 제약하기 위해서는 Property 객체로 인스턴스 객체의 변수를 Wrapping 해야 함property(fget=None, fset=None, fdel=None, doc=None)

class P:

def __init__(self,x): self.x = x def getx(self) : return self.x def setx(self, x) : self.x = x def delx(self) : del self.x

x = property(getx,setx,delx," property test ")

Getter, setter, deleter 메소드를 정의

인스턴스 객체의 변수명과 동일하게 Property 객체 생성 ( 내부에 _x 생김 )

Creating Property– 객체 직접 정의 (2)

실제 인스턴스 객체의 변수에 접근하면 Property 객체의 메소드를 호출하여 처리되고 인스턴스 객체의 변수값이 변경됨

p1 = P(1001)print id(p1.x)print P.__dict__['x']print id(p1.__dict__['x'])print p1.xp1.x = -12print p1.xprint p1.__dict__

# 처리결과값44625868<property object at 0x02C1D4E0>446258681001-12{'x': -12}

Creating Property decorator(1)

인스턴스 객체의 변수 접근을 메소드로 제약하기 위해서는 Property 객체로 인스턴스 객체의 변수를 Wrapping 해야 함property(fget=None, fset=None, fdel=None, doc=None)

class P:

def __init__(self,x): self.x = x @property def x(self): return self.__x @x.setter def x(self, x): self.__x = x @x.deleter def x(self): del self.x

Getter, setter, deleter 메소드를 정의인스턴스 객체의 변수명과 동일하게 Property 객체 생성 ( 내부에 _x 생김 )

Creating Property decorator(2)

Property 객체 생성하여 처리하는 방식과 동일

p1 = P(1001)print id(p1.x)print P.__dict__['x']print id(p1.__dict__['x'])print p1.xp1.x = -12print p1.xprint p1.__dict__

# 처리결과값44625916<property object at 0x02C1D3C0>446259161001-12{'x': -12}

내장함수를 통한 객체접근

Built-in 내장함수내장함수를 이용하여 객체의 속성에 대한 접근getattr(object, name[, default])setattr(object, name, value)delattr(object, name)hasattr(object, name)callable(object)

Built-in 내장함수 : 예시 1객체의 속성을 접근하고변경

class A(): def __init__(self, name,age) : self.name = name self.age = age a = A('dahl',50)

if hasattr(a,"name") : print getattr(a,"name") setattr(a,"name","Moon") print getattr(a,"name")else : pass

if hasattr(a,"age") : print getattr(a,"age")else : pass

# 처리결과값dahlMoon50

Built-in 내장함수 : 예시 2메소드 및 함수여부 확인 후 실행

class A(): def __init__(self, name,age) : self.name = name self.age = age def in_set(self,name,default) : self.__dict__[name] = default print self.__dict__[name]

a = A('dahl',50)

def add(x,y) : return x+y if callable(add) : add(5,6)else : pass

if callable(a.in_set) : a.in_set('age',20)else: pass

# 처리결과값dahlMoon5020

Information Hiding

Information hiding - 변수__ 명칭 : Private ( 객체 내부에서만 사용 ) 외부에서 호출시 mangling 되는 구조로 요청시 접근 가능 인스턴스 ._ 클래스명 __ 명칭_ 명칭 : protected ( 클래스 및 하위 클래스에서만 사용 )

Information hiding - 변수예시 명칭 : public (파이썬은 공개되는 게 기본 ) __명칭 : Private (객체 내부에서만 사용 ) mangling 되는 구조로 명칭이 변경됨 호출시는 인스턴스 ._클래스명__명칭 _명칭 : protected (클래스 및 하위 클래스에서만 사용권고 ) “don’t touch this, unless you’re a subclass”

>>>class foo: … def __secret(self): pass …

foo.__secret => AttributeError: __secret

>>>foo.__dict__{'_foo__secret': <function __secret at fc328>, '__module__': '__main__', '__doc__': None}

Private 메소드 정의 및 호출 Class Namespace 명칭

Information hiding – 변수 - 특별 __ 명칭 __ : 내장된 변수나 함수 등을 정의

Information hiding –Descriptor(Property)

파이썬은 Property 객체를 이용하여 객체내의 변수들의 접근을 메소드로 제어한다 .Descriptor 객체 , Property 객체나 @property decorator 를 이용인스턴스 객체의 변수 명과 동일한 property 객체가 생성되어야 함

Class P Instance p1{‘x’: }

Descriptor/Property

x

생성

인스턴스생성

p1.x 접근

Property 내 메소드 호출하여 처리

Abstract Base Class

Abstract Class추상화 클래스란 직접 인스턴스를 만들지 못하고 상속을 받아 메소드 오버라이딩해서 사용하는 방식

Concrete Class instanceObj = ConcreteClass()

인스턴스 객체 생성

Abstract Class instanceObj = ConcreteClass()

인스턴스 객체 생성XAbstract

ClassConcrete

Class instance

ConcreteClass(Abstract Class)

상속

Obj = ConcreteClass()

인스턴스 객체 생성

Abstract Class 정의 방법추상화 클래스는 exception 및 abc 모듈 2 가지 처리 방법으로 만들 수 있다 .

exception 방식

abc 모듈 방식

모든 메소드를 subclass 에서 정의할 필요가 없다오류처리 : NotImplementedError

모든 메소드를 subclass 에서 정의해야 한다 . 오류처리 : TypeError

Abstract Class : exception 방식클래스 정의 후에 메소드 실행 부분을 exception 처리하고 상속받은 클래스에서 메소드 오버라이딩 처리

class Base: def foo(self): raise NotImplementedError("foo")

def bar(self): raise NotImplementedError("bar")

class Concrete(Base): def foo(self): return "foo() called"

상속 및 메소드 오버라이딩

추상클래스의 모든 메소드를 구현할 필요없음

Abstract Class : ABC 모듈ABC 모듈을 이용하여 정의해서 추상클래스 정의 후 상속을 받아 메소드 오버라이딩 처리

from abc import ABCMeta, abstractmethodclass Base(): __metaclass__=ABCMeta @abstractmethod def foo(self): pass @abstractmethod def bar(self): pass

class Concrete(Base): def foo(self): pass def bar(self): pass

상속 및 메소드 오버라이딩

추상클래스의 모든 메소드를 구현되어야 함

Abstract Class :property 정의Abstract Class 에서 decorator(@property) 를 사용하여 처리하기

class 구현클래스명 () : 변수명@propertydef get 메소드명 :@ 변수명 .setterdef set 메소드명 :@ 변수명 .deleterdef del 메소드명 :

import abcclass 추상클래스명 () : __metaclass__ = abc.ABCMeta

@abc.abstractpropertydef get 메소드명 :@ 변수명 .setterdef set 메소드명 :@ 변수명 .deleterdef del 메소드명 :

매칭

Abstract Class :property 구현Abstract Class 에서 decorator(@property) 를 사용하여 처리하기

import abc

class Base(object): __metaclass__ = abc.ABCMeta @abc.abstractproperty def value(self): return 'Should never see this' @value.setter def value(self, newvalue): return

class Implementation(Base): # private 처리 _value = 'Default value' @property def value(self): return self._value

@value.setter def value(self, newvalue): self._value = newvalue

abc 모듈을 이용해서 추상클래스 정의 추상클래스 상속받은 하위클래스 정의

Duck typing

Duck typeing 정의 방법다양한 클래스가 동일한 메소드를 처리할 수 있도록 인터페이스를 갖도록 만드는 법

함수

클래스

Duck typing 에 필요한 함수 정의 후 인스턴스들의 메소드 호출 처리

Duck typing 에 필요한 클래스 정의 후 인스턴스들의 메소드 호출 처리

Duck typeing : 함수 구현 (1)Duck typeing 함수 정의 후 클래스에 동일한 메소드 정의

def in_the_forest(duck): duck.quack() duck.feathers()

class Duck: def quack(self): print("Quaaaaaack!") def feathers(self): print("The duck has white and gray feathers.")

class Person: def quack(self): print("The person imitates a duck.") def feathers(self): print("The person takes a feather from the ground and shows it.") def name(self): print("John Smith")

함수 정의 클래스 정의

Duck typeing : 함수 구현 (2)Duck typeing 처리

def game(): donald = Duck() john = Person() in_the_forest(donald) in_the_forest(john)

print "function duck typeing "game()

# 실행 결과function duck typeing Quaaaaaack!The duck has white and gray feathers.The person imitates a duck.The person takes a feather from the ground and shows it.

Duck typeing : 클래스 구현 (1)

Duck typeing 클래스 정의 후 클래스에 동일한 메소드 정의

class InTheForest() : @staticmethod def quack(self) : self.quack() @staticmethod def feathers(self) : self.feathers() @classmethod def all(cls,self) : cls.quack(self) cls.feathers(self)

class Duck: def quack(self): print("Quaaaaaack!") def feathers(self): print("The duck has white and gray feathers.")

class Person: def quack(self): print("The person imitates a duck.") def feathers(self): print("The person takes a feather from the ground and shows it.") def name(self): print("John Smith")

함수 정의 클래스 정의

Duck typeing : 클래스 구현 (2)

Duck typeing 처리

def gameC(): donald = Duck() john = Person() InTheForest.all(donald) InTheForest.all(john)

print " class duck typeing "gameC()

# 실행 결과 class duck typeing Quaaaaaack!The duck has white and gray feathers.The person imitates a duck.The person takes a feather from the ground and shows it.

INSPECTMODULE

Insepect Module

Inspect modulemodule 에 대한 다양한 점검을 위한 함수를 제공

Function Description

inspect.getmoduleinfo(path)

모듈에 대한 정보를 가져오기ModuleInfo(name='in_test', suffix='.py', mode='U', module_type=1)

inspect.getmodulename(path) 모듈 네임만 문자열로 가져옴 in_test

inspect.ismodule(object) import 한 모듈을 확인 여부

Inspect 객체객체에 대한 다양한 점검을 위한 함수를 제공

Function Descriptioninspect.getmembers(object[, predi-

cate] 객체의 멤버를 튜플 ( 키와 값 ) 로 표시inspect.isclass(object) Object 에 클래스가 들어가면 True 이고 나머지는 False

inspect.ismethod(object) Object 가 메소드 여부 inspect.isabstract(object) Object 가 추상클래스 여부

inspect.ismethoddescriptor(object) int.__add__ 처럼 내장 메소드일 경우 descriptor protocol 존재해서 true 처리

inspect.isdatadescriptor(object) __get__, __set__, __delete__ 메소드를 가진 인스턴스일 경우 True

Inspect 함수함수에 대한 다양한 점검을 위한 함수를 제공

Function Descriptioninspect.isfunction(object) Object 가 함수 여부

inspect.isgeneratorfunction(object) Object 가 제너레이터 함수 여부inspect.isgenerator(object) Object 가 제너레이터 여부

개념적 접근

객체지향이란 ?

왜 객체지향을 하는가 ? 소프트웨어이 관리 기준은 모듈이지만 실행환경에서 모듈은 객체처럼 움직이면서 관리

실행환경과 구현환경이 동일하게 관리하는 것이 객체지향을 도입한 중요한 이유

인간의 사고는 추상화적인 분류를 기준 추상화를 위한 단위를 객체로 보고 소프트웨어를 만드는 것이 인간의

사고 개발자들이 추상적인 생각을 키우면서 소프트웨어를 개발하기 딱 맞는

환경이 객체지향이고 이를 위해 소프트웨어도 그 개념을 받아들여 발전 객체 즉 사물을 보고 잘 분류하는 사고가 필요

객체지향 사물의 분류 사물 (Things)은 곧 객체이다 . 사물에는 형태를 가진 것과 개념만 존재하는 것으로 분류할 수 있다 . 소프트웨어 분석 설계 구현을 한다는 것은 실세계의 사물을 가상세계의 사물로 전환하는

것이다 . 객체 모델링 , 데이터 모델링도 다 사물들을 관리하는 기준에 맞춰 분류하는 것이다 . 타입 , 클래스는 객체 즉 사물을 분류했을 때 정의하는 것에 지나지 않는다 . 사물을 어떻게 분류할 것인가?

책을 예시로 보면 책은 객체이다 . 책에 대한 정보만 관리하는 것은 개념 객체이고 책의 실물을 관리하는 사물을 관리하는 객체가 구별되어 관리되어야 한다 .

책이라는 객체가 책 정보에 대한 분류 기준으로 도서문헌상의 분류 규칙을 따르므로 다양한 분류체계를 관리하는 객체도 발생할 수 있다 .

사물은 단순이 존재한다고 하나의 객체만은 아니다 . 보는 관점 , 각 비즈니스 도메인별로 차이가 발생하므로 사물의 분류 기준을 비즈니스에 맞춰

모델링이 되어야 한다 .

계약중심의 설계 실세계 객체들이 대화 즉 의사소통을 통행 움직인다 . 소프트웨어도 실제 객체들이 혼재되어 실행되지만 객체간의 영향을 항상

조화를 이룰 수 있다면 깨지지 않고 많은 것을 처리할 수 있다 . 이를 위해 객체간의 메시지 즉 소통을 위해 각 객체들은 자신들의 할 수

있는 일과 상대방에게 요구하는 일들을 약속해서 명확하게 처리되어야 한다 .

design by contract 계약중심의 설계는 실제 객체들이 실행시 자신들의 권리와 의무를 명확히 하고 이를 어길 경우에도 정확한 에러처리를 통해 소프트웨어가 잘 작동할 수 있는 설계를 하자는 것이다 .

소프트웨어는 가상의 물질 즉 객체들에 의해 작동되지만 실세계의 객체들이 움직임처럼 명확히 살아있는 것처럼 생각해서 설계가 되어야 스파게티 소스를 만들지 않을 수 있는 지름길이다 .

객체의 생명주기 관리 계약이란 쌍방이 매매를 했을 때 권리와 의무를 명확히 표시한 거래이다 . 계약이 발생하면 그 계약이 시작점과 종료점이 있다 . 계약도 생명주기를 갖는다 . 생명주기를 갖는 것은 하나의 객체로서 관리를 해야 한다는 것이다 .

온라인 쇼핑몰에서 책을 구매한다 . 책을 매매한 계약은 배송으로 끝나는 것이 아니라 반품 등이 발생할 수 있으므로 최소 14일

정도까지는 기다려야 한다 . 회사 정책으로 더 많은 기간을 반품기간으로 정할 경우는 매매계약이 생명주기는 더 길어진다 . 이처럼 생명주기가 발생하는 것은 개념 객체이므로 객체로 관리해야 하는 대상이다 .

매매계약이 발생했을 때 이 계약에 필요한 문서 등을 고객에게 출력해줘야 하는 경우는 생명주기가 더 길어진다 .

계약 문서 등도 별도의 객체이므로 계약과의 연관관계를 유지하도록 한다 . 객체는 항상 생명주기가 있고 보는 시각을 달리하면 생명주기 관리기준도 다양하게 발생한다 . 객체를 보는 관점을 다양하게 갖는 게 아주 중요하다 .

상속대신 연관관계로 표현 객체지향 설계 시 상속을 사용하지 않는 이유는

상속관계가 끊어지면 모델을 다시 만들어야하기 때문이다 .

상속은 인간들이 보기가 좋지만 상속 레벨이 3단계가 넘어가거나 다중상속일 경우 인간이 이해하는 범위가 넘어가서 실질적인 상속을 이해할 수가 없다 .

실제 생물들도 부모로부터 상속을 받지만 상속관계로 표현할 수 있는 게 너무 없어서 실제 상속을 사용할 수 있는 것을 없다 .

상속을 끊을 경우 어떤 대안은 별도의 클래스를 생성할 수 있는 팩토리 체계를

만들어서 상속대신 관계성을 가질 수 있는 설계로 반영해야 한다 .

실세계에 존재하는 객체들은 그렇게 상속을 가지지 못하거나 너무 복잡해서 우리가 인식할 수 없다 .

상속을 사용할 경우 시스템 재개발 등이 발생시 더 많은 비용이 들 수 있어 연관관계를 사용해서 다양한 클래스로 분리

상속만으로 추상화는 불가 객체지향 프로그램 언어는 상속을 가지고 재사용성을 높일 수 있다고

한다 . 실제 상속은 비즈니스 환경에서는 맞지 않는다 . 상속으로 재사용성을 높인다고는 하지만 재사용은 변경이 아니라

추가인데 상속에서 추가를 한다는 것은 자식을 추가하는 것인데 자식들만 추가한다고 그 자식들이 거의 유사한 것들이 되는 것인가 ?

상속을 하려면 자식들이 가진 아주 대표적인 것만 부모가 되어야 하는데 , 비즈니스 환경에서는 부모와 자식이 구분이 안되는 경우가 더 많다 .

객체들이 많다면 그 객체들이 통합이 가능한지를 먼저 확인하고 객체들을 별도로 추상화하여 각 객체들이 집단간의 연관관계를 고려하는 게 더 추상화가 높을 수 있다 .

왜 스파게티가 될까 ? 기술적 재사용성만 강조하면 다중 상속이 필요하고

이를 반영하려면 클래스가 세분화 된다 . 하나의 서비스를 처리하기 위해 사용되는

클래스들이 많아지면 상속 및 연관관계가 일관되게 유지되기 어렵다 .

스파게티를 해결하려면 특정 도메인으로 분리해서 실제 연관관계를 분리해야 한다

SOLID?

SOLID 단일 책임 원칙 (Single responsibility principle) 개방 -폐쇄 원칙 (Open/closed principle) 리스코프 치환 원칙 (Liskov substitution princi-

ple) 인터페이스 분리 원칙 (Interface segregation

principle) 의존관계 역전 원칙 (Dependency inversion

principle)

단일 책임 원칙 Single responsibility principle 한 클래스는 하나의 책임만 가져야 한다 .

단일 책임 원칙 : 예시 거래당사자 정보를 정보관리와 거래 당사자의

역할로 분할하여 책임 정의

Involved Party

Person Organization

Role

Customer Employee Owner …

개방 -폐쇄 원칙 Open/closed principle “소프트웨어 요소는 …… 확장에는 열려 있으나 변경에는 닫혀 있어야 한다 .”

요구사항의 변경이나 추가사항이 발생하더라도 , 기존 구성요소는 수정이 일어나지 말아야 하며 , 기존 구성요소를 쉽게 확장해서 재사용할 수 있어야 한다는 뜻입니다 .

필수적인 요구사항만 , 구성요소 ( 클래스 )안에 구현하고 , 나머지는 , 구현자체를 생략하라는 겁니다 .

개방 -폐쇄 원칙 : 예시 거래당사자의 역할은 기존 클래스를 변경하는 게

아니라 새로운 책임성을 가지는 클래스를 추가

Role

Customer Employee Owner …Applicant

리스코프 치환 원칙 Liskov substitution principle 서브타입은 언제나 자신이 기반타입 (base type) 으로

교체할 수 있어야 한다 . 서브타입 클래스의 메소드를 변경하지 않아야 기반 클래스의 사용자는

그 기반 클래스에서 유도된 클래스 ( 서브타입 ) 에 대해 아무것도 알 필요가 없어야 한다 .

상속은 코드 재사용을 위해서가 아니라 명확한 가족 관계가 있을때 사용해야 하며 ,  그 행위 (Behavior) 와 연관이 있습니다 . 부모와 파생된 객체들이 존재 할때 가능한 모두 동일한 메소드 이름과 갯수를 가지게 함으로써 언제든지 서브 타입이 기반타입으로 교체될 수 있어야 함을 말합니다 . 

리스코프 치환 오용 상속관계가 아닌 객체를 비슷한 일을 하는 것을

보고 코드 재사용 욕심에 가족 관계로 묶는 것 . 다중 상속이나 다단계 상속으로 계층 구조가 깊고 복잡하게 하는 것 .

파생 타입에 부모 , 형제들과는 전혀 동떨어진 능력을 부여 함으로써 돌연변이를 만들어 버리는 것 .

리스코프 치환 원칙 : 예시 서브타입에 특정 기능을 오버라이딩한 것이 없도록 처리하여

기반타입으로 교체해도 이상이 없도록 함class rectangle() : def __init__(self,height, width) : if height == width : self.height = height self.width = width else : if self.__class__.__name__ == 'square' : print " error " else : self.height = height self.width = width def area(self) : return self.height * self.width

class square(rectangle) : pass

r = rectangle(5,8)print r.__dict__print r.area()

try : s = square(5,6) print s.__dict__ print s.area()except : pass

{'width': 8, 'height': 5}40 error {}

인터페이스 분리 원칙 Interface segregation principle “특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스

하나보다 낫다 .” 클라이언트는 자신이 사용하지 않는 메소드에 의존 관계를 맺으면 안된다 . 

비대한 클래스 (Fat class)  거대하고 보기 흉하다는 사실 말고도 , 한 사용자가 이 비대한 클래스의 메소드를 다 사용하는 일이 매우 적다는 것도 문제입니다 . 즉 . 메소드를 몇십개 선언한 클래스에서 사용자는 단지 두세 개만 호출 할 지도 모르죠 . 불행하게도 이 사용자들은 호출하지도 않는 메소드에 생긴 변화에도 영향을 받습니다 .

인터페이스 분리 원칙 : 예시 인터페이스에 대한 통합은 필요하지 않은 기능도 호출이

되므로 실질적으로 필요한 기능만 호출할 수 있어야 함

Involved Party

Person Organization

인터페이스

Involved Party

Person Organiza-tion

인터페이스

인터페이스에 대한 분리

의존관계 역전 원칙 Dependency inversion principle “프로그래머는 “추상화에 의존해야지 , 구체화에 의존하면 안된다 .”

의존성 주입은 이 원칙을 따르는 방법 중 하나다 . 고차원의 모듈은 저차원의 모듈에 의존하면 안된다 . 이 두 모듈 모두 다른

추상화된 것에 의존한다 . 추상화 된 것은 구체적인 것에 의존하면 안 된다 . 구체적인 것이 추상화된

것에 의존해야 한다 .  자주 변경되는 구상 클래스 (Concreate class) 에 의존하지 마라 . 만약

어떤 클래스에서 상속받아야 한다면 , 기반 클래스를 추상 클래스로 만들어라 . 만약 어떤 클래스의 참조 (Reference) 를 가져야 한다면 , 참조 대상이 되는 클래스를 추상 클래스로 만들어라 . 만약 어떤 함수를 호출해야 한다면 , 호출 되는 함수를 추상 함수로 만들어야 합니다 .

의존관계 역전 원칙 : 예시 각 레이어별로 역할이 정해져 있으면 역참조를 할 수 없도록 구성해야 함 역참조가 발생할 수 있는 것은 BCS(Business common service) Layer 를 구성해서

역전이 발생하지 않도록 처리 레이어도 무한정 정리할 수 없으므로 타 시스템 연계 등을 EIS(Enterprise Interface Ser-

vice)Layer로 구분하여 의존관계 역전 원칙 준수

Application Service layer

Process Service layer

Domain Service layer

ORM Service layer

BCS

LAYER

EIS

LAYER

외부시스템

Class 란 ?

클래스 명명규칙 및 정의 클래스 명명규칙과 정의는 그 클래스가 무엇인지를 설명해야 하고 명확한 책임성을 반영되어야 함 클래스가 식별되면 책임성에 대해 정의하고 유사 개념 또는 중복성 여부를 판단할 명확한 근거를

정리해야 함 클래스의 중요성을 간결하게 정의되어야 함

Class name

Attribute

Operation

클래스 이름은 명확히 구별되어야 하며 , 클래스 정의를 위한 명확한 구별이 가능해야 함

왜 그 클래스가 업무에 중요한가를 나타낼 수 있는 명명을 지정하고 정의에서 세부적인 책임성을 설명해야 함

클래스 정의는 “왜 이것이 업무에 중요한가 ?” 라는 질문에 답을 해야 함 필요한 경우 , 클래스가 여러 기능 , 공정 , 조직 또는 시스템관점(view) 을 가로질러 사용 된다면 , 그것이 적용되는 관점 (view) 을 명료하게 표시한 각 뷰 ( 관점 ) 별로 정의사항을 추가하라

클래스 명명 및 정의시 작성되어야 할 사항

클래스 구성 클래스에 대한 기술은 이 클래스의 인스턴스들을 생성하는 template 역할을

한다 . 클래스는 데이터타입과 비슷하나 , 클래스는 데이터와 함께 기능도가지고 있다 .

Class name

Attribute

Operation

object object object …..

생성생성 생성

클래스의 성질 기업이 실제 처리하는 비즈니스 도메인의 범위 안에 있어야 함 기업이 그에 대한 정보를 보관코자 하는 어떤 것을 나타냄 클래스의 속성들의 응집성에 의해 결정된 단일개념을 나타냄 하나의 실제사물(객체 )이 아니라 동종 또는 유사 사물의 집합을 나타냄 집합의 본질을 희석시키지 않고 , 해당 클래스내의 객체를 구별할 수 있는 능력을 제공 함

B 단위 업무 영역A 단위 업무 영역

C 단위 업무 영역

실세계 업무 범위

클래스가 갖춰야 할 요건 클래스들은 실세계를 가능한 완벽하게 추상화 시켜야 한다 . 실세계를 제대로 추상화해 내지 못하면 좋은 시스템을 기대할 수 없다 . 정보는 기능이나 데이터가 아닌 클래스들을 중심으로 국지화되어야 한다 . 클래스들의 구현방법은 철저하게 외부로 부터 숨겨져야 하며 , 밖으로는 잘 정의된 인터페이스만이 나타나야 한다.

(구현적 의미에서 보면)

객체 영역A Class name

Attribute

Operation

B Class name

Attribute

Operation

추상화

Class/Object 식별 기준

카테고리화에 의한 분류 : 상품 새로운 클래스를 설정하고 기존 클래스와 연관 예정이나 비즈니스 규칙과 같은 보다

추상적인 개념을 다루거나 실물과 지식의 구별을 강조 유사한 개념은 하나의 개념으로 묶어 그룹화하여 하나의 범주로 통합하여야 함 개념의 공통성을 찾아 하나의 범주로 묶어야 함

일반대출 계좌주택대출 계좌지급보증 계좌

…..

여신 계좌Category 화

상품 소분류나 중분류별 관리되는 계좌정보에 대해 통합된 개념으 Category 화 필요 개념 사물에 대한 세부 원칙을 통합관리 기준으로 분리

보통예금 계좌저축예금 계좌정기적금 계좌

…..

예금 계좌Category 화 Category 화

계약

카테고리화에 의한 분류 : 서비스 금융상품을 제외한 다양한 서비스에 대한 처리에 대한 계약 처리 송금 , 지급결제 , 환전 등이 별도 거래

기타 판매기타 수납대여금고

…..

기타 서비스Category 화

금융상품을 제외한 다양한 서비스에 대한 계약에 따른 세부 분리

송금지급결제

환전…..

금전서비스Category 화 Category 화

계약

집합으로 규정할 수 있어야 함 동일한 부류나 범주의 집합으로 규정하여 클래스간의 책임성 중복이 발생하지 않아야 함 집합으로 정의할 수 있도록 명확한 분류 기준을 수립해야 함 집합에 속한 객체들이 중복되지 않도록 명확해야 함

계약고객과의 수신 , 여신 상품을 신규할 경우 계약조건 등 계약에 필요한 정보를 관리 =

집합 정의

공통성과 변이성을 구분 비즈니스 소프트웨어의 복잡성의 가장 중요한 원인은 ‘변형 (variation)’의 규모에서 온다 . 이러한 변형 경우를 분석함으로써 ‘공통점 (Commonality)’을 추출할 수 있다 . 클래스 복잡성을 해결하기 위한 핵심은 공통점과 변형을 구분하는 데 있다 .

James.part-time.weekly-paid

John.full-time.weekly-paid

Jane.part-time.monthly-paid

공통점 분석 후 ,…

[Payment Type].weekly-paid.monthly-paid

[Working Style].part-time.full-time

[Worker].name. …

공통점 변형

독립적인 집합 이어야 함 어떤 다른 집합과는 본질적으로 다른 자기 혼자만의 고유한 집합이어야 한다는 것 다른 집합의 부분집합이되거나 다른 집합과의 교집합을 가지지 않아야 한다는 것

계약 거래상품

하나의 독립적인 집합으로 유지되며 독립적인 사물로써 상호작용을 수행

사물 (Things) 정의 대상 문제에 있어 명확한 경계와 의미를 가진 것이 객체이며 , 공동 의미 , 행동을 가진

객체 그룹 실존하는 집합으로써 다른 집합들과 구별(Identify)할 수 있는 것 어떤 사물의 집합 . 이 집합 안의 사물들은 같은 특징을 공유하고 , 같은 방식으로 행동하고 ,

같은 규칙과 정책을 준수함

통장 증서 수표 어음

실제 비즈니스에서 존재하는 사물들을 하나의 집합으로 묶어 클래스화

비사물 (Non-Things) 정의 비즈니스 내의 관행 등으로 관리되는 논리적인 관리대상을 객체들의 집합을

식별하는 것 논리적인 이유로 같은 부류에 속하는 객체들의 집합을 식별하는 것 공통성을 찾아 의미적으로 통합하여 하나의 집합으로 묶을 수 있어야 함

계약 자기앞수표발행 제사고신고 거래

비즈니스에서 관리되는 개념 객체들을 그룹화하여 클래스 화

행위관리 대상체의 분리 사물에 대한 복잡성 완화를 위해 객체들에 대한 고유정보와 행위관리를 위한 책임성을

분리하여야 함 행위가 반복적으로 발생하는 주체와 그 행위가 대상이 되는 사물정보에 대해

분리하여 관리함

계약상품

계약조건상품조건

기업의 판매되는 사물 대상체 판매된 행위관리 대상체

사물과 행위관리 기준으로 분리

서브 클래스화에 의한 분류 기존 클래스를 특수화해 서브클래스를 설정 서브 클래스마다 데이터나 메소드가 달라지는 경우 또는 별개의

클래스와 연관을 가지는 등 모델구조의 차이를 강조하기 위해 사용계약

수신 계약 대출 계약 지급보증 계약

수신관련Class

대출관련Class

지급보증관련Class

특정 비즈니스를 수용을 위한 Level

세부 업무별 특화된 처리

자기참조를 위한 계층 구조화 자기 참조가 되는 구조를 구성하여 계층구조를 만들어속성과

메소드의 중복 해결해야 함 새로운 계층의 추가에 대응을 통한 구조변경 용이

고객

개인 조직

재귀적인 호출을 위해 계층구조

클래스간의 상호작용 확장 실제 객체들을 클래스화하면서 응집도를 높이기 위해서는 식별된 클래스간의 관계

및 상호인터페이스 기준을 명확히 설정해야 함 클래스간의 상호관계가 명확히 될 수록 클래스간의 커플링이 약하게 구성되어 다른

클래스와의 상호작용이 용이함

계좌 거래내역 타점권내역

계좌의 책임성을 계좌생명주기로 축소 계좌내의 입출금이 발생하는 모든 이벤트에 대한 책임성을 거래내역에 부여 계좌내의 입금 발생시 거래내역에 속한 타점권 정보관리에 대한 책임성을 부여

입금발생시 사물정보인 타점권 관리책임 분리

계좌개설 및 해지까지의 관리책임 분리

관리하고자 하는 대상 확장 '관리하고자 하는 ' 이란 의미는 관리하고자 하는 정보만을 클래스로 취할 것임을 의미한다 . 업무의 목적과 범위 , 전략 , 방향에 따라 클래스로 취할 수도 있고 버릴 수도 있다는 것을

의미한다 . 그렇다면 먼저 이러한 부분이 분명하게 정의하는 것은 매우 중요한 일일 것이다 . 현재 우리가 관리하고자 하는 것과 앞으로 관리하고자 하는 것까지도 포함하는 말이다 .

계약

거래 계약이후 계약이 종료시까지 세부적인 행위내역을 관리

계약에 대한 행위를 관리

고객과의 계약이후 해제까지의 비즈니스적 관리 대상

계약생명주기

거래생명주기

계약조건변경 거래

입출금거래