new_car = Car("KIA", 50_000_000)
old_car = Car("BMW", 30_000_000)
print(f"My old car was {old_car.get_brand()} and the price was {old_car.get_price():,} won.")
print(f"My new car was {new_car.get_brand()} and the price was {new_car.get_price():,} won.")
> 인스턴스 변수는 인스턴스 생성 후에도 속성 추가 가능 (해당 인스턴스에만 생성)
color라는 속성이 하나 추가된 모습color라는 속성이 있는 해당 인스턴스에만 생성되는 모습
정적 변수
> 클래스 내부에 공간이 할당되어 여러 인스턴스들이 하나의 자료를 공유 가능
> 정적 변수는 클래스에 정의
>> 사용법: 클래스이름.변수 or 인스턴스이름.변수
>> 클래스 속성은 여러 객체가 공유한다는 것을 주의
> 동일한 변수일 경우 이름 찾는 순서: 인스턴스 변수 > 클래스 변수
>> 위와 같은 예시일 경우 인스턴스 변수 count는 설정이 없으므로 클래스 변수 count값 사용
OOP(Object-Oriented Programming - 실행 순서가 아닌 단위 객체를 중심으로 프로그램을 작성.)
- 객체: 실생활에서의 모든 자료 (물건)
- 모든 객체는 속성과 행동을 가진다.
> 객체 지향 프로그래밍은 이러한 객체 개념을 프로그램으로 표현함.
예) 속성 > 변수, 행동 > 함수로 표현
클래스
> 하나의 새로운 데이터 타입을 만드는 것
> 클래스를 사용하는 목적이 변수와 함수를 묶어서 하나의 새로운 객체(타입)로 만드는 것
> 실제 세계에 존재하는 실체(instance)를 객체(object)라고 하고, 객체들의 공통점을 간추려서 개념적으로 나타낸 것
> 어떤 클래스를 만들기 위해서는 그 객체가 갖는 성질(상태, 속성,변수)과 그 객체가 하는 행동(메소드,함수)을 정의해주면 된다고 이해하기
잉어빵, 황금 붕어빵과 같은 차별화된 붕어빵을 만들기 위해 틀을 잘 정의하는 것이지요. 그러나 아무리 틀을 예쁘고 정교하게 만들었다고 해서 붕어빵이 나오는 것은 아닙니다. 실제로 먹을 수 있는 붕어빵을 만들려면 붕어빵 틀에 반죽을 넣고 붕어빵을 구워야 합니다. 이처럼 붕어빵 틀에 반죽을 넣어서 만들어진 붕어빵이 인스턴스에 해당합니다.
클래스(class)와 인스턴스(instance)의 관계
> 학교와 모범생 관계라고 생각하면 됨.
> 학교는 커리큘럼을 가지고 있는데 아무리 좋은 커리큘럼을 가지고 있다고 해도 모범생이 무조건 나오는 것은 아니다. 모범생이 나올려면 공부도 열심히 시키고 질 높은 수업, 환경을 만들어줘야 한다. 이처럼 학교라는 어떠한 틀에서 좋은 수업 환경을 받은 모범생이 인스턴스에 해당함.
> 각각의 인스턴스에는 별도의 공간(메모리)이 존재하며, 각각에 별도의 값 할당이 가능함.
> 정리
class Car:
color = ""
speed = 0
def up_speed(self, value):
self.speed += value
def down_speed(self, value):
self.speed -= value
my_car = Car()
her_car = Car()
his_car = Car()
my_car.color = "Red" ; her_car.color = "Black" ; his_car.color = "Blue"
my_car.up_speed(100) ; her_car.up_speed(50) ; his_car.up_speed(80)
my_car.down_speed(10) ; her_car.down_speed(5) ; his_car.down_speed(20)
print(f"my_car is {my_car.color} and current speed is {my_car.speed}km/h")
print(f"my_car is {her_car.color} and current speed is {her_car.speed}km/h")
print(f"my_car is {his_car.color} and current speed is {his_car.speed}km/h")
생성된 객체는 각각의 속성을 유지하고 있음.
클래스 생성 단계 및 사용
1단계 클래스 정의
class 클래스_이름:
// 멤버변수 선언
// 메소드 선언
# 예시
class Car:
def __init__ (self, c):
self.color = c
def up_speed(self,value):
....
>> 바인딩: 자료형, 변수명, 변수값에 각각 int, num, 10 이라는 구체적인 값을 할당하는 각각의 과정
# 출처: 파이썬으로 배우는 알고리즘 트레이딩
파이썬에서는 클래스가 정의되면 그림 6.11과 같이 하나의 독립적인 네임스페이스가 생성됩니다.
그리고 클래스 내에 정의된 변수나 메서드는 해당 네임스페이스 안에 파이썬 딕셔너리 타입으로 저장됩니다.
Stock 클래스는 그림 6.11과 같이 Stock이라는 네임스페이스 안에
'market':'kospi'라는 값을 가진 딕셔너리를 포함합니다.

