Heap, Stack, Static

힙(heap)은 malloc(크기), new, 생성자 호출로 메모리를 할당받는다.

주소로 접근해야 하기 때문문에 변수가 필요하고 리스트나 객체가 저장되는 메모리이다.

스택(stack)은 함수나 메소드 호출되면 할당받는 메모리이다. 변수선언으로 할당받기 때문에 변수명이 필요하고 

한번 호출되고 나면 사라지는 성질이 있다(유효시간이 가장 짧음).

static은 클래스변수를 저장한다. 프래그램이 시작해서부터 종료할때까지 존재한다.

RAM
static
heap
stack

이런 순으로 RAM에 위치하고 있다.

 

class Test:
    x=0   #클래스 변수. 정적 멤버 변수. 정적 메모리(static)에 저장.
            #이 클래스로 만든 모든 객체가 공용으로 사용
    def __init__(self):
        self.y = 0     #일반멤버변수. 앞에 self.를 꼭 붙인다. 이 멤버변수는 self객체 소속

    def printXY(self):
        print('x:',Test.x)
        print('y:',self.y)

def main():
    print(Test.x)   #객체를 생성하지 않아도 사용가능
    #print(t1.y)    #일반멤버변수는 객체 사용 전에 사용 불가


    t1= Test()
    Test.x+=1
    t1.y+=1
    t1.printXY()

    t2= Test()
    Test.x+=1
    t2.y+=1
    t2.printXY()

    t3= Test()
    Test.x+=1
    t3.y+=1
    t3.printXY()

main()

 

파이썬에서는 객체를 통하지 않고 사용할 수 있는 변수를 생성하는 것이 가능하다.

이들 변수는 모든 객체를 통틀어서 하나만 생성되고 모든 객체가 이것을 공유하게 되는데 이러한 변수를 정적 멤버변수

또는 클래스 멤버(class member)라고 한다. 

간단하게는 변수 앞에 self.가 없다면 정적변수라고 할 수 있다.

 

출력에서 보다시피 정적변수들은 모든 객체에서 공유하기 때문에 정적변수 x의 값이 점점 누적되어 하나씩 증가한다.

y는 동적변수이기 때문에 처음 초기화 해준 값인 0으로 되돌아간다.

 

 

class Test:
    cnt = 0     #객체들이 공유해야 하는 값
    def __init__(self):
        Test.cnt += 1
        print(Test.cnt,'번째 객체 생성')



def main():
    for i in range(0, 5):
        Test()

main()

 

위 예제에서 볼수 있듯 cnt가 정적변수이기 때문에 계속 누적이 되어 print 되는 것을 알수있다.

 

 

 

 

정적메소드

정적메소드는 인스턴스를 생성하고 호출하는 방식이 아니라서 클래스에서 바로 호출이 가능하다.

클래스안의 메소드이지만 self가 없지만 클래스 소속이기 때문에 클래스 이름으로 사용가능!

 

 

엥 여기서 잠깐!

객체 = 클래스 + 인스턴스

인스턴스(객체 지향 프로그래밍(OOP)에서 해당 클래스의 구조로 컴퓨터 저장공간에서 할당된 실체를 의미)

메소드 : 클래스 내부에서 정의된 함수 (객체의 함수)

 

class Test:
    x = 0   #클래스 변수. 정적 멤버 변수

    def __init__(self):
        self.y = 0

    def method1(self):   #일반메소드. 클래스변수, 멤버변수 모두 사용가능
        print('method1: 멤버메소드')
        print('x:',Test.x)
        print('y:',self.y)

    def method2():   #정적메소드. 객체 생성전에 사용가능하므로 일반멤버변수 사용 불가.
        print('method2: 정적메소드')
        print('x:',Test.x)
        name = 'aaa'
        print(name)
        #print('y:',self.y)

    def method3(self):   #일반메소드는 일반 메서드 호출도 가능. 정적메소드 호출도 가능.
        print('method3: 멤버메소드')
        self.method1()   #일반 메소드호출
        Test.method2()   #정적 메소드호출

    def method4():   #정적메소드. 객체 생성전이므로 일반 메소드 호출 불가
        print('method4: 정적메소드')
        #self.method1()
        Test.method2()

def main():
    Test.method2()
    Test.method4()

    t1=Test()
    t1.method1()
    t1.method3()

main()

 

정적 메서드는 self를 받지 않으므로 인스턴스 속성에는 접근할 수 없다. 그래서 보통 정적 메소드는 인스턴스 속성, 인스턴스 메소드가 필요 없을 때 사용한다.

그럼 무엇을 정적 메서드로 만들어야 할까? 정적 메소드는 메소드의 실행이 외부 상태에 영향을 끼치지 않는 순수 함수(pure function)를 만들 때 사용한다.

순수 함수는 부수 효과(side effect)가 없고 입력 값이 같으면 언제나 같은 출력 값을 반환한다(약간..상수함수 느낌?)

즉, 정적 메소드는 인스턴스의 상태를 변화시키지 않는 메소드를 만들 때 사용합니다.

 

import math


class Math:
    #파이썬에서 상수 정의 방법

    __pi = 3.14   #변수앞에 __붙이면 private멤버변수(클래스 밖에서 안보임)
    PI = __pi

    def circle(r):
        return r*r*Math.PI

    def rect(w, h):
        return w*h

def main():
    print('pi:', Math.PI)
    w = Math.circle(5)
    print('원의 넓이:',w)

    w = Math.rect(5, 10)
    print('사각형의 넓이:', w)

main()

정적메소드는 이렇게 수학적인 연산이나 계산쪽에서 활용도가 높을 것 같다.

+ Recent posts