본문 바로가기

학습 노트/알고리즘 (Python)

Python #2

서론


이전 시간에 각자의 페이스에 맞겨 진행했더니
Egg > Whale > Rabbit 순서대로 진도의 차이가 났다.
큰 차이는 아니었지만 이는 각자가 제대로 된 페이스 메이커의 역할을 해 주지 못한다는 이야기로.
먼저 진행하고 있던 사람이 후위의 사람의 진행을 도와줄 수는 있으나.
이 또한 선행자의 학습 흐름을 끊은 행위기에 비효율적이라 판단했다.
따라서 문제는 한 화면을 통해 공유하여 선행고 후위의 간격을 질정 수준으로 조율하고,
너무 오래 걸리는 경우 함께 답을 확인하고 코드리뷰를 하는 방식으로 진행했다.

 

본론


이번에 진행한 부분은 이전 시간에 이은 131번 부터로,
어차피 모든 모듈을 알 수 없으니 이후 실습하면서 하나씩 알아 가는 것으로,
함수도 유지보수 및 코드의 효율화를 위해 필요하며 이후에 실습하며 익숙해 지는 것으로
가닥을 잡아 클래스를 먼저 확인하기로 정했다.

 

20220402.ipynb
0.06MB

 

이 날 275번 까지 진행했으며 특히 마지막 270번 ~ 275번은 하나의 클래스에 기능을 추가하는 방식이기 때문에
각자의 코드들을 공개하고 리뷰하는 방식으로 진행했다.

문제의 조건은 다음과 같다.

  • 데이터의 구조는 은행이름, 예금주, 계좌번호, 잔액으로 구성된다.
  • 데이터 중 예금주의 이름, 잔액 두 개의 데이터만 생성자를 통해 입력 받는다.
  • 은행 이름은 'SC은행'으로 고정한다.
  • 계좌번호는 'xxx-xx-xxxxxx'의 포맷으로 고정되며, 무작위 번호로 구성된다.
  • 'get_account_num' 메서드를 선언한다. 해당 메서드는 생성된 계좌의 수를 반환하는 클래스 변수를 출력한다.
  • 'deposit' 메서드를 선언한다. 입금 기능에 해당하며, 해당 메서드는 1원 이상의 금액을 잔액에 추가한다.
  • 'withdraw' 메서드를 선언한다. 출금 기능에 해당하며, 잔액 이상의 금액으로는 잔액에서 제할 수 없다.

대부분 기본적인 문법으로 구현되는 부분이기 때문에 우리들의 관전 포인트는 계좌번호 생성 부분이었다.

#Egg's

import random

def genAccount():
  top = 0
  middle = 0
  bottom = 0

  top = str(random.random())[4:7]
  middle = str(random.random())[4:6]
  bottom = str(random.random())[4:10]

  result = top + '-' + middle + '-' + bottom

  return result

class Account:
  counter = 0
  
  def __init__(self,customer_name,cost):
    self.bank_name = "SC_bank"
    self.customer_name = customer_name
    self.account_num = genAccount()
    self.cost = cost
    Account.counter += 1
  def get_aacount_num():
    print(Account.counter)
  def deposit(self, deposit):
    if deposit > 0:
      self.cost += deposit
    else:
      print('deposit must over 0')
  def withdraw(self, withdraw):
    if withdraw > self.cost:
      print('can\'t withdraw over current cost.')
    else:
      self.cost -= withdraw

custom_1 = Account('custom_1',1000000)
custom_2 = Account('custom_2',1000000000)

print(custom_1.bank_name,custom_1.customer_name,custom_1.account_num,custom_1.cost)
Account.get_aacount_num()
custom_1.deposit(-3)
print(custom_1.cost)
custom_1.withdraw(10000000000)
print(custom_1.cost)

 

계좌 생성을 위해 random 모듈을 import하고,
각각의 자릿수에 해당하는 값들을 생성하는 'genAccount' 함수를 하나 선언했다.

함수 파트를 건너 뛴 상태로 진행했기 때문에,
메서드의 선언이 동일하게 함수의 선언으로도 작동하는지 확인해 보기 위한 처사였다.

var1 = random.random()
var2 = random.random()

print(var1, var2)
결과

0.05710164899729009 0.8626206555991165

random 모듈의 random 메서드는 무작위의 float값을 생성한다.
계좌번호에 자릿수를 제외하면 어떠한 규칙도 존재하지 않기 때문에
해당 실수를 문자열로 타입캐스팅(Type Casting)해 슬라이싱으로 각각의 자릿수를 만들어 줬다.
이후 생성자에서 호출해 데이터 입력 시 생성되도록 했다.

