class User:
user1 = User()
user2 = User()
user3 = User()
만약에 자동차를 만들고 싶다면, 자동차 설계도 클래스를 만들고 자동차에 필요한 기능과 부품들을 만들 수 있다.(ex: 휠이라는 부품은 나아갈 방향을 조종한다. 휠은 인스턴스다) 그리고 그 인스턴스들끼리 잘 조합해서 자동차가 나아가게 한다.(객체지향프로그래밍)
class Car:
wheel.Car():
engine.Car():
wheel(인스턴스명).description(속성 이름) = "direction"
engine(인스턴스명).description(속성 이름) = "power"
형식: 🎆인스턴스명.속성명 = 데이터값🎆
인스턴스.인스턴스 변수
wheel.description
📌 객체 = 속성(변수) + 행동(함수=메소드)
메소드에는 세 가지 종류가 있다.
인스턴스 메소드, 클래스 메소드, 정적 메소드다.
class Car:
def Carpart(parts):
print("당신의 부품의 기능은 {}입니다.".format(parts.description)
wheel.Car():
engine.Car():
wheel(인스턴스명).description(속성 이름) = "direction"
wheel.size = 500
engine(인스턴스명).description(속성 이름) = "power"
engine.size = 10000
Car.Carpart(wheel) #"당신의 부품의 기능은 direction 입니다."
여기서 Carparts 함수 파라미터 parts 에 wheel이나 engine이 들어갈 수 있다.
만약 Carpart(wheel)을 집어넣으면 print문에 format(wheel.description)이 들어간다.
그래서 "당신의 부품의 기능은 direction 입니다."로 출력한다.
Carpart는 description이라는 인스턴스 변수를 사용하기 때문에 인스턴스 메소드라고 할 수 있다.
클래스명.인스턴스 메소드 명(인스턴스명)
Car.Carpart(wheel)
Car.Carpart(wheel) = wheel.Carpart()
#클래스.메소드(인스턴스) = 인스턴스.메소드()
여기서 클래스.함수.인스턴스 의 결과값이랑, 인스턴스.함수()의 결과값이 같다.
원래 wheel.part()는 함수 호출할 때 파라미터에 아무것도 집어넣지 않았으니까 None 값이라 둘이 같지 않아야 한다.
여기서 특별한 규칙이란, 인스턴스.함수(), wheel.Carpart()는
wheel(인스턴스)가 Carpart(함수)에 자동으로 파라미터로 넣어진다는 것이다.
파라미터를 여러 개 넣어봐도,
class Car:
def Carpart(parts):
print("당신의 부품의 기능은 {}입니다.".format(parts.description)
def MyCar(parts,your_des, your_size):
if parts.description == "direction" and parts.size == "500":
print("correct")
else:
print("wrong")
wheel.Car():
engine.Car():
wheel.description = "direction"
wheel.size = 500
engine.description = "power"
engine.size = 10000
Car.Carpart(wheel) #"당신의 부품의 기능은 direction 입니다."
wheel.Carpart() #"당신의 부품의 기능은 direction 입니다."
wheel.Mycar(direction, 500) # correct 로 출력됨
wheel.Mycar(wheel,direction, 500) #Type Error : 인자 하나를 받아야 하는데 두 개 받았다고 나옴.
#함수 앞에 쓴 wheel도 파라미터로 자동할당됨.
이렇듯, 파라미터 여러개를 입력받을 때에도 맨 앞의 인스턴스가 자동 할당된다.
인스턴스 메소드의 첫번째 파라미터인 인스턴스에 초점이 맞춰진 주인공이 된다. 그 주인공이 항상 self란 걸 알면 편하기 때문에 "파이썬"에서는 self로 써주자는 규칙이 있다. (안지켜도 오류는 없지만)
인스턴스 메소드를 호출하는 자신, 인스턴스를 self라고 하니, 더 보기 편하다.
class Car:
def Carpart(self):
print("당신의 부품의 기능은 {}입니다.".format(self.description)
def check(self,description):
return self.description == description
wheel.Car():
engine.Car():
wheel.description = "direction"
wheel.size = 500
engine.description = "power"
engine.size = 10000
Car.Carpart(wheel) #"당신의 부품의 기능은 direction 입니다."
wheel.Carpart() #"당신의 부품의 기능은 direction 입니다."
print(wheel.check("direction")) #True
print(engine.check("direction")) #False
여기서 주목할 부분
def check(self,description):
return self.description == description
print(wheel.check("direction")) #True
print(wheel.check("power")) #False
앞의 self.description은 첫번째 파라미터.description 를 가리키고,
뒤의 description은 check(self,description)의 description이다.
여기서 user1의 특성이 무엇인지 굳이 정해주지 않아도, 메소드 initialize 로 self.name = name 식으로 쓰고 파라미터로 그 인스턴스의 변수의 값을 설정해주면 훨씬 간단해진다.
class User:
def initialize(self, name, email, password):
self.name = name
self. email = email
self. password = password
user1 = User()
user1.initialize("Young", "young@codeit.kr", "123456")
user2 = User()
user2.initialize("Yoonsoo", "yoonsoo@codeit.kr", "abcdef")
user3 = User()
User.initialize(user3, "Taeho", "taeho@codeit.kr", "123abc")
user4 = User()
User.initialize(user4, "Lisa", "lisa@codeit.kr", "abc123")
print(user1.name, user1.email, user1.password)
print(user2.name, user2.email, user2.password)
print(user3.name, user3.email, user3.password)
print(user4.name, user4.email, user4.password)
이제부터 새 인스턴스를 짤 때마다 두 줄씩만 입력하면 된다.
User를 생성하는 줄과 초깃값 설정하는 줄
user1 = User()
user1.initialize("Young", "young@codeit.kr", "123456")
여기서 한 줄로 더 줄일 수 있다.
인스턴스 메소드 initialize()를 __ init__()로 바꿔준다.
__init__() 메소드는 인스턴스가 생성될 때 자동으로 호출된다.
특정 상황에서 자동으로 호출 되는 메소드다.
class User:
def __init__(self, name, email, password):
self.name = name
self. email = email
self. password = password
user1 = User("Young", "young@codeit.kr", "123456")
user2 = User("Yoonsoo", "yoonsoo@codeit.kr", "abcdef")
User = User(user3, "Taeho", "taeho@codeit.kr", "123abc")
User = User(user4, "Lisa", "lisa@codeit.kr", "abc123")
print(user1.name, user1.email, user1.password)
print(user2.name, user2.email, user2.password)
print(user3.name, user3.email, user3.password)
print(user4.name, user4.email, user4.password)
결과는 똑같다.
그럼 이 한 줄에 무슨 일이 일어난걸까?
user1 = User("Young", "young@codeit.kr", "123456")
- User 인스턴스가 생성된다
- init 메소드가 자동 호출된다.
def __init__(self, name, email, password): self.name = name self. email = email self. password = password
user1 = User("Young", "young@codeit.kr", "123456")
여기에서 self에는 막 생성된 User의 인스턴스명(user1)이 들어간다. 그리고 괄호 안에 있는 name, email, password 값들("Young", "young@codeit.kr", "123456")이 순서대로 init의 name, email, password에 들어간다.
~~~python
self.name = "Young"
self.email = "young@codeit.kr"
self.password = "123456"
정리해서, 다시 지금껏 줄인 단계를 한 단계씩 짚어보겠다.
Step1
class User:
user1.User():
user1(인스턴스명).name(속성 이름) = "Young"
user1.email = "young@codeit.kr"
user1.password = "123456"
user1.메소드명()
user1.메소드명("Young", "young@codeit.kr")
Step2
class User:
def initialize(self, name, email, password):
self.name = name
self. email = email
self. password = password
user1 = User()
user1.initialize("Young", "young@codeit.kr", "123456")
Step3
class User:
def __init__(self, name, email, password):
self.name = name
self. email = email
self. password = password
user1 = User("Young", "young@codeit.kr", "123456")
class User:
def __init__(self, name, email, password):
self.name = name
self. email = email
self. password = password
def say_hello(self):
print("안녕하세요! 저는 {}입니다!".format(self.name)
user1 = User("Young", "young@codeit.kr", "123456")
user2 = User("Yoonsoo", "yoonsoo@codeit.kr", "abcdef")
User = User(user3, "Taeho", "taeho@codeit.kr", "123abc")
User = User(user4, "Lisa", "lisa@codeit.kr", "abc123")
print(user1.name, user1.email, user1.password)
print(user2.name, user2.email, user2.password)
print(user3.name, user3.email, user3.password)
print(user4.name, user4.email, user4.password)
초기화된 인스턴스를 출력해보았다.
결과물
'어떤 클래스의 객체인지 + 인스턴스 저장 주소'가 적혀있다.
이제 원하는 상황으로 출력하고 싶어 다시 특별한 메소드를 쓰려고 한다.
어떤 인스턴스를 출력하면 _str__ 리컨값이 출력된다.
check only
str 메소드는 인스턴스의 정보를 이해하기 쉬운 문자열로 나타내고 싶을 때 유용하게 사용된다.
이런식으로 str메소드에 리턴값을 지정해주면 print문이 실행될 때 자동으로 str 메소드를 거쳐 출력이 되게 한다.
이렇게 인스턴스와 관련된 원하는 정보를 출력하고 싶을 때 str 메소드를 쓰면 굳이 호출해주지 않아도 (리턴값만 잘 지정해준다면) 알아서 str 메소드가 호출되어 편리해진다.
방식은 이렇게 클래스 밑에 바로 전역변수 선언하듯 써주면 된다.
값 변경할 때나 설정할 때에도, 출력할 때에도, 클래스명.클래스변수 = "값"으로 지정해주면 된다.
클래스 변수 count가 유저 인스턴스 개수를 정확히 나타내도록 하려면
init 메소드에서 count 해주면 된다.
A. 인스턴스 변수가 읽어진다.
꼬일 수 있어서 클래스 변수는 클래스 이름으로만 설정한다.
클래스 변수는 클래스명. 클래스변수 혹은 인스턴스명.클래스변수로 읽을 수 있다.
하지만 클래스 변수의 값을 설정할 때는 꼭 클래스이름. 클래스 변수명으로 설정해야한다.
말그대로 add_print_to(print_hello)는 wrapper만 return한 것이다. 함수명만으로는 실행이 안된다. wrapper()라는 괄호로 파라미터가 들어갈 자리가 있어야 실행이 되는 것이다. 나는 처음에 7번째 줄 괄호 안에 무언가를 넣어야 한다고 생각했었는데 지금 코드가 wrapper는 문자열을 출력하고 original을 출력하는 것이다.
print_hello = original = print("안녕")
wrapper = print("함수시작") + original() + print("함수끝")
add_print_to(original)= add_print_to(print_hello)
문제는 간단하다. 13줄 자체에는 보기만해서는 문제가 없는데, 실행과정을 보면 return으로 wrapper만 나오니까, 11줄에서 wrapper를 수행시키게 수정하거나, add_print_to(print_hello)() 뒤에 괄호를 추가해주면 wrapper()가 된다.
실행된다.
이렇게 함수 print_hello()의 출력값을 앞뒤로 decorate하듯이 원하는 결과값으로 출력하게 되었다.
조금 떠 깔끔하게 고쳐보자.
꾸며주고 싶은 함수 위에 @데코레이터 함수를 쓴다.
이렇게!
다양한 함수를 데코레이터 하나를 모두 붙여주면 같은 방식으로 꾸며질 것이다.
같은 리본을 달게 된다.
20번째 줄의 cls.count는 앞에 클래스 메소드로 number_of_users로 지정해서
User.count와 같게 된다.
이제 메소드 number_of_users는 클래스 User도 인스턴스 user123으로도 parameter input이 가능하게 된다.
say_hello() : instance method
User.say_hello(user1) (selfX_파라미터로 입력해야 전달)
user1.say_hello() (self O)#인스턴스 자신이 첫번째 파라미터로 자동전달되는 것
여기서 인스턴스 자신이 첫 parameter로 자동 전달 되는 것은 self다.
자동호출 되는 것은 두 번째 줄처럼 되어있을 때만 그렇게 되었다.
number_of_users() : class method
하지만 클래스 메소드에는 두 방법 다 첫번째 파라미터로 자동 전달된다.
User.number_of_users()
user1.number_of_users()
그리고 클래스 변수로만 작성되는 함수라면 클래스 메소드로 작성이 되어야 한다.
Q1. 그럼 클래스 변수와 인스턴스 변수 둘다 쓴다면?
A. 인스턴스 메소드로 쓰기
인스턴스 메소드는 인스턴스 변수, 클래스 변수 모두 사용 가능하기 때문.
클래스 메소드는 인스턴스 변수 사용 불가, cls로 클래스 변수는 가져올 수 있지만,
클래스 메소드가 인스턴스 변수를 가져올 방법이 없다.
Q2. 인스턴스 없이도 필요한 정보가 있다면
A. 클래스 메소드로 쓴다.
예를 들어 앞의 User.count 메소드는 인스턴스가 없더라도 필요하다.
이렇게 유저 인스턴스가 하나도 없더라도 사용할 가능성이 있으면 클래스 메소드를 만들어야 한다.
보통 클래스 메소드는 아래 예시처럼 모든 인스턴스에게 공통된 값을 적용할 때 사용된다.
클래스명.클래스메소드로 주로 쓴다.
👉 name, email, password 클래스 변수를 만들어 인스턴스에게 같은 성질을 부여했다.
@classmethod
def from_string(cls, string_params):
# 유저 인스턴스를 생성해서 리턴한다
return User("강영훈", "younghoon@codeit.kr", "123456")
@classmethod
def from_string(cls, string_params):
# 유저 인스턴스를 생성해서 리턴한다
return cls("강영훈", "younghoon@codeit.kr", "123456")
둘은 같은 의미의 코드다.
class User:
count = 0
def __init__(self, name, email, pw):
self.name = name
self.email = email
self.pw = pw
User.count += 1
def say_hello(self):
print("안녕하세요! 저는 {}입니다!".format(self.name))
def __str__(self):
return "사용자: {}, 이메일: {}, 비밀번호: ******".format(self.name, self.email)
@classmethod
def number_of_users(cls):
print("총 유저 수는: {}입니다".format(cls.count))
@staticmethod
def is_valid_email(email_address):
return "@" in email_address
인스턴스, 클래스 두가지를 통해 모두 가능하다.print(User.is_valid_email("taehosung"))
print(User.is_valid_email("taehosung@codeit.kr"))
print(user1.is_valid_email("taehosung"))
print(user1.is_valid_email("taehosung@codeit.kr"))