티스토리 뷰

Python

OOP 기초 지식

techbard 2015. 7. 10. 11:30
  • Procedural vs Object-Oriented

# Procedural

import string

myStr = ' contain whitespace '

myStr = string.strip(myStr)


# Object-Oriented

myStr = ' contain whitespace '

myStr = myStr.strip()

  • 가장 간단한 클래스의 형태

# 클래스 템플릿

class c(object):

def __init__(self, arg):

super(c, self).__init__()

self.arg = arg

print(arg)

c = c('ok')


결과)

ok



  • 용어
  1. 클래스를 변수에 할당함 = 클래스의 실체화 = 인스턴스 생성 = 메모리에 클래스를 적재
  2. 클래스는 변수와 함수를 한 컨테이너에 담은 것
  3. 하나의 클래스를 이용해 다수의 객체를 생성할 수 있으므로 각각의 객체를 구분하기 위해서 클래스에 self를 사용한다. 이 self의 의미는 이번에 내가 생성한 객체 바로 그것을 나타낸다. 최초 생성될 때는 내용은 같지만 메모리 내에는 구분된 다른 공간들을 차지 하고 있으므로 차지하고 있는 공간 각각을 가리킨다고 이해할 수도 있다. 또 클래스의 모양으로는 변수명이 동일하므로 서로 다른 객체의 같은 변수명이 차지하고 있기 때문에 self가 달라지면 그 변수 또한 다른 것을 의미하도록 self가 역할을 한다고도 볼 수 있다.
  4. 클래스 내의 변수는 필드 함수는 메쏘드로 부르며, 필드 + 메쏘드 = 속성이라 한다.
  5. 필드는 또 다시 두 가지로 나뉘어 지는데, 클래스 변수와 객체 변수이다. 클래스에서 여러 개의 객체가 탄생한다고 했으니 클래스 변수는 단 하나이며 객체 변수는 여러 개가 가능하다. 객체의 모태가 클래스이므로 클래스 변수가 바뀌면 여러 객체들에서도 클래스 변수는 다 변경된 상태이다. 하지만 객체 변수는 객체마다 가지고 있으므로 (self의 존재가 그것을 증명한다) 객체 변수 개개는 서로 다른 값을 가질 수 있다.
  6. Class: A Blueprint for an object
  7. Object: An Instance of a class
  8. A Class consists of data and Actions (Variables & Methods)
  9. Two types Data: Class Variables & Instance Variables
  10. Class Variables and Methods are shared by all objects of a class
  11. Instance Variables are within the object space and accessible only to that object
  12. Encapsulation: Packaging of Data Variables and action methods is called encapsulation
  13. Inheritance: Classes can be extended (both attributes and functionality) by creating derived classes using all the properties of base (super) class
  14. Multiple Inheritance: Creating classes using more than one base class. Python supports multiple Inheritance
  15. Methods Overriding: A base class method can be changed or extended in a derived class
  16. Objects
    1. The name for "a thing"
    2. An object is instantiated (created) from a class
  17. Classes
    1. The blueprint for an object; declaring what the thing has and what the thing does
  18. Attributes
    1. What the thing has
  19. Methods
    1. What the thing does; these are no different from subroutines (at procedural programming)
  20. Concepts
    1. Behavior is created by object interaction (a.k.a message passing)
    2. Objects are interacted with via their methods
    3. Objects contain state (data) via theit attributes
  • 클래스의 구조 기초

# 속성을 가진 클래스를 정의한다.

class House:
    doors = 1

 

# 클래스에서 객체를 만든 후 속성을 읽어온다.

class House:
    doors = 1

 

myHouse = House()

print(myHouse.doors)

 

결과)

1

 

# 객체의 속성에 쓰기를 한다.

class House:
    doors = 1

 

myHouse = House()
myHouse.doors = 4

print(myHouse.doors)

 

결과)

4

 

# 객체에 속성을 읽기하는 메쏘드를 추가한다.

class House:
    doors = 1

 

    def openDoors(self):
        for door in range(self.doors):
            print('door opened.')

 

myHouse = House()
myHouse.doors = 4

myHouse.openDoors()

 

결과)

door opened.
door opened.
door opened.
door opened.

 

# 객체에 속성 쓰기하는 메쏘드를 추가한다.

class House:
    doors = 1

 

    def openDoors(self):
        for door in range(self.doors):
            print('door opened.')

 

    def addDoors(self, number):
        self.doors += number

 

myHouse = House()
myHouse.doors = 4
myHouse.addDoors(1)

myHouse.openDoors()

 

결과)

door opened.
door opened.
door opened.
door opened.
door opened.

 

# 초기화 메쏘드의 추가

class House:
    def __init__(self, doors):
        self.doors = doors

 

    def openDoors(self):
        for door in range(self.doors):
            print('door opened.')

 

myHouse = House(doors = 4)
myHouse.openDoors()

 

결과)

door opened.
door opened.
door opened.
door opened.

 

# 클래스의 상속

class House:
    def __init__(self, doors):
        self.doors = doors

 

    def openDoors(self):
        for door in range(self.doors):
            print('door opened.')

 

class Villa(House):
    pass

 

myHouse = Villa(doors = 4)
myHouse.openDoors()

 

결과)

door opened.
door opened.
door opened.
door opened.

 

# 상속 클래스에 추가된 메쏘드 사용

class House:
    def __init__(self, doors):
        self.doors = doors

 

    def openDoors(self):
        for door in range(self.doors):
            print('door opened.')

 

class Villa(House):
    swimpool = True

 

    def readyToSwim(self):
        if self.swimpool:
            print('You can swimming.')
        else:
            print('You can not swimming now.')

 

myHouse = Villa(doors = 4)
myHouse.openDoors()
myHouse.readyToSwim()

 

결과)

door opened.
door opened.
door opened.
door opened.
You can swimming.

 

# 상속 클래스에서 부모 클래스와 동일한 메쏘드 이름을 사용할 수 있음

class House:
    def __init__(self, doors):
        self.doors = doors

 

    def openDoors(self):
        for door in range(self.doors):
            print('door opened.')

 

class Villa(House):
    swimpool = True

    def readyToSwim(self):
        if self.swimpool:
            print('You can swimming.')
        else:
            print('You can not swimming now.')

 

    def paintingOutside(self):
        print('Your villa applied new paintings.')

 

class Apartment(House):
    def paintingOutside(self):
        print('Your apartment applied new paintings.')   

 

myBuildings = [Villa(doors=1), Apartment(doors=2)]

 

for mb in myBuildings:
    mb.paintingOutside()

 

결과)

Your villa applied new paintings.
Your apartment applied new paintings.


# 다형성 - 상속된 객체에 있는 메쏘드를 동일한 방식으로 호출할 수 있다.

class Characters():

    def display(self):

        print('Parent display.')


class String(Characters):

    def display(self):

        print('String display.')


class Number(Characters):

    def display(self):

        print('Number display.')


c = Characters()

s = String()

n = Number()


for o in (c, s, n):

    o.display()


결과)

Parent display.

String display.

Number display.


# 다형성 - 객체에 알맞는 메쏘드만 실행한다.

class Characters():

    def display(self):

        print('Parent display.')


class String(Characters):

    def display(self):

        print('String display.')


    def lower(self):

        print('String lowered.')


    def double(self):

        return


class Number(Characters):

    def display(self):

        print('Number display.')


    def lower(self):

        return


    def double(self):

        print('Number is doubled.')


s = String()

n = Number()


for o in (s, n):

    o.display()

    o.lower()

    o.double()


결과)

String display.

String lowered.

Number display.

Number is doubled.


# 상속 객체에 없는 메쏘드는 부모 객체에서 찾는다.

class P():

    def walk(self):

        print('walking.')


class C(P):

    def crawl(self):

        print('crawling.')


c = C()

c.crawl()


c.walk()


결과)

crawling.

walking.

  • 클래스의 인자

# 클래스의 인스턴스를 생성할때 인자가 맞지 않으면 실패한다.

class Person():

def __init__(self, name, age, address):

self.name = name

self.age = age

self.address = address


def getName(self):

return self.name


def getAge(self):

return self.age

def getAddress(self):

return self.address


noArgs = Person()


결과)

TypeError: __init__() missing 3 required positional arguments: 'name', 'age', and 'address'


# 함수의 인자와 마찬가지로 default 인자를 줄 수 있다.

class Person():

def __init__(self, name='noname', age=None, address=None):

self.name = name

self.age = age

self.address = address


def getName(self):

return self.name


def getAge(self):

return self.age

def getAddress(self):

return self.address


defaultArgs = Person()


currentName = defaultArgs.getName()

print(currentName)


결과)

noname


# 객체의 필드를 직접 수정할 수 있다.

class Person():

def __init__(self, name='noname', age=None, address=None):

self.name = name

self.age = age

self.address = address


def getName(self):

return self.name


def getAge(self):

return self.age

def getAddress(self):

return self.address


defaultArgs = Person()

defaultArgs.name = 'mike'


currentName = defaultArgs.getName()

print(currentName)


결과)

mike


# 두 개의 언더스코어를 붙이면 외부에서 직접 액세스 할 수 없다.

class Person():

def __init__(self, name='noname', age=None, address=None):

self.__name = name

self.__age = age

self.__address = address


def getName(self):

return self.__name


def getAge(self):

return self.__age

def getAddress(self):

return self.__address


defaultArgs = Person()

defaultArgs._name = 'mike'


currentName = defaultArgs.getName()

print(currentName)


결과)

noname

  • 관용적인 클래스 인자의 사용

# kwargs와 getter/setter 메쏘드를 이용해서 flexiable한 코드가 가능하다.

class Animal:

    def __init__(self, **kwargs):

        self.variables = kwargs


    def setVariable(self, k, v):

        self.variables[k] = v


    def getVariable(self, k):

        return self.variables.get(k, None)


a = Animal(color = 'white')

a.setVariable('height', 2)

print(a.getVariable('color'))

print(a.getVariable('height'))


결과)

white

2

  • 클래스 메쏘드와 스태틱 메쏘드

# 클래스 변수와 마찬가지 의미로 클래스 메쏘드가 가능하다. 의미상 클래스의 객체가 만들어지지 않은 상황에서 메소드가 필요할 때 사용할 수 있으며 관례상 self 자리에 cls로 표기한다.

class Item():

def __init__(self, color, size):

self.color = color

self.size = size


def display(self):

print('color: ' + self.color, 'size: ' + self.size)


@classmethod

def createItem(cls, itemlist):

for color, size in itemlist:

yield cls(color, size)


items = ('yellow', 'middle'), ('black', 'small')


for i in Item.createItem(items):

i.display()


결과)

color: yellow size: middle

color: black size: small




# 스태택 메쏘드는 클래스 메쏘드와 유사한 성질을 가지지만 객체를 인자로 받지 않는다. 클래스 메쏘드와 비교할 때 같은 일을 하는데 있어 명시적으로 클래스 이름을 적어야 하는 면에서 차이가 있다.

class Item():

def __init__(self, color, size):

self.color = color

self.size = size


def display(self):

print('color: ' + self.color, 'size: ' + self.size)


@staticmethod

def createItem(itemlist):

for color, size in itemlist:

yield Item(color, size)


items = ('yellow', 'middle'), ('black', 'small')


for i in Item.createItem(items):

i.display()


결과)

color: yellow size: middle

color: black size: small

  • 데코레이터

# 데코레이터를 사용한 프로퍼티 세팅/게팅

class Thing():

    def __init__(self, **kwargs):

        self._properties = kwargs


    @property

    def color(self):

        return self._properties.get('color', None)


    @color.setter

    def color(self, c):

        self._properties['color'] = c


    @color.deleter

    def color(self):

        del self._properties['color']


t = Thing()

t.color = 'white'

print(t.color)


결과)

white

  • 상속

# 자식 클래스에서는 부모 클래스의 속성을 이어 받을 수 있다. 이러한 상속 관계를 가지기 때문에 부모 클래스의 변경 사항 한 번으로 이를 상속받은 자식 클래스에 바로 변경이 반영될 수 있다. 또한 같은 이름의 메쏘드라도 자식 클래스 마다 각각 다르게 정의할 수 있어서 코딩을 간편하게 유지할 수 있다.

class Transport():

def __init__(self, name):

self.name = name

def display(self):

print('Name: ' + self.name)


class Bicycle(Transport):

def __init__(self, name, wheel):

super().__init__(name)

self.wheel = wheel


def display(self):

super().display()

print('Wheel: ', self.wheel)


class Car(Transport):

def __init__(self, name, fair):

super().__init__(name)

self.fair = fair

def display(self):

super().display()

print('Fair: ', self.fair)


b = Bicycle('Bicycle', 2)

c = Car('Car', 1000)


b.display()

c.display()


결과)

Name: Bicycle

Wheel:  2

Name: Car

Fair:  1000



# to-string 메소드 재정의를 통한 클래스 출력

# __str__ 메소드 재정의

class Name:

    def __init__(self, p1, p2, p3):

        self.p1 = p1

        self.p2 = p2

        self.p3 = p3


    def __str__(self):

        return self.p1 + ' ' + self.p2 + ' ' + self.p3


    def initials(self):

        return self.p1[0] + self.p2[0] + self.p3[0]


aPerson = Name('mike', 'jane', 'peggy')


print(aPerson)

print(aPerson.initials())


결과)

mike jane peggy

mjp

# 클래스의 필드, 메쏘드를 이용한 클래스의 이해

class Student:

# 클래스 필드 정의

    grades = []

# 인스턴스 필드 정의

    def __init__(self, name, id):

        self.name = name

        self.id = id

# 인스턴스 메쏘드로 클래스 필드에 값을 추가한다.

    def addGrade(self, grade):

        self.grades.append(grade)

# 인스턴스 메쏘드로 새로운 값을 반환한다.

    def showGrades(self):

        grds = ''

        for grade in self.grades:

            grds += str(grade) + ' '

        return grds

# 인스턴스 필드와 메쏘드에 접근한다.

    def __str__(self):

        return 'Name: '  + self.name + '\n' + \

                'Id: ' + self.id + '\n' + \

                'Grades: ' + self.showGrades() + '\n' + \

                'Average: ' + str(self.getAverage())

# 클래스 필드에 접근해서 계산값을 반환한다.

    def getAverage(self):

        total = 0

        for grade in self.grades:

            total += grade

        return total / len(self.grades)


s1 = Student('mike', '112') 

s1.addGrade(45)

s1.addGrade(80)

s1.addGrade(68)

print(s1)


결과)

Name: mike

Id: 112

Grades: 45 80 68 

Average: 64.33333333333333

  • Attribute 조작

# getattr, setattr, hasattr

class Person():

    def __init__(self, name, age):

        self.name = name

        self.age = age


p = Person('mike', 22)


n = getattr(p, "name")

print(n)


setattr(p, "name", "jane")

n = getattr(p, "name")

print(n)


h = hasattr(p, "name")

print(h)


결과)

mike

jane

True


"""

Polymorphism


- The third pillar of OOP

- Two classes with samen interface (i.e., method name)

- The methods are often different, but conceptually similar

- Allows for expressiveness in design: we can say that

this group of related classes implement the same action

- Duck typing refers to reading an object's attributes to decide

whether it is of a proper type, rather than checking the

type itself


"""


"""

Inheritance Examples


- When working in a child class we can choose to

implement parent class methods in different ways

- inherit: simply use the parent class' defined

method

- Override/overload: provide child's own version

of a method

- Extend: do work in addition to that in parent's

method

- Provide: implement abstract method that parent

requires

"""


"""

Composition vs. Inheritance


- Inheritance can be brittle (a change may require

changes elsewhere)

- Decoupled code is classes, functions, etc. that

work independently and don't depend on one another

- As long as the interface is maintained, interactions

between classes will work

- Not checking or requiring particular types is

polymorphic and Pythonic


"""


# Implementing Core Syntax


class MaxList():

def __init__(self, this_list):

self.mylist = this_list


def __add__(self, other):

new_list = [max(x, y) for x, y in zip(self.mylist, other.mylist)]

return MaxList(new_list)


def __repr__(self):

return str(self.mylist)


cc = MaxList([1, 2, 3, 4, 5])

dd = MaxList([5, 4, 3, 2, 1])


ee = cc + dd

print(ee)


# 결과

[5, 4, 3, 4, 5]


# Subclassing - dict


class MyDict(dict):

def __setitem__(self, key, val):

print("setting a key and value.")

dict.__setitem__(self, key, val)


dd = MyDict()

dd['a'] = 5

dd['6'] = 6


for key in dd.keys():

print('{} = {}'.format(key, dd[key]))


# 결과

setting a key and value.

setting a key and value.

6 = 6

a = 5


# class를 사용해서 두 리스트의 합을 가진 새로운 리스트를 리턴


class PlusList():

def __init__(self, this_list):

self.mylist = this_list


def __add__(self, other):

new_list = [x + y for x, y in zip(self.mylist, other.mylist)]

return PlusList(new_list)


def __repr__(self):

return str(self.mylist)


a = PlusList([1, 2])

b = PlusList([1, 1])

c = a + b

print(c)


# 결과

[2, 3]


# BO(Business Object), Data, UI로 분리해서 구현한 두 개 리스트의 합 리턴


class Data():

def __init__(self, list):

self.this_list = list


def get_data(self):

return self.this_list


class Calc():

def __init__(self, one, two):

self.one = one

self.two = two


def plus(self):

new_list = [x + y for x, y in zip(self.one.get_data(), self.two.get_data())]

return new_list


class UI():

def __init__(self):

self.one = Data([1, 2])

self.two = Data([1, 1])


self.calc = Calc(self.one, self.two)


def get_calc(self):

return self.calc.plus()


def get_one(self):

return self.one.get_data()


def get_two(self):

return self.two.get_data()


u = UI()

print(u.get_calc())


# 결과

[2, 3]


댓글
댓글쓰기 폼
공지사항
Total
410,768
Today
37
Yesterday
44
«   2019/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
글 보관함