컴퓨터 사이언스 (CS)/자료구조 및 알고리즘

04. 인스턴스 변수와 메소드

한소희DE 2021. 6. 2. 08:59

 

 

목차 

인스턴스 변수

인스턴스 메소드

여러 인스턴스가 공유하는 속성

 


 

 

01. 인스턴스변수

인스턴스의 개별적 속성은 인스턴스 변수라고 한다. 형식은 아래와 같다.

 

인스턴스이름.속성이름(인스턴스 변수) = 속성에 넣을 값

 

class User: 
	pass 

user = User() 
user.name = '한소희' 
user.email = 'eng.sohee@gmail.com' 

# 인스턴스 변수 사용방법 
print(user.name)

 


 

02. 인스턴스 메소드

객체는 속성과 행동이다. 속성은 변수로 나타내고 행동은 함수로 나타낸다. 이 함수를 메소드라고 한다.

 

메소드의 다양한 종류 중, 첫 번째로 인스턴스 메소드에 대해 설명해보겠다.

 

인스턴스 메소드란, 인스턴스 변수를 사용하거나, 인스턴스 변수에 값을 설정하는 메소드를 말한다.


 

class User: 
	# 인사 메시지 출력 메소드 
    def say_hello(some_user): 
    print('안녕! 나는 {}야'.format(some_user.name)) 
    
user1 = User() 
user1.name = "한소희" 
user1.email = "eng.sohee@gmail.com" 


# 인스턴스 메소드 사용방법. 2가지 방법이 존재 
User.say_hello(user1) 
user1.say_hello()

 

우리는 함수에서 username을 호출하도록 했는데, user1에는 username이라는 속성이 없는데도 에러가 안났다. 그것은 인스턴스 메소드의 특징 때문이다.

user1.say_hello() 에서는, user1의 첫 번째 속성을 넘겨주기 때문이다.

 

그럼 새로운 메소드를 생성해보자.

 

class User: 
	# 인사 메시지 출력 메소드 
    def say_hello(some_user): 
    print('안녕! 나는 {}야'.format(some_user.name)) 
    
    def login(some_user, my_email, my_password): 
    if (some_user.eamil == my_email and some_user.password == my_password): 
    print("로그인 성공") 
    
    else: print("로그인 실패") 
    
user1 = User() 
user1.name = "한소희" 
user1.email = "eng.sohee@gmail.com" 
user1.password = "12" 

# 인스턴스 메소드 사용방법 
user1.login("eng.sohee@gmail.com","12")

 

2-1. 인스턴스 메소드의 특별한 규칙

user1.login("eng.sohee@gmail.com","12")에서, user1 자신이 첫 번째 파라미터로서 자동전달된다.

우리는 이 것을 self 로 쓰기로 약속한다. 따라서 self 라고 작성해주자.

 

수정된 코드 결과는 다음과 같다. self는 객체의 인스턴스 그 자체를 말한다.

즉, self란 객체 자기 자신을 참조하는 매개변수인 셈이다.

 

객체지향 언어는 모두 이걸 메소드에 안보이게 전달하지만, 파이썬은 클래스의 메소드를 정의할 때 self를 명시한다.

 

class User: 
	# 인사 메시지 출력 메소드 
    def say_hello(self): 
    print('안녕! 나는 {}야'.format(self.name)) 
    
    
    def login(self, my_email, my_password): 
    if (self.eamil == my_email and self.password == my_password): 
    print("로그인 성공") 

	else: 
    print("로그인 실패") 
    
 
 user1 = User() 
 user1.name = "한소희" 
 user1.email = "eng.sohee@gmail.com" 
 user1.password = "12" 
 
 # 인스턴스 메소드 사용방법 
 user1.login("eng.sohee@gmail.com","12")

 

 

이때 인스턴스 변수와 같은 이름을 갖는 파라미터가 존재하더라도, 혼동이 되지 않는다.

예시는 아래와 같다.

class User: 
	def check_name(self, name): 
    return self.name == name 
    
user1 = User() 
user1.name = "한소희" 
user1.email = "eng.sohee@gmail.com" 
user1.password = "12" 

# 인스턴스 메소드 사용방법. 결과값: True 
user1.check_name("한소희")

 

 

 

2-2. initialize 메소드

그런데 만약에, user1 뿐만 아니라 객체가 여러개 존재한다면, 저렇게 일일이 객체 지정을 해 주어야 하는 것일까? 그렇지 않다. 우리는 class 안에, 각 속성의 규칙을 정해줄 수 있다. 아래의 예시를 살펴보자.

 

class User: 
	def initialize(self, name, email, password): 
    self.name = name 
    self.email = email 
    self.password = password 

user1 = User() 
user1.initialize("한소희", "eng.sohee@gmail.com", "12")

 

이렇게 작성하면, 나중에 인스턴스가 많아져 많은 변수를 할당해야 할 때 반복적으로 작성하는 코드를 줄일 수 있다.


 

2-3. 특수(Special) 메소드 - init 메소드

 

그런데 위 initialize 메소드도 사실은 두 줄이라 조금 길다. 

우리는 이것을 한 줄로 바꿔줄 수도 있다.

