In [4]:
id([1,2,3])


Out[4]:
4366758472

In [44]:
class Person:
    nationality = '대한민국'

In [45]:
p1 = Person()
p2 = Person()

print('{}의 국적: {}'.format('p1', p1.nationality))
print('{}의 국적: {}'.format('p2', p2.nationality))


p1의 국적: 대한민국
p2의 국적: 대한민국

In [46]:
Person.nationality = '중국'

print('{}의 국적: {}'.format('p1', p1.nationality))
print('{}의 국적: {}'.format('p2', p2.nationality))


p1의 국적: 중국
p2의 국적: 중국

In [47]:
Person.nationality = '일본'

print('{}의 국적: {}'.format('p1', p1.nationality))
print('{}의 국적: {}'.format('p2', p2.nationality))


p1의 국적: 일본
p2의 국적: 일본

In [49]:
class Person:
    def __init__(self, name, nationality):
        """객체가 생성될 때 실행되는 내부 함수"""
        self.name = name
        self.nationality = nationality

In [50]:
# 같은 종류의 정보로 구성된 여러 개의 정보 생성
p1 = Person('이성주', '대한민국')
p2 = Person('토니 스타크', 'USA')
p3 = Person('클라크 켄트', 'USA')

In [55]:
p3.nationality = '크립톤'
for p in [p1, p2, p3]:
    print('{}({})'.format(p.name, p.nationality))


이성주(대한민국)
토니 스타크(USA)
클라크 켄트(크립톤)

In [8]:
class Person:
    def __init__(self, name, nationality):
        self.name = name
        self.nationality = nationality
    
    def say_name(self):
        print('이름: {}'.format(self.name))

In [9]:
p1 = Person('이성주', '대한민국')
p2 = Person('토니 스타크', 'USA')
p3 = Person('클라크 켄트', '크립톤')

In [10]:
isinstance(p1, Person)


Out[10]:
True

In [11]:
isinstance(p1, dict)


Out[11]:
False

In [63]:
for p in [p1, p2, p3]:
    p.say_name()


이름: 이성주
이름: 토니 스타크
이름: 클라크 켄트

dict 을 사용했다면?


In [6]:
p1 = {'name':u'이성주', 'nationality': u'대한민국'}
p2 = {'user_name':u'토니 스타크', 'nationality': u'USA'}

def say_name(profile):
    if not isinstance(profile, dict):
        return
    if 'name' in profile:
        print(u'이름: {}'.format(profile['name']))

say_name(p1)
say_name(p2)
say_name(1)


이름: 이성주

클래스 영역과 객체 영역의 차이


In [70]:
class Person:
    number_of_people = 0
    def __init__(self, name, nationality):
        self.name = name
        self.nationality = nationality
        Person.number_of_people += 1
    
    def say_name(self):
        print('이름: {}'.format(self.name))

In [71]:
p1 = Person('이성주', '대한민국')
p2 = Person('토니 스타크', 'USA')
p3 = Person('클라크 켄트', '크립톤')

In [72]:
print(Person.number_of_people)


3

In [73]:
print(p1.number_of_people)


3

In [74]:
Person.number_of_people += 1
print(Person.number_of_people)


4

In [75]:
p1.number_of_people += 1
print(p1.number_of_people)


5

In [77]:
p1.number_of_people = 0
print(Person.number_of_people)
print(p1.number_of_people)


4
0

도전과제

카지노에 오는 사람들은 이름, 성별, 자본금 정보를 갖는다. 각 사람의 정보를 저장하는 클래스를 정의한다.

a. 자본금을 원화(KRW) 또는 달러화(USD)로 출력할 수 있도록 클래스를 정의하고 객체를 생성한다.

isinstance(p,Player) --> True

p.show_money(currency='KRW') --> 이성주의 자본금: 510,000 원 p.show_money(currency='USD') --> 이성주' budget: 500 USD

b. 각 사람은 게임에 참가한 결과 자본금이 변할 수 있다. 자본금의 변화를 반영할 수 있는 클래스의 메소드를 정의한다.

