다운로드
작성자: admin 작성일시: 2016-08-03 19:47:13 조회수: 2713 다운로드: 222
카테고리: Python 태그목록:

Python 객체 지향 프로그래밍 (Object-Oriented Programming)

객체 (Object)

  • 코드 실행을 위해 필요한 것

    • 자료 -> 변수 (variable)
    • 작업 실행 방법 -> 함수 (function)
  • 객체

    • 관련이 있는 자료(변수)와 실행 방법(함수)를 한 곳에 모아 놓은 것
    • 멤버 member, 속성 attribute
  • 멤버 변수 member variable
    • 자료
    • 객체 내의 변수
    • 데이터 속성 data attribute
  • 멤버 메소드 member method
    • 실행 방법
    • 객체 내의 함수
    • 함수(메소드) 속성 function(method) attribute
In:
x = np.array([1])
In:
dir(x)
Out:
['T',
 '__abs__',
 '__add__',
 '__and__',
 '__array__',
 '__array_finalize__',
 '__array_interface__',
 '__array_prepare__',
 '__array_priority__',
 '__array_struct__',
 '__array_wrap__',
 '__class__',
 '__contains__',
 '__copy__',
 '__deepcopy__',
 '__delattr__',
 '__delitem__',
 '__delslice__',
 '__div__',
 '__divmod__',
 '__doc__',
 '__eq__',
 '__float__',
 '__floordiv__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__getslice__',
 '__gt__',
 '__hash__',
 '__hex__',
 '__iadd__',
 '__iand__',
 '__idiv__',
 '__ifloordiv__',
 '__ilshift__',
 '__imod__',
 '__imul__',
 '__index__',
 '__init__',
 '__int__',
 '__invert__',
 '__ior__',
 '__ipow__',
 '__irshift__',
 '__isub__',
 '__iter__',
 '__itruediv__',
 '__ixor__',
 '__le__',
 '__len__',
 '__long__',
 '__lshift__',
 '__lt__',
 '__mod__',
 '__mul__',
 '__ne__',
 '__neg__',
 '__new__',
 '__nonzero__',
 '__oct__',
 '__or__',
 '__pos__',
 '__pow__',
 '__radd__',
 '__rand__',
 '__rdiv__',
 '__rdivmod__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__rfloordiv__',
 '__rlshift__',
 '__rmod__',
 '__rmul__',
 '__ror__',
 '__rpow__',
 '__rrshift__',
 '__rshift__',
 '__rsub__',
 '__rtruediv__',
 '__rxor__',
 '__setattr__',
 '__setitem__',
 '__setslice__',
 '__setstate__',
 '__sizeof__',
 '__str__',
 '__sub__',
 '__subclasshook__',
 '__truediv__',
 '__xor__',
 'all',
 'any',
 'argmax',
 'argmin',
 'argpartition',
 'argsort',
 'astype',
 'base',
 'byteswap',
 'choose',
 'clip',
 'compress',
 'conj',
 'conjugate',
 'copy',
 'ctypes',
 'cumprod',
 'cumsum',
 'data',
 'diagonal',
 'dot',
 'dtype',
 'dump',
 'dumps',
 'fill',
 'flags',
 'flat',
 'flatten',
 'getfield',
 'imag',
 'item',
 'itemset',
 'itemsize',
 'max',
 'mean',
 'min',
 'nbytes',
 'ndim',
 'newbyteorder',
 'nonzero',
 'partition',
 'prod',
 'ptp',
 'put',
 'ravel',
 'real',
 'repeat',
 'reshape',
 'resize',
 'round',
 'searchsorted',
 'setfield',
 'setflags',
 'shape',
 'size',
 'sort',
 'squeeze',
 'std',
 'strides',
 'sum',
 'swapaxes',
 'take',
 'tobytes',
 'tofile',
 'tolist',
 'tostring',
 'trace',
 'transpose',
 'var',
 'view']
In:
[attr for attr in dir(x) if not callable(getattr(x, attr))]
Out:
['T',
 '__array_finalize__',
 '__array_interface__',
 '__array_priority__',
 '__array_struct__',
 '__doc__',
 '__hash__',
 'base',
 'ctypes',
 'data',
 'dtype',
 'flags',
 'flat',
 'imag',
 'itemsize',
 'nbytes',
 'ndim',
 'real',
 'shape',
 'size',
 'strides']