#Whale's

import random
class Account :
  count=0
  def rand() :
    i=random.randrange(1,999)
    i2=random.randrange(1,99)
    i3=random.randrange(1,999)

    if (i/100)>=1 :
        r=str(i)
    elif (i/100)<1 :
      if (i/10)>=1 and (i/10)<10 :
        r="0"+str(i)
      elif (i/10)<1 :
        r="00"+str(i)

    if (i2/10)>=1 :
      r2=str(i2)
    elif (i2/10)<1 :
      r2="0"+str(i2)

    if (i3/100)>=1 :
      r3=str(i3)
    elif (i3/100)<1 :
      if (i3/10)>=1 and (i3/10)<10 :
        r3="0"+str(i3)
      elif (i3/10)<1 :
        r3="00"+str(i3)

    re=r+"-"+r2+"-"+r3

    return re;

  def __init__(self, name, money) -> None:
    self.name=name
    self.money=money
    self.bank="SC은행"
    self.number=Account.rand()
    Account.count+=1

  def get_number(self) :
    return self.count

  def deposit(self, don) :
    if don>=1 :
      self.money+=don
      print(don, "원 추가")
    else :
      print("1원 이상 넣어주세요")

  def withdraw(self, don) :
    if self.money<don :
      print("없는걸 달라하니 니놈은 강도로구나")
    elif self.money>=don and don>=0 :
      self.money-=don
      print(don,"만큼 출금되었습니다. |n 남은 금액은 ", self.money,"원 입니다." )

c=Account("이름", 0)
print(c.name, c.money, c.bank, c.number)

d=Account("test", 0)
print(d.name, d.money, d.bank, d.number)

#272
#273
c.get_number()
#274
c.deposit(500)
print(c.money)
c.deposit(0)
print(c.money)
#275
c.withdraw(700)
print(c.money)

random 모듈의 randrange 메서드를 사용해 계좌번호를 생성했다.

var1 = random.randrange(1,999)
var2 = random.randrange(1,999)

print(var1,var2)
결과

176 413

randrange 메서드는 전달된 범위 안의 무작위 정수를 반환한다.
따라서 최댓값은 예측할 수 있지만 최소값에 가까운 값이 나올 수록 요구하는 자릿수를 만족하기 어려워진다.
즉 Whale은 1부터 시작하는 무작위 값을 위해 일단은 값을 생성하고, 자릿수에 만족하지 않을 경우 0을 채우는 방식을 선택했다.

#Rabbit's

import random

def randnum():
    ran_num1 = random.randint(0,999)
    ran_num2 = random.randint(0,99)
    ran_num3 = random.randint(0,999999)
        
    num1 = str(ran_num1).zfill(3)
    num2 = str(ran_num2).zfill(2)
    num3 = str(ran_num3).zfill(6)
        
    final = num1+"-"+num2+"-"+num3
    return final

class Account:
    
    count = 0
    
    def __init__(self, name, money):
        self.bank = "SC은행"
        self.name = name
        self.code = randnum()
        self.money = money
        
        Account.count += 1
        
    def get_account_num(self):
        print("{}".format(self.count))
        
    def deposit(self, money):
        if money >= 1:
            print("{}".format(self.money + money))
        else:
            print("입금이 불가합니다.")
            
    def withdraw(self, money):
        if money > self.money:
            print("출금이 불가합니다.")
        else:
            print("{}".format(self.money-money))

a = Account("Rabbit", 10000)
b = Account("Egg", 100000)
c = Account("Whale", 500)

print("은행이름: ", a.bank)
print("계좌번호: ", a.code)
print("계좌번호: ", b.code)
print("계좌번호: ", c.code)

 

Whale과 비슷하지만 random 모듈의 randint 메서드를 사용했다.

var1 = random.randint(0,999)
var2 = random.randint(0,999)

print(var1, var2)
결과

280 305

마찬가지로 주어진 범위 내의 정수를 반환한다.
때문에 자릿수를 맞춰 줘야 하고, 이 때는 문자열 클래스의 zfill 메서드를 사용했다.
Whale과 같은 매커니즘이지만 훨씬 깔끔하다는 장점이 돋보인다.

 

결론


import UIKit

let bankList = ["SC은행"]
var accountAmount = 0

func genAccount() -> String {
	var head: String
	var thorax: String
	var abdomen: String
	var result: String
	
	head = String(format: "%03d", Int.random(in: 1...999))
	thorax = String(format: "%02d", Int.random(in: 1...99))
	abdomen = String(format: "%06d", Int.random(in: 1...999999))
	
	result = String(format: "%@-%@-%@", arguments: [head, thorax, abdomen])
	
	return result
}

class Account {
	var account: String
	var name: String
	var bank: String
	var balance: Int
	
	init(nameVal: String, balanceVal: Int) {
		bank = bankList[0]
		name = nameVal
		balance = balanceVal
		account = genAccount()
		accountAmount += 1
	}
	
	func get_account_num() -> Int {
		return accountAmount
	}
	
	func deposit(depositVal: Int) {
		if depositVal > 0 {
			balance -= depositVal
		} else {
			print("deposit val must over 0.")
		}
	}
	
	func withdraw(withdrawVal: Int) {
		if (0...balance).contains(withdrawVal) {
			balance -= withdrawVal
		} else {
			print("withdarwVal must between in 1 to 'account balance'")
		}
	}
}

var custom1 = Account(nameVal: "Custom1", balanceVal: 10000000)
var custom2 = Account(nameVal: "Custom2", balanceVal: 10000)

custom2.get_account_num()
custom1.get_account_num()

custom1.balance
custom1.deposit(depositVal: 0)
custom1.deposit(depositVal: 10000)
custom1.balance

Python으로 작성했던 코드를 Swift로 구현해 봤다.
지금과 같이 값이 저장돼 있지 않은 상태에서 생성자에서 메서드를 호출에 값을 지정할 수 없으므로
계좌 생성 함수를 클래스 밖에서 선언해 호출하는 방식으로 구현 된 모습이다.

import UIKit

let bankList = ["SC은행"]
var accountAmount = 0

class Account {
	var account: String = ""
	var name: String
	var bank: String
	var balance: Int
	
	func genAccount() -> String {
		var head: String
		var thorax: String
		var abdomen: String
		var result: String
		
		head = String(format: "%03d", Int.random(in: 1...999))
		thorax = String(format: "%02d", Int.random(in: 1...99))
		abdomen = String(format: "%06d", Int.random(in: 1...999999))
		
		result = String(format: "%@-%@-%@", arguments: [head, thorax, abdomen])
		
		return result
	}
	
	init(nameVal: String, balanceVal: Int) {
		bank = bankList[0]
		name = nameVal
		balance = balanceVal
		account = genAccount()
		accountAmount += 1
	}
	
	func get_account_num() -> Int {
		return accountAmount
	}
	
	func deposit(depositVal: Int) {
		if depositVal > 0 {
			balance -= depositVal
		} else {
			print("deposit val must over 0.")
		}
	}
	
	func withdraw(withdrawVal: Int) {
		if (0...balance).contains(withdrawVal) {
			balance -= withdrawVal
		} else {
			print("withdarwVal must between in 1 to 'account balance'")
		}
	}
}

var custom1 = Account(nameVal: "Custom1", balanceVal: 10000000)
var custom2 = Account(nameVal: "Custom2", balanceVal: 10000)

custom2.get_account_num()
custom1.get_account_num()

custom1.balance
custom1.deposit(depositVal: 0)
custom1.deposit(depositVal: 10000)
custom1.balance

만약 해당 함수를 클래스 내에 넣고 싶다면,
위와 같이 저장하려는 변수에 무엇이든 값을 입력한 상태로 진행해야 한다.

String 클래스의 포멧 지정자를 사용해 부족한 자릿수는 '0'으로 대체하고,
Int 클래스의 random 메서드를 사용해 지정된 범위의 무작위 값을 생성했다.

Class 변수를 사용해 계좌의 생성 수를 판단하는 방법은 Swift에서 사용할 수 없으므로,
별도의 변수를 사용해 구현했다.

출금시 값 검증을 위해 잔액을 최대값으로 하는 범위를 생성하고,
contains 메서드를 사용해 입력된 값이 해당 범위에 속하는지를 판단했다.

'학습 노트 > 알고리즘 (Python)' 카테고리의 다른 글

Stack #1  (0) 2022.06.04
선형 데이터 구조와 탐색  (0) 2022.05.03
Q1. 방 배정 하기  (0) 2022.04.22
Python #3  (0) 2022.04.18
Python #1  (0) 2022.03.23