클래스 속성 사용하기

class Person:
    backpack = []

    def put_backpack(self, item):
        self.backpack.append(item)

james = Person()
james.put_backpack('노트북')

maria = Person()
maria.put_backpack('파이썬')

print(james.backpack) # james는 Person 클래스 이기에 출력가능
print(maria.backpack) # maria는 Person 클래스 이기에 출력가능

 

> Person 클래스에 바로 backpack 속성을 넣고 put_backpack 메서드를 만든다.

> 그리고 인스턴스 2개를 만들고 각각 put_backpack 메서드 사용 

> 클래스 속성은 클래스에 속해 있어서 모든 인스턴스에서 공유함. 

위의 코드를 출력하면 이렇게 나옴.

 

 

그런데 앞의 코드는 한 가지 아쉬운 점이 있다. 

put_backpack 메서드에서 클래스 속성 backpack에 접근할 때 self를 사용했는데

self는 현재 인스턴스를 뜻하므로 클래스 속성을 지칭하기에는 모호하다. 

따라서 클래스 속성에 접근할 때는 다음과 같이 클래스 이름으로 직접 접근하면 코드가 더 명확해진다. 

class Person:
    backpack = []

    def put_backpack(self, item):
        Person.backpack.append(item)

james = Person()
james.put_backpack('노트북')

maria = Person()
maria.put_backpack('파이썬')

print(james.backpack)
print(maria.backpack)

 

위와 같이 코드를 입력하니 클래스 Person에 속한 backpack 속성이라는 것을 바로 알 수 있다.

마찬가지로 클래스 바깥에서도 다음과 같이 클래스 이름으로 클래스 속성에 접근하면 된다.

print(Person.backpack)

 

파이썬에서는 속성, 메서드 이름을 찾을 때 인스턴스, 클래스 순으로 찾는다.

그래서 인스턴스 속성이 없으면 클래스 속성을 찾게 되므로 james.backpack, maria.backpack도 문제없이 동작한다.

겉보기에는 인스턴스 속성을 사용하는 것 같지만 실제로는 클래스 속성이라는 것이다. 

 

인스턴스와 클래스에서 __dict__ 속성을 출력해보면 현재 인스턴스와 클래스의 속성을 딕셔너리로 확인할 수 있다. 

 

 

 

 

여기서 중요한 것!

backpack을 그럼 여러 사람이 공유하지 않도록 하기 위해서는 어떻게 해야하나?

그냥 backpack을 인스턴스 속성으로 만들면 된다.

어떻게 만드냐 앞에 있는 Person 클래스 코드에 __init__를 추가하여 초기화가 되도록 만들어주면 된다.

class Person:                      # 클래스이름
    def __init__(self):            # constructor
        self.backpack = []
 
    def put_backpack(self, item):  # instance method
        self.backpack.append(item)

        
james = Person()                   # object instanciation
james.put_backpack('노트북')
 
maria = Person()                   # object instanciation
maria.put_backpack('파이썬')
 
print(james.backpack)              # 명확한 instance 변수 호출
print(maria.backpack)              # 명확한 instance 변수 호출

 

 

> 여기서 확인해보면 각각 넣은 물건만 출력된다는 것을 알 수 있다. 

> 즉, 인스턴스 속성은 인스턴스별로 독립되어 있으며 서로 영향을 주지 않는다.

 

 

정리

> 클래스 속성: 모든 인스턴스가 공유. 인스턴스 전체가 사용해야 하는 값을 저장할 때 사용

> 인스턴스 속성: 인스턴스 별로 독립되어 있음. 각 인스턴스가 값을 따로 저장해야할 때 사용

 

 

 

비공개 클래스 속성

> 클래스 속성을 만들 때 _속성과 같이 __(밑줄 2개)로 시작하면 비공개 속성이 된다.

> 클래스 안에서만 접근할 수 있고, 클래스 바깥에서는 접근할 수 없다.

class 클래스이름:
	__ 속성 = 값  # 비공개 클래스 속성

 

class Boxing:
    __item_limit = 10 # 비공개 클래스 속성

    def print_item_limit(self):
        print(Boxing.__item_limit)

peter = Boxing()
peter.print_item_limit()

print(Boxing.__item_limit) # 클래스 바깥에서는 접근할 수 없음.

 

클래스 바깥에서 print를 하려고 하니 에러가 뜬 것을 확인할 수 있다.

 

 

정적메서드 사용하기

> 인스턴스를 통하지 않고 클래스에 바로 호출 가능 

> 정적 메서드는 다음과 같이 메서드 위에 @staticmethod를 붙인다.

> 말 그대로 정적메서드이며 이때 정적메서드는 매개변수에 self를 지정하지 않는다.

class 클래스이름:
	@staticmethod
    def 메서드(매개변수1, 매개변수2):
    	코드

 

> @staticmethod처럼 앞에 @가 붙은 것을 데코레이터(장식자)라고 하며 메서드(함수)에 추가 기능을 구현할 때 사용

class Calculator:

    @staticmethod
    def add(x, y):
        print(x + y)

    @staticmethod
    def mul(x, y):
        print(x * y)

Calculator.add(10, 20)
Calculator.mul(10, 20)

 

> 정적 매서드는 self를 받지 않으므로 인스턴스 속성에는 접근할 수 없음.

> 그래서 정적 메서드는 인스턴스 속성, 인스턴스 메서드가 필요없을 때 사용함.

> 정적 메서는 메서드의 실행이 외부 상태에 영향을 끼치지 않는 순수 함수(pure function)를 만들 때 사용함.

> 순수 함수는 부수 효과(side effect)가 없고 입력값이 같으면 언제나 같은 출력값을 반환함.

> 즉, 정적 메서드는 인스턴스의 상태를 변화시키지 않는 메서드를 사용할 때 사용함. 

 

 

 

 

클래스메서드 사용하기

> 클래스 메서드는 다음과 같이 메서드 위에 @classmethod를 붙임.

> 이때 클래스 메서드는 첫 번째 매개변수에 cls를 지정해야 한다.

class 클래스이름:
	@classmethod
    def 메서드(cls, 매개변수1, 매개변수2):
    	코드

 

class Car:
    count = 0

    def __init__(self):
        Car.count += 1

    @classmethod
    def print_count(cls):
        print(f"{cls.count}대가 생성되었습니다.") # cls로 클래스 속성에 접근

x = Car()
y = Car()
z = Car()

Car.print_count()

 

> 먼저 인스턴스가 만들어질 때마다 숫자를 세야하기에 __init__메서드에서 클래스 속성 count에 1을 더해줌.

> @classmethod를 붙여서 클래스 메서드를 만든다.

> 클래스 메서드는 첫 번째 매개변수가 cls인데 여기에는 현재 클래스가 들어온다.

> 따라서 cls.count처럼 cls로 클래스 속성 count에 접근할 수 있다.  (정적 메서드와의 차이점)

> 클래스 메서드는 정적 메서드처럼 인스턴스 없이 호출할 수 있다는 점은 같다.

> 그러나 클래스 메서드는 메서드 안에서 클래스 속성, 클래스 메서드에 접근해야할 때 사용.

 

class Car:
    count = 0

    def __init__(self):
        Car.count += 1

    @classmethod
    def print_count(cls):
        print(f"{cls.count}대가 생성되었습니다.")

    @classmethod
    def create(cls):
        instance = cls()
        return instance

x = Car()
y = Car()
z = Car() # x, y, z 객체 생성으로 count 증가 (Car.count += 1)
w = x.create() # w 객체에서 classmethod 호출로 count 증가 (Car.count += 1)
o = Car.create() # Car클래스에서 직접 classmethod 호출로 count 증가 (Car.count += 1)

Car.print_count()

 

'프로그래밍 > Python' 카테고리의 다른 글

제너레이터(Generator)  (0) 2024.08.12
Python - Closure 함수  (0) 2023.12.15
Python - 인스턴스 변수 vs 정적변수  (0) 2023.11.25
Python - 클래스 생성자  (2) 2023.11.25
Python - 클래스  (1) 2023.11.25

+ Recent posts