In:
# list of methods
[method for method in dir(x) if callable(getattr(x, method))]
Out:
['__abs__',
 '__add__',
 '__and__',
 '__array__',
 '__array_prepare__',
 '__array_wrap__',
 '__class__',
 '__contains__',
 '__copy__',
 '__deepcopy__',
 '__delattr__',
 '__delitem__',
 '__delslice__',
 '__div__',
 '__divmod__',
 '__eq__',
 '__float__',
 '__floordiv__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__getslice__',
 '__gt__',
 '__hex__',
 '__iadd__',
 '__iand__',
 '__idiv__',
 '__ifloordiv__',
 '__ilshift__',
 '__imod__',
 '__imul__',
 '__index__',
 '__init__',
 '__int__',
 '__invert__',
 '__ior__',
 '__ipow__',
 '__irshift__',
 '__isub__',
 '__iter__',
 '__itruediv__',
 '__ixor__',
 '__le__',
 '__len__',
 '__long__',
 '__lshift__',
 '__lt__',
 '__mod__',
 '__mul__',
 '__ne__',
 '__neg__',
 '__new__',
 '__nonzero__',
 '__oct__',
 '__or__',
 '__pos__',
 '__pow__',
 '__radd__',
 '__rand__',
 '__rdiv__',
 '__rdivmod__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__rfloordiv__',
 '__rlshift__',
 '__rmod__',
 '__rmul__',
 '__ror__',
 '__rpow__',
 '__rrshift__',
 '__rshift__',
 '__rsub__',
 '__rtruediv__',
 '__rxor__',
 '__setattr__',
 '__setitem__',
 '__setslice__',
 '__setstate__',
 '__sizeof__',
 '__str__',
 '__sub__',
 '__subclasshook__',
 '__truediv__',
 '__xor__',
 'all',
 'any',
 'argmax',
 'argmin',
 'argpartition',
 'argsort',
 'astype',
 'byteswap',
 'choose',
 'clip',
 'compress',
 'conj',
 'conjugate',
 'copy',
 'cumprod',
 'cumsum',
 'diagonal',
 'dot',
 'dump',
 'dumps',
 'fill',
 'flatten',
 'getfield',
 'item',
 'itemset',
 'max',
 'mean',
 'min',
 'newbyteorder',
 'nonzero',
 'partition',
 'prod',
 'ptp',
 'put',
 'ravel',
 'repeat',
 'reshape',
 'resize',
 'round',
 'searchsorted',
 'setfield',
 'setflags',
 'sort',
 'squeeze',
 'std',
 'sum',
 'swapaxes',
 'take',
 'tobytes',
 'tofile',
 'tolist',
 'tostring',
 'trace',
 'transpose',
 'var',
 'view']
In:
x = np.arange(10)
x
Out:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In:
np.sum(x)
Out:
45
In:
# 객체 지향. 메소드 사용
x.sum()
Out:
45
In:
x.shape
Out:
(10,)

게임 프로그램에서의 객체

  • 플레이어의 캐릭터
    • 속성: 캐릭터의 능력치, 경험치 등
    • 메소드: 캐릭터를 움직이는 방법, 이동, 공격 등

객체(인스턴스)와 클래스의 관계

  • 객체(인스턴스)
    • 속성들의 모음
    • 예: 붕어빵
  • 클래스
    • 객체를 생성하기 위한 코드 모음
    • 예: 붕어빵을 만드는 틀

Python Class 정의

In:
class MyClass(object):
    """A simple example class"""
    i = 12345
    def f(self):
        return 'hello world'
In:
a = MyClass()
b = MyClass()
In:
a.i, b.i
Out:
(12345, 12345)
In:
a.f()
Out:
'hello world'
In:
b.f()
Out:
'hello world'
In:
MyClass.__doc__
Out:
'A simple example class'
In:
MyClass?
In:
a?