이때는 init을 활용하는데, 이는 특수메소드(스페셜메소드)라고 한다. 특수메소드는 앞뒤로 언더바가 들어가 있어, 다운언더 메소드 혹은 던더 메소드라고 불리기도 한다.

 

즉 특수(스페셜)메소드란, 특정상황에서 자동으로 호출되는 메소드

 

init의 경우 인스턴스가 생성될 때 자동으로 호출된다는 특징이 있다. 따라서 아래처럼 함수를 간단하게 변경할 수 있다.

 

class User: 
	def __init__(self, name, email, password): 
    self.name = name 
    self.email = email 
    self.password = password 

user1 = User("한소희", "eng.sohee@gmail.com", "12")

 

이는 User 인스턴스가 생성된 후 init 메소드가 자동으로 호출되는 것이다. 이때 값들이 파라미터로 들어가주어 초기값이 설정되는 것이다. 그렇다면 간단한 실습을 진행해보자.

 

 

2-4. init 메소드 실습

우리는 인스타그램의 기본 기능 (팔로잉 기능)을 만들어볼 것이다. 각 이름과 email을 변수로 지정해, 서로 팔로우를 하고, 나중에는 한 객체 당 어떤 객체들이 팔로우를 했는지 출력해볼 것이다.

 

class User: 
	# 인스턴스 변수 설정 
    def __init__(self, name, email, password): 
    self.name = name 
    self.email = email 
    self.password = password 
    
    # 이 유저가 팔로우하는 유저 리스트 
    self.following_list = [] 
    
    # 이 유저를 팔로우하는 유저 리스트 
    self.followers_list = [] 
    
    # 팔로우 기능 
    def follow(self, another_user): 
    self.following_list.append(another_user) 
    another_user.followers_list.append(self) 
    
    # 내가 몇 명을 팔로우하는지 리턴 
    def num_following(self): 
    	return len(self.following_list) 
    
    # 나를 몇 명이 팔로우하는지 리턴 
    def num_followers(self): 
    	return len(self.followers_list) 

# 유저들 생성 
user1 = User("Young", "young@codeit.kr", "123456") 
user2 = User("Yoonsoo", "yoonsoo@codeit.kr", "abcdef") 
user3 = User("Taeho", "taeho@codeit.kr", "123abc") 
user4 = User("Lisa", "lisa@codeit.kr", "abc123") 

# 유저마다 서로 관심 있는 유저를 팔로우 
user1.follow(user2)
user1.follow(user3)
user2.follow(user1)
user2.follow(user3)
user2.follow(user4)
user4.follow(user1) 

# 유저 이름, 자신의 팔로워 수, 자신이 팔로우하는 사람 수를 출력 
print(user1.name, user1.num_followers(), user1.num_following()) 
print(user2.name, user2.num_followers(), user2.num_following()) 
print(user3.name, user3.num_followers(), user3.num_following()) 
print(user4.name, user4.num_followers(), user4.num_following())

 

2-5. str 메소드

인스턴스를 출력(print)할 때 마다, 우리가 원하는 변수값이 바로바로 출력되지 않는다. 이때 str 메소드는 인스턴스에 print 함수가 호출될 때 자동으로 출력시켜주는 메소드를 의미한다. 예제는 다음과 같다. (위와 중복되는 함수는 생략하겠다.)

# 아래와 같이 바로 출력할 경우, 인스턴스 변수값이 바로 출력되지는 않음 
print(user1) 

def __str__(self): 
	return "사용자 : {}, 이메일 : {}".format(self.name, self.email) 
    
# str 형식에 맞게 인스턴스 변수 출력 
print(user1)

 


 

03. 여러 인스턴스가 공유하는 속성

만약, user 인스턴스의 총 개수를 구하려고 한다면 어떻게 해야 하는가?

파이썬은 이렇게 여러 인스턴스가 공유하는 속성을 클래스 변수로 지정한다.

 

이때, init 함수가 생기면 개수가 증가해야 하므로 저렇게 함수를 적어준다. 그러면 한번씩 init함수가 수행될 때마다 count 수가 늘어날 것이다. 이것이 바로 클래스 변수(특정 클래스의 인스턴스가 공통으로 갖고 있는 변수)를 의미한다.

 

class User: 
	# 클래스 변수 설정 
    count = 0 
    
    def __init__(self, name, email, password): 
    self.name = name 
    self.email = email 
    self.password = password 
    User.count += 1 
    
 user1.count = 1 
 print(User.count) 
 
 # user1의 count만 1로 출력. 같은 이름의 클래스 변수와 인스턴스 변수 중에는, 인스턴스 변수가 조금 더 강하다. 
 print(user1.count) 
 print(user2.count)

 

이처럼 클래스 변수는 아래와 같이 출력할 수 있다.

 

클래스이름.클래스변수이름
✅ 인스턴스이름.클래스변수이름

 

그리고 인스턴스 변수가 조금 더 강한 속성 때문에, 클래스 변수를 바꿀 때는 반드시 클래스이름.클래스변수이름 = 바꾸고자하는 값으로 적어줘야 코드가 꼬일 염려를 덜 수 있으니 반드시 기억하자!