**그림 6.11 파이썬 클래스 네임스페이스**
Stock 클래스의 네임스페이스를 파이썬 코드로 확인하려면 클래스의 `__dict__` 속성을 확인하면 됩니다.
딕셔너리 타입에 'market':'kospi'라는 키와 값 쌍이 존재하는 것을 확인할 수 있습니다.
```{.py}
Stock.__dict__
mappingproxy({
'market': 'kospi',
'__module__': '__main__',
'__dict__': <attribute '__dict__' of 'Stock' objects>,
'__doc__': None,
'__weakref__': <attribute '__weakref__' of 'Stock' objects>})
> 클래스가 독립적인 네임스페이스를 가지고 클래스 내의 변수나 메서드를 네임스페이스에 저장하고 있으므로 다음과 같이 클래스 내의 변수에 접근이 가능한 것.
> 정리
1번 코드는 speed라는 클래스 변수가 정의되고
반면에 인스턴스 변수 speed가 정의가 없다면 인스턴스 변수 sepeed는 클래스 변수 speed의 초기값을 공유
그런데 그 이후 클래스 변수 speed는 인스턴스 변수 speed가 변경되어도 클래스 변수의 값은 변경되지 않고
그냥 자기 갈 길 간다고 생각하면 된다.
2번 코드는 1번 코드와 동일한 형식이지만 클래스 변수와 인스턴스 변수가 동일한 이름이라도
n = 21
for(i in 1:100){
cat("collatz : NOW =", n, "\n")
if (n %% 2 == 0){
n = n / 2
} else {
n = n*3 + 1
}
if(n == 1){
cat("collatz : END =", n, "\n")
break
}
}
사용자 정의 함수
function(<para1>, <para2>, ....){<expression>}
para1, 2 는 매개변수,
expression은 매개변수를 활용한 함수식
예시1
Ex0 = function(x) {7*x+5}
Ex0(3)
Ex1 = function(x){
y = 7*x + 5
# 별도로 객체를 정의하여 값을 저장하면
# 함수를 실행시키더라도 함수값을 출력해주지 않음.
}
Ex1(4)
y
# 함수 안에서 만들어진 변수는 함수가 종료되면 없어짐.
예시2
Ex2 = function(x){
x^2 + 3*x - 6
}
Ex2(10)
반환하고 싶을 때는 return(<object>)를 사용하여야 함.
Ex1 = function(x){
y = 7*x + 5
return(y)
}
Ex1(4)
return을 쓰면 함수를 호출했을 때
함수 내에서 저장한 변수를 return(y)로 반환해줄 수 있음.
return 예시 1
Ex3 = function(x){
a = x^2 + 3*x - 6
b = 2*x^2 - exp(2)
return(a+b)
}
Ex3(10)
Ex5(3, -3:10) 코드는 순서대로 매개변수의 속성에 맞게 넣었기 때문에 오류가 없이 출력이 된다.
그러나 Ex5(vec = -3:10) 은 현재 threshold의 값을 따로 설정해주지 않았기 때문에 매개변수의 순서에 맞게 넣는게 아니다.
따라서 -3:10이 어떤 매개변수에 해당하는지 적어줘야한다.
다수의 매개변수, 기본값 예시
Ex6 = function(n, mu, sig, value = 0){
set.seed(100)
tmp = rnorm(n, mu, sig)
if(min(tmp) > value){
result = max(tmp) - min(tmp)
} else {
result = value - min(tmp)
}
return(result)
}
Ex6(4, 6, 3)
Ex6(4, 6, 3, 6)
연습하기
최솟값 찾기
# Find minimum by function ----
my.min = function(x){
mini = x[1]
for (i in 1:length(x)){
if (mini > x[i]){
mini = x[i]
} else {
mini = mini
}
}
return(mini)
}
set.seed(100)
x = runif(100, 0, 30)
my.min(x)
코드 설명
1. 첫 번째 값을 초기값으로 지정
2. 다음 값과 비교 후 더 작으면 그대로 유지
3. 만약 다음 값이 더 작을 경우 그 값으로 대체
4. 반복문을 이용하여 가장 작은 값 찾기
unif >>> 균등분포
팩토리얼
# Find Factorial
my.fac = function(n) {
if (n == 0) {
n = 1
} else{
n = n * my.fac(n - 1)
}
return(n)
}
my.fac(8) == factorial(8)
사용자 정의 함수는 함수 안에서 사용자 정의 함수를 사용할 수 있다.
ex)
ft1 = function(x){n = n*ft1(n-1)}
파이썬의 재귀함수를 생각하면 쉽게 이해할 수 있다.
연습문제
Q1 > f(x,y) = x^2 + y^2
Q2 > x값이 주어졌을 때 x값이 양수이면 x를 출력하고 양수가 아니면 x의 절댓값을 출력하는 함수
Q3 > n값이 주어졌을 때 N(5,2)에서 n개의 값을 뽑은 벡터의 최솟값과 최댓값의 합을 산출하는 함수
입력의 첫 줄에는 테스트 케이스의 개수 T(1 ≤ T ≤ 10)가 주어진다. 각 테스트 케이스는 한 줄에 하나의 문자열이 주어진다. 문자열은 알파벳 A~Z 대문자로 이루어지며 알파벳 사이에 공백은 없으며 문자열의 길이는 1000보다 작다.
출력
각 테스트 케이스에 대해서 주어진 문자열의 첫 글자와 마지막 글자를 연속하여 출력한다.
T_num = int(input())
for i in range(T_num):
munja = input()
print(f"{munja[0]}{munja[-1]}") # -1은 가장 끝 첫번째를 나타냄.
11654
print(ord(input()))
11720
문제
N개의 숫자가 공백 없이 쓰여있다. 이 숫자를 모두 합해서 출력하는 프로그램을 작성하시오.
입력
첫째 줄에 숫자의 개수 N (1 ≤ N ≤ 100)이 주어진다. 둘째 줄에 숫자 N개가 공백없이 주어진다.
출력
입력으로 주어진 숫자 N개의 합을 출력한다.
n1 = input()
n2 = input()
hap = 0
for i in range(int(n1)):
hap = hap + int(n2[i])
print(hap)
이 문제 처음 봤을 때는 input으로 받아와서 (input으로 받으면 문자열 처리된다.) split 해서 하나하나씩 더해주면 되겠다고 생각했는데 띄어쓰기와 같은 구분자가 없어서 당황했다. 그런데 그냥 문자열을 인덱싱해서 하나하나씩 int 처리해주면 전체 합을 구할 수 있겠다고 생각했었고 실제로 돌려보니 정답이었다.
# for 문 (for loop/statement) 형식
for (<var> in <interval>) { <repeated_work> }
# 설정한 변수 <var>가 지정된 구간 <interval>에서 변하면서
# 문장 <repeated_work>을 반복실행
# 반복문; for loop ----
for (i in 1:3) {
print(i)
}
for (i in c("a", "b", "c")){
print(i)
}
for(i in 5:3){
print(i)
}
# 반복문 : 1~1000합 구하기 ----
sss = 0
for(i in 1:100){
sss = sss + i
}
## exercise ----
x = 3
for(i in 1:5){
x = x*2
}
sss = 0
for(i in 100:200){
sss = sss + i
}
kk = 1
for(i in 1:10){
kk = kk*i
}
kk == factorial(10)
# 반복문: 정규분포 ----
vec = rnorm(100,7,3)
sum1 = 0
for(i in 1:length(vec)){
sum1 = sum1 + vec[i]
}
m = sum1/length(vec)
## exercise ----
vec2 = rnorm(100, 5, 2)
sum2 = 0
for(i in 1:length(vec2)){
sum2 = sum2 + vec2[i]
}
m2 = sum2/length(vec2)
sum3 = 0
for(i in 1:length(vec2)){
sum3 = sum3 + vec2[i]^2
}
var1 = (sum3 - length(vec2)*m2^2)/(length(vec2)-1)
var1
R에서의 반복문은 파이썬에서의 반복문과 조금 다를 뿐 원리는 비슷함.
WHILE문
# while문(while loop/statement)
while(<condition>) { <repeated_work> }
# 반복할 조건 <condition>의 참 거짓을 판별하여
# 참인 경우 문장 <repeated_work>을 반복 실행
# 주어진 조건을 만족하는 동안 무한 반복하기 때문에 예상과 달리 루프에 갇히게 되면 break해야함.
# 반복문: while문 ----
x = 3
while(x<1000){
x = x*2
}
print(x)
# 결과가 다르다는 걸 느끼기
# 1
i = 0
sss = 0
while(i <= 100){
i = i + 1
sss = sss + i
}
sss # 5151
# 2
i = 0; sss = 0
while(i <= 99){
i = i + 1
sss = sss + i
}
sss # 5050
# 3
i = 0; sss = 0
while(i <= 100){
sss = sss + i
i = i + 1
}
sss # 5050
# 100~200합 구하기
i = 100
sss = 0
while(i <= 200){
sss = sss + i
i = i + 1
}
sss
# 1부터 10까지의 곱과 factorial 비교
i = 1
sss = 1
while(i <= 10){
sss = sss*i
i = i + 1
}
sss == factorial(10)
# example
# 처음으로 합이 100을 넘기는 n값 찾기
n = 0 ; n.sum = 0
while(n.sum <= 100){
n = n + 1
n.sum = n.sum + n
}
## practice ----
n = 0
while(n.sum <= 100000){
n = n + 1
n.sum = n.sum + n
}
n = 0
n.fac = 1
while(n.fac <= 1000000){
n = n + 1
n.fac = n.fac * n
}
repeat문
# repeat문
repeat{<repeated_work>}
# 작업 <repeated_work>을 무한 반복하다가 break 조건을 만족하면 stop
# 반복문: repeat ----
n = 0
sss = 0
repeat{
n = n + 1
sss = sss + n
if (n >= 100) break
}
# 이산확률분포 - random number 활용
x = 0:n
y = dbinom(x, n, p)
plot(x,y,
type = "h", xlim = c(0,n), lwd = 3, col = "tomato")
# 추출하는 난수의 개수 조정
n = 25
p = 0.2
random.x10 = rbinom(10, n, p)
plot(table(random.x10), xlim = c(0,n),
lwd = 3, col = "red")
mean(random.x10) ; var(random.x10)
random.x100 = rbinom(100, n, p)
plot(table(random.x100), xlim = c(0,n),
lwd = 3, col = "red")
mean(random.x100) ; var(random.x100)
random.x1000 = rbinom(1000, n, p)
plot(table(random.x1000), xlim = c(0,n),
lwd = 3, col = "red")
mean(random.x1000) ; var(random.x1000)
result = data.frame(n = c(10, 100, 1000),
mean = c(NA),
var = c(NA))
result[1,2:3] = c(mean(random.x10), var(random.x10))
result[2,2:3] = c(mean(random.x100), var(random.x100))
result[3,2:3] = c(mean(random.x1000), var(random.x1000))
result
추출하는 개수가 높아질수록 이론적인 평균값에 가까워진다는 것을 확인할 수 있음.
연속확률분포
## 연속확률분포 ----
### 정규분포 ----
rnorm(10, mean = 0, sd = 1)
random.x = rnorm(100)
mean(random.x) ; var(random.x)
# random number로 hist/curve 그리기
?hist
hist(random.x, probability = T, main = "Normal(0,1)")
# random number로 hist/curve 그리기
hist(random.x, probability = T, main = "Normal(0,1)")
# probability = T에 대한 의미 ----
# probability = T >> 상대도수
# probability = F >> 빈도수
curve(dnorm(x), add = T, col ="tomato", lwd = 3)
t-분포
### t-분포 ----
set.seed(123)
random.x = rt(100, 2.5)
hist(random.x, probability = T, main = "t-dist")
result = data.frame(
n = c(30, 50, 100, 2000),
mean = c(NA),
variance = c(NA)
)
x30 = rt(result[1,1], 2.5)
x50 = rt(result[2,1], 2.5)
x100 = rt(result[3,1], 2.5)
x2000 = rt(result[4,1], 2.5)
result
set.seed(123)
result[1,2:3] = c(mean(x30), var(x30))
result[2,2:3] = c(mean(x50), var(x50))
result[3,2:3] = c(mean(x100), var(x100))
result[4,2:3] = c(mean(x2000), var(x2000))
result = rbind(c(NA, 0, 2.5/(2.5-2)), result)
result