Constructor 생성자

  • 클래스에서 인스턴스를 만드는 순간에 호출되는 특수 메소드
  • 인스턴스의 멤버 변수 값을 초기화
  • 이름 = __init__
  • 인스턴스 = self
In:
class Complex(object):
    def __init__(self, realpart, imagpart):
        self.r = realpart
        self.i = imagpart
In:
x = Complex(3.0, -4.5)
In:
x.r, x.i
Out:
(3.0, -4.5)

Game Program 에서의 객체(인스턴스)와 클래스

In:
class Character(object):
    def __init__(self):
        self.life = 1000
    
    def attacked(self):
        self.life -= 10
        print(u"공격받음! 생명력 =", self.life)    
In:
a = Character()
b = Character()
c = Character()
In:
a.life, b.life, c.life
Out:
(1000, 1000, 1000)
In:
a.attacked()
공격받음! 생명력 = 990
In:
b.attacked()
공격받음! 생명력 = 990
In:
a.attacked()
a.attacked()
a.attacked()
a.attacked()
a.attacked()
공격받음! 생명력 = 980
공격받음! 생명력 = 970
공격받음! 생명력 = 960
공격받음! 생명력 = 950
공격받음! 생명력 = 940
In:
a.life, b.life, c.life
Out:
(940, 990, 1000)

클래스 멤버와 인스턴스 멤버

  • 클래스 멤버
    • 모든 인스턴스에 공통
  • 인스턴스 멤버
    • 각 인스턴스마다 다름
In:
class Dog(object):
    kind = 'canine'
    def __init__(self, name):
        self.name = name
In:
a = Dog('Fido')
b = Dog('Buddy')
In:
a.kind, b.kind
Out:
('canine', 'canine')
In:
Dog.kind
Out:
'canine'
In:
a.name, b.name
Out:
('Fido', 'Buddy')
In:
class Dog(object):
    kind = 'canine'
    def __init__(self, name):
        self.name = name
        self.tricks = []
    def add_trick(self, trick):
        self.tricks.append(trick)
In:
a = Dog('Fido')
b = Dog('Buddy')
In:
a.add_trick('roll over')
In:
b.add_trick('roll over')
b.add_trick('play dead')
In:
a.tricks, b.tricks
Out:
(['roll over'], ['roll over', 'play dead'])

속성 목록 출력

  • dir()
    • 상위의 모든 클래스 변수, 메소드 포함
    • 이름(문자열) 리스트 출력
  • __dict__
    • 인스턴스 멤버 변수만 포함
    • 이름과 값을 포함하는 사전 출력
In:
dir(a)
Out:
['__class__',
 '__delattr__',
 '__dict__',
 '__doc__',
 '__format__',
 '__getattribute__',
 '__hash__',
 '__init__',
 '__module__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 'add_trick',
 'kind',
 'name',
 'tricks']
In:
a.__dict__
Out:
{'name': 'Fido', 'tricks': ['roll over']}

멤버 변수를 동적으로 생성하기

In:
a.age = 3
In:
a.__dict__
Out:
{'age': 3, 'name': 'Fido', 'tricks': ['roll over']}
In:
b.__dict__
Out:
{'name': 'Buddy', 'tricks': ['roll over', 'play dead']}

Immutable Class Member: 덮어쓰기

In:
b.kind = "K9"
In:
a.kind, b.kind
Out:
('canine', 'K9')
In:
a.__dict__
Out:
{'age': 3, 'name': 'Fido', 'tricks': ['roll over']}
In:
b.__dict__
Out:
{'kind': 'K9', 'name': 'Buddy', 'tricks': ['roll over', 'play dead']}
In:
Dog.kind, a.kind, b.kind
Out:
('canine', 'canine', 'K9')
In:
id(Dog.kind), id(a.kind), id(b.kind)
Out:
(140428378474128, 140428378474128, 140428389513056)

Mutable Class Member: 잘못된 공유

In:
class Dog(object):
    tricks = []
    def __init__(self, name):
        self.name = name
    def add_trick(self, trick):
        self.tricks.append(trick)
In:
a = Dog('Fido')
b = Dog('Buddy')
In:
a.add_trick('roll over')
In:
a.tricks, b.tricks
Out:
(['roll over'], ['roll over'])

접근 권한

  • Python은 기본적으로 속성에 대해 접근 권한(access permission)을 모두 public으로 한다.
  • 단, 이름이 double underscore (__)로 시작하는 속성에 대해서는 내부 접근 이름과 외부 접근 이름이 달라진다.
    • 내부 접근시 : 그냥 속성 이름 사용
    • 외부 접근시 : 속성 이름 앞에 _classname을 붙어서 접근한다.
In:
class NotAllowedSum(object):
    def __init__(self):
        self.__sum = 0
    def get_sum(self):
        return self.__sum
    def add(self, num):
        self.__sum += num
In:
nas = NotAllowedSum()
In:
nas.get_sum()
Out:
0
In:
nas.add(5)
In:
nas.get_sum()
Out:
5
In:
nas.__sum

AttributeErrorTraceback (most recent call last)
 in ()
----> 1 nas.__sum

AttributeError: 'NotAllowedSum' object has no attribute '__sum'
In:
nas._NotAllowedSum__sum
Out:
5

상속 (Inheritance)

  • 이미 만들어진 클래스를 이용하여 다른 클래스를 생성

  • 예: Game Program에서 다음과 같은 직업을 가진 캐릭터 생성

    • Warrior
    • Wizard
In:
class Character(object):
    def __init__(self):
        self.life = 1000
        self.strength = 10
        self.intelligence = 10
    def attacked(self):
        self.life -= 10
        print(u"공격받음! 생명력 =", self.life) 
In:
class Warrior(Character):
    def __init__(self):
        super(Warrior, self).__init__()
        self.strength = 15
        self.intelligence = 5
In:
class Wizard(Character):
    def __init__(self):
        super(Wizard, self).__init__()
        self.strength = 5
        self.intelligence = 15
In:
a = Warrior()
b = Wizard()
In:
a.strength, b.strength
Out:
(15, 5)
In:
a.intelligence, b.intelligence
Out:
(5, 15)
In:
a.attacked()
공격받음! 생명력 = 990
In:
b.attacked()
공격받음! 생명력 = 990

메소드 오버라이딩 (Method Overriding)

  • 동일한 이름의 메소드가 클래스에 따라 실제로 실행되는 코드가 달라짐
In:
class Character(object):
    def __init__(self):
        self.life = 1000
        self.strength = 10
        self.intelligence = 10
    def attacked(self):
        self.life -= 10
        print(u"공격받음! 생명력 =", self.life) 
    def attack(self):
        print(u"공격!")             
In:
class Warrior(Character):
    def __init__(self):
        super(Warrior, self).__init__()
        self.strength = 15
        self.intelligence = 5
    def attack(self):
        print(u"육탄 공격!") 
In:
class Wizard(Character):
    def __init__(self):
        super(Wizard, self).__init__()
        self.strength = 5
        self.intelligence = 15
    def attack(self):
        print(u"마법 공격!") 
In:
a = Character()
b = Warrior()
c = Wizard()
In:
a.attack()
공격!
In:
b.attack()
육탄 공격!
In:
c.attack()
마법 공격!
In:
a.attacked()
공격받음! 생명력 = 990
In:
b.attacked()
공격받음! 생명력 = 990

참조: 오버로딩 Overloading

  • C++, Java 등에서는 같은 함수 이름이지만 인수의 타입이나 숫자에 따라 다른 함수가 실행될 수 있다.
  • Python은 오버로딩을 지원하지 않는다.
    • 프로그래머가 내부적으로 알아서 처리해야 한다
float length(list p1, list p2);                  // 점 (p1[0], p1[1]) - (p1[0], p1[1]) 까지의 길이
float length(int x1, int y1, int x2, int y2);    // 점 (x1, y1) - (x2, y2) 까지의 길이
In:
def length(*args):
    if len(args) == 2:
        x1 = args[0][0]
        y1 = args[0][1]
        x2 = args[1][0]
        y2 = args[1][1]
        return np.sqrt((x1 - x2)**2 + (y1 - y2)**2)
    elif len(args) == 4:
        x1 = args[0]
        y1 = args[1]
        x2 = args[2]
        y2 = args[3]
        return np.sqrt((x1 - x2)**2 + (y1 - y2)**2)
    else:
        raise ValueError()
In:
length([0, 0], [1, 1])
Out:
1.4142135623730951
In:
length(0, 0, 1, 1)
Out:
1.4142135623730951

Decorator 데코레이터

  • 함수 자체를 인수로 받아서 어떤 일을 수행하는 방법
    • 함수의 출력 결과에 원하는 부분을 추가하여 다른 함수로 만든다.
  • Decorator를 사용하는 경우
    @dec2
    @dec1
    def func(arg1, arg2, ...):
      pass
  • Decorator를 사용하지 않는 경우
    def func(arg1, arg2, ...):
      pass
    func = dec2(dec1(func))
In:
def f1(x, y):
    z = x + y
    return x, y, z
In:
f1(1, 2)
Out:
(1, 2, 3)
In:
def print_form(func):
    def func_wrapper(x, y):
        return "x = {0}\ny = {1}\nx + y = {2}".format(x, y, func(x, y)[-1])
    return func_wrapper
In:
@print_form
def f2(x, y):
    z = x + y
    return x, y, z
In:
f2(1, 2)
Out:
'x = 1\ny = 2\nx + y = 3'
In:
print(f2(1,2))
x = 1
y = 2
x + y = 3

스태틱 메소드 static method, 클래스 메소드 class method

  • 인스턴스와 상관없이 클래스에 따라 실행되는 메소드
  • static method

    • @staticmethod 데코레이터 decorator 사용
    • Class 객체를 인수로 받지 않는다.
    • Class 멤버 변수를 사용할 수 없다.
  • class method

    • @classmethod 데코레이터 decorator 사용
    • Class 객체를 받는다.
    • Class 멤버 변수를 사용할 수 있다.
In:
class A(object):
    @staticmethod
    def say_classname():
        print("My class name is", "A")        
In:
a = A()
In:
a.say_classname()
My class name is A
In:
A.say_classname()
My class name is A
In:
class B(A):
    pass
In:
b = B()
In:
b.say_classname()
My class name is A
In:
class A(object):
    class_name = "A"
    @classmethod
    def say_classname(cls):
        print("My class name is", cls.class_name)
In:
class B(A):
    class_name = "B"
In:
a = A()
b = B()
In:
a.say_classname()
My class name is A
In:
b.say_classname()
My class name is B

Property

  • 가상의 멤버 변수
  • 다른 멤버 변수에 종속적인 값을 출력
  • @property 데코레이터 decorator 사용
In:
class Circle(object):
    def __init__(self, radius):
        self.radius = radius
    @property
    def area(self):
        return np.pi * self.radius**2;
In:
c = Circle(2)
In:
c.area  # not c.area()
Out:
12.566370614359172
  • __repr__
  • __str__
In:
c = Complex(1, 1)
c
Out:
<__main__.Complex at 0x7fb8079ff090>
In:
str(c)
Out:
'<__main__.Complex object at 0x7fb8079ff090>'
In:
class Complex2(Complex):
    def __repr__(self):
        return "Complex: real = %f imag = %f" % (self.r, self.i)
    def __str__(self):
        return "[for str] " + self.__repr__()
In:
c2 = Complex2(1, 1)
c2
Out:
Complex: real = 1.000000 imag = 1.000000
In:
str(c2)
Out:
'[for str] Complex: real = 1.000000 imag = 1.000000'
  • __getitem__
In:
c2["imag"]

TypeErrorTraceback (most recent call last)
 in ()
----> 1 c2["imag"]

TypeError: 'Complex2' object has no attribute '__getitem__'
In:
class Complex3(Complex2):
    def __getitem__(self, key):
        if key in ["r", "real"]:
            return self.r
        if key in ["i", "imag"]:
            return self.i        
In:
c3 = Complex3(1, 2)
c3
Out:
Complex: real = 1.000000 imag = 2.000000
In:
c3["i"]
Out:
2

질문/덧글

아직 질문이나 덧글이 없습니다. 첫번째 글을 남겨주세요!