p.change_capital(10) --> 이성주의 자본금: 510 USD (+10)

p.change_capital(-30) --> 이성주의 자본금: 500 USD (-10)

c. 각 함수에는 적절한 자료형의 인자가 할당되어야 한다. 적절하지 않은 자료형의 인자가 할당되었을 때는 예외 처리를 수행해 프로그램이 비정상적으로 종료되지 않게 작성한다.


In [61]:
class Player:
    def __init__(self, name, isFemale, capital):
        self.name = name

        if not isinstance(isFemale, bool):
            # 불리언 형식이 아니면 ValueError 예외 발생
            # 객체 생성 실패
            raise ValueError

        self.isFemale = isFemale
        
        try:
            # 숫자 값으로 변환 시도
            self.capital = float(capital)
            # TODO: 음수 확인
        except:
            # 변환에 실패하면, 자본금의 값을 0으로 설정
            print('자본금을 0으로 지정합니다.')
            self.capital = 0.0
            
    def set_capital(self):
        pass
            
    def show_gender(self):
        """출력 예시: 이성주 님은 남성/여성입니다."""
        msg = u'{} 님은, {}입니다.'
        if self.isFemale:
            msg = msg.format(self.name, u'여성')
        else:
            msg = msg.format(self.name, u'남성')
        
        # 입출력은 되도록 마지막에 몰아서
        print(msg)

        return self.isFemale
        
    def show_money(self, currency='USD'):
        currency_rate = {'KRW': 1100, 
                         'USD': 1}
        
        # TODO: 만약 capital의 값이 숫자가 아니라면?
        # TODO: capital이 음수가 될 수 있을까?
        currency_converted = self.capital * currency_rate[currency]
        
        if currency == 'KRW':
            msg = u'{}의 자본금: {}'
        else:
            msg = u"{}'s budget: {}"

            
        print(msg.format(self.name, currency_converted))
        
        return currency_converted
    
    def change_capital(self, delta):
        self.capital += delta
        return self.capital
            
# 객체 생성       
p = Player(u'이성주', False, '5백 달러')
print(p.name)
p.show_money()
p.show_money(currency='KRW')
result = p.change_capital(+10)
p.show_gender()


자본금을 0으로 지정합니다.
이성주
이성주's budget: 0.0
이성주의 자본금: 0.0
이성주 님은, 남성입니다.
Out[61]:
False

도전과제

SJ 카지노는 블랙잭, 룰렛 두 가지 게임을 제공한다. 각 게임에는 참가자들이 1 명 이상 참가할 수 있다. SJ 카지노를 Casino 클래스로 정의하고, 클래스 내에서 각 게임들을 정의하시오.


In [91]:
from __future__ import print_function
import random

class Casino:
    def __init__(self, capital=10000000):
        self.capital = capital
        
    def generate_card(self):
        # 52장 카드 덱 생성
        suits = ['Heart', 'Diamond', 'Clover', 'Spade']
        ranks = range(2,11)+['J', 'Q', 'K', 'A']
        deck = []
        for s in suits:
            for r in ranks:
                card = s + str(r)
                deck.append(card)
        random.shuffle(deck)
        return deck
    
    def get_card_value(self, hand):
        """카드패의 숫자값 합계"""
        # 현재 hand의 카드의 숫자를 모두 더한다.
        value=0
        for card in hand:
            # 현재 카드의 숫자값
            rank = card[1]
            if rank=='A':
                value = value + 14
            elif rank=='K':
                value = value + 13
            elif rank == 'Q':
                value = value + 12
            elif rank == 'J':
                value = value + 11
            else:
                # 숫자인 경우는 그냥 더해준다.
                value = value + rank
                
        return value
    
    def play_blackjack(self, players, output_file=None):
        # 블랙잭 게임 시작
        deck=self.generate_card()
        
        # 각 참가자에 대해
        for p in players:
            # 카드 첫 두 장 받기
            p['hand'] = [deck.pop(), deck.pop()]
        
        # TODO: 여러 명이 참가할 수 있는 블랙잭 규칙 적용 ...

        # 게임 결과를 파일로 출력
        if output_file is not None:
            f = open(output_file, 'a')
            text_encoded = play_log.encode('utf-8')
            f.write(text_encoded)
            f.close()
    
    def play_roulette(self, players, output_file=None):
        """룰렛(Roulette)는 돌아가는 바퀴라는 의미인데 
        0으로부터 36까지 37~38개의 눈금으로 나눈 회전반 
        가운데 1개의 알을 넣고 돌리다가 정지했을 때 
        알이 어느 눈금에 정지하느냐를 맞추는 노름이다."""
        
        # 1. 각 플레이어 베팅
        bettings = []
        for p in players:
            # 각 플레이어 베팅 시뮬레이션
            bet_number = random.randint(0,36)
            # 베팅은 10 단위 이상, 참가자의 자본금 이하 액수로 무작위
            if p.capital < 10:
                continue
            bet = random.randint(10, p.capital)
            p.change_capital(-1*bet)# 베팅 액수만큼 감액
            bettings.append((p, bet_number, bet))
        
        # 2. 룰렛 돌리기
        spin = random.randint(0,36)
        
        # 3. 승패 확인
        winners = []
        for bet in bettings:
            if bet[1] == spin:
                # 승리!
                winners.append(bet[0])        
        
        # 4. 베팅 분배
        # 전체 베팅 금액을 승리자의 숫자로 균등 분배
        bet_total = 0
        for bet in bettings:
            bet_total += bet[2]
        
        if len(winners) == 0:
            print(u'House always wins')
            self.capital += bet_total
            print(self.capital)
            return
        
        reward = float(bet_total)/len(winners)
        for p in winners:
            p.change_capital(reward)
            
        # TODO: 결과 파일 출력력

In [92]:
casino = Casino()

p1 = Player(u'이성주', False, 500)
p2 = Player(u'신수현', True, 1000)
p3 = Player(u'유한별', False, 800)
p4 = Player(u'김경철', False, 1200)

players = [p1, p2, p3, p4]

for i in range(10):
    casino.play_roulette(players)

# 게임이 끝난 후 각 참가자들의 자본금 출력
for p in players:
    p.show_money()


House always wins
10001129
House always wins
10002988
House always wins
10003256
House always wins
10003321
House always wins
10003451
House always wins
10003483
House always wins
10003494
House always wins
10003494
House always wins
10003494
이성주's budget: 0.0
신수현's budget: 2.0
유한별's budget: 1.0
김경철's budget: 3.0

상속


In [45]:
class Person:
    def __init__(self, name, isFemale, nationality):
        self.name = name
        self.isFemale = isFemale
        self.nationality = nationality
    
    def say_name(self):
        print(u'이름: {}'.format(self.name))

In [95]:
class Player(Person):
    def __init__(self, name, isFemale, nationality, capital):
        Person.__init__(self, name, isFemale, nationality)

player = Player(u'이성주', False, u'대한민국', 1000)
player.say_name()


이름: 이성주

상속받은 기능 확장


In [52]:
class Player(Person):
    def __init__(self, name, isFemale, nationality, capital):
        Person.__init__(self, name, isFemale, nationality)
        
        
    def say_name(self):
        print(u'SJ 카지노 VIP!')
        Person.say_name(self)
        
    
player = Player(u'이성주', False, u'대한민국', 1000)
player.say_name()


SJ 카지노 VIP!
이름: 이성주

도전과제

고양이과 동물은 다양한 방식의 울음소리를 낸다. 모든 고양이과 동물의 울음소리는 meow() 라는 메소드를 공통적으로 활용한다. 사자, 호랑이, 고양이의 클래스를 만들고, 다음과 같이 출력되도록 한다.

출력예시:

사자: 난 고양이과. '으르렁'

호랑이: 난 고양이과. '어흥'

고양이: 난 고양이과. '야옹'


In [104]:
class Cat:
    def __init__(self):
        self.whoami = u'고양이'
        self.sound = u'야옹'
        self.category = u'고양이과'
    
    def meow(self):
        msg = u'{}: 난 {}. {}'.format(
            self.whoami, self.category, self.sound)
        return msg
        
cat = Cat()
print(cat.meow())


고양이: 난 고양이과. 야옹

In [109]:
class Lion(Cat):
    def __init__(self):
        Cat.__init__(self)
        self.whoami = u'사자'
        self.sound = u'으르렁'
        
    def meow(self, multiple):
        msg = Cat.meow(self)
        return msg * multiple
        
lion = Lion()
print(lion.meow(2))


사자: 난 고양이과. 으르렁사자: 난 고양이과. 으르렁

In [110]:
isinstance(cat, Cat)


Out[110]:
True

In [111]:
isinstance(lion, Lion)


Out[111]:
True

In [116]:
type(lion)


Out[116]:
instance

In [112]:
isinstance(lion, Cat)


Out[112]:
True

In [113]:
isinstance(cat, Lion)


Out[113]:
False

다형성과 Duck Type


In [1]:
class Dog:
    def eat(self):
        print('낼름낼름')

class Cat:
    def eat(self):
        print('홀짝홀짝')

class Person:
    def eat(self):
        print('얌얌')

In [2]:
def dine(animal):
    animal.eat()

In [3]:
dog = Dog()
cat = Cat()
me = Person()

dine(dog)
dine(cat)
dine(me)


낼름낼름
홀짝홀짝
얌얌

질문: 자료형을 지정하지 않는데 부적절한 형태의 입력이 들어오면 문제가 되지 않나요?

SJ: 네, 문제가 생깁니다.


In [4]:
class Alien:
    def inhale(self):
        print('우리는 정기를 빨아들인다.')

In [5]:
alien = Alien()
dine(alien) # Attribute 오류 발생!


---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-5-785769037d45> in <module>()
      1 alien = Alien()
----> 2 dine(alien)

<ipython-input-2-ee08785b1d1c> in dine(animal)
      1 def dine(animal):
----> 2     animal.eat()

AttributeError: Alien instance has no attribute 'eat'

Duck Typing

"오리처럼 걷고, 오리처럼 울면 오리"

질문: 그럼 자료형을 지정하지 않는 파이썬 같은 프로그래밍 언어는 안전하지 않은가요?

SJ: 자료형을 지정하는 언어와 입력을 확인하는 방법이 다를 뿐이다. 자료형을 확인하는 것은 수단일 뿐 목적이 아님. 자료형을 확인 대신 예외처리를 적용.


In [6]:
def dine(animal):
    try:
        animal.eat()
    except AttributeError as ex:
        print('먹는게 뭔가요?')

In [7]:
alien = Alien()
dine(alien)


먹는게 뭔가요?

상속


In [1]:
a_list = [1,2,3]

In [2]:
isinstance(a_list, list)


Out[2]:
True

In [3]:
isinstance(a_list, dict)


Out[3]:
False

도전과제

리스트, 문자열과 같은 시퀀스를 인자로 받아 무작위로 섞어서 반환하는 함수 shuffle_up를 정의하시오. 함수 내에서 random 모듈을 사용하시오.

예:

shuffled = shuffle_up([1,2,3])
print(shuffled) # [3,1,2]
shuffled = shuffle_up(u'파이썬')
print(shuffled) # 썬파이

In [119]:
text = u'파이썬'
print(text[0])
text[0] = u'아'


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-119-251bcbda32c1> in <module>()
      1 text = u'파이썬'
      2 print(text[0])
----> 3 text[0] = u'아'

TypeError: 'unicode' object does not support item assignment

In [123]:
from random import shuffle
import string
text = 'abc'
text = list(text)
shuffle(text)
print(string.join(text, ''))


bca

In [3]:
from shuffle_up import shuffle_up

result = shuffle_up([1,2,3,4,5,6,7,8])
print(result)


[5, 7, 2, 1, 6, 4, 3, 8]

In [ ]: