클래스는 파이썬 초보자인 나에게 헷갈리는 개념이다.
아직 헷갈리지만 최대한 정리해둔다.
참고로, 파이썬 - 기본을 갈고 닦자! 41번 문서에 클래스가 잘 설명돼 있다. 나중에 제대로 보자.
클래스(Class)와 객체(Object)를 직관적으로 설명하는 예시는 '클래스는 붕어빵 찍어내는 틀이고, 객체는 이 틀로 찍어낸 붕어빵'이라는 것이다. 쉽게 와닿지만, 어떤 블로그 글에선 이 예시가 잘못됐다고 지적하는 내용도 있어 혼란스럽다. 하지만 일단 이 정도로 이해하고 넘어가겠다.
위 붕어빵 예시가 보여주듯 클래스는 '설계도'이고 객체는 '설계도로 구현한 대상'이다.
- 클래스는 객체의 구조와 행동을 정의한다.
- 클래스는 복잡한 문제를 다루기 쉽도록 만든다.
클래스를 이해하려면
Object, self, __init__ 등 개념을 이해해야 한다.
👉Object : Object is one of the instances of the class which can perform the functionalities which are defined in the class
👉self : self represents the instance of the class. By using the 'self' keyword we can access the attributes and methods of the class.
👉__init__ : __init__ is a reserved method in python classes. It is known as a constructor in object-oriented concepts. This method called when an object is created from the class and it allows the class to initialize the attributes of a class.
아래 내용은 <입문부터 실무까지 한 방에 끝내는 파이썬 프로그래밍_by 조인석> 내용을 정리한 것임을 밝힙니다. 좋은 책이니 파이썬 기초를 공부하는 분에게 추천합니다.
사실 잘 이해 안 된다.
클래스를 이해하려면
Object, self, __init__ 등 개념을 이해해야 한다.
👉Object : Object is one of the instances of the class which can perform the functionalities which are defined in the class
👉self : self represents the instance of the class. By using the 'self' keyword we can access the attributes and methods of the class.
👉__init__ : __init__ is a reserved method in python classes. It is known as a constructor in object-oriented concepts. This method called when an object is created from the class and it allows the class to initialize the attributes of a class.
아래 내용은 <입문부터 실무까지 한 방에 끝내는 파이썬 프로그래밍_by 조인석> 내용을 정리한 것임을 밝힙니다. 좋은 책이니 파이썬 기초를 공부하는 분에게 추천합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | #%% md # Ch 09. 클래스 ## 09.01 클래스 이해하기 ''' 클래스에서 생성된 객체를 인스턴스라고 부른다. 일반적으로 클래스의 객체를 생성하는 과정을 인스턴스화라고 한다. 모든 인스턴스에는 타입이 존재한다. 이 타입은 클래스에 의해 정의된다. 메소드 : 클래스 속에 속해 있는 내장 함수 ''' #%% var = '파이썬 객체 지향 이야기' var.__class__ # var 지역 변수 __class__ 값 확 var.replace('파이썬', 'Python') # var 값 일부 변경 #%% md ### (1) 클래스 정의 및 불러 오기 #%% class BookReader: # 클래스 BookReader 선언 name = str() # 문자열 타입 변수 name 선언 def read_book(self): # 함수 read_book 선언 print(self.name + ' is reading Book!!') #%% md 클래스명 작성 방식 : 낙타 표기법을 따른다! 클래스명에서는 언더바를 사용하지 않는다. 그리고 각 단어의 첫 음절이 대문자인 단어들의 조합 형태로 돼 있다. 이런 표기법을 CamelCase (낙타 표기법) 이라고 한다. ''' #%% reader = BookReader() # 인스턴스 생성 type(reader) # 변수 reader1 타입 확인 #%% md __ _main_ __ : 현재 클래스가 생성된 위치를 보여 준다. 파이썬 실행의 최상단 레벨 코드에서 실행이 되었다는 의미로 볼 수 있다. 이는 곧 이 클래스를 호출할 수 있는 유효범위와도 깊은 관계가 있으며, __main__에 속한 클래스는 전역에서 호출이 가능하다. ''' #%% reader.name = 'Ryu' # 속성 값 세팅 reader.read_book() # 메소드 호출 #%% md ### (2) 클래스 초기화 함수 __init__() 재정의 ''' __init__ : __init__() 함수는 새로 생성하는 함수가 아니라 이미 존재하고 있는 초기화 함수다. 인스턴스를 만들 때 호출하는 BookReader() 호출 시 불리는 함수라고 보면 된다. 이렇게 이미 존재하는 함수를 다시 정의하는 과정을 함수 재정의라고 한다. ''' #%% class BookReader: def __init__(self, name): # 초기화 함수 재정의 self.name = name def read_book(self): print(self.name + ' is reading Book!!') #%% reader = BookReader('Sooyoun') # 객체 생성 reader.read_book() # 메소드 호출 #%% md ### (3) 클래스 변수와 인스턴스 변수 ''' 클래스 변수 : 클래스에 의해 생성된 모든 객체가 인스턴스화되는 시점에 같은 값을 조회할 때 사용 가능 (country) 인스턴스 변수 : 객체가 인스턴스화 될 때마다 새로운 값이 할당되며 서로 다른 객체 간에는 값을 공유할 수 없다. (name) 만약 이해가 잘 안 된다면, 무조건 인스턴스 변수만을 사용하길 권고한다. 이렇게 작성된 인스턴스 변수 중 값이 절대로 변경되지 않거나, 여러 객체 사이에서 값이 공유돼야 하는 경우에는 클래스 변수로 옮기면 된다. 이렇게 작성된 소스 코드를 더 보기 좋고 효율적으로 변경하는 작업을 '리팩토링' 이라고 한다. 소스 코드도 물과 같이 고이면 냄새가 나고 썩기 마련이다. 리팩토링 기법에 관한 서적을 쉽게 접할 수 있으니 관심 있으면 읽어보길. ''' #%% class BookReader: country = 'South Korea' # 클래스 변수 country 선언 def __init__(self, name): # 초기화 함수 재정의 self.name = name def read_book(self): print(self.name + ' is reading Book!!') reader1 = BookReader('Chris') # 'Christ' 라는 이름을 가진 객체 인스턴스화 reader2 = BookReader('Anna') # 'Anna' 라는 이름을 가진 객체 인스턴스화 reader1.country # 클래스 변수 country 값 확인 #%% class Dog: tricks = [] # 클래스 변수 (인스턴스 간 공유 됨) def __init__(self, name): self.name = name def add_trick(self, trick): self.tricks.append(trick) # 클래스 변수에 값 추가 fido = Dog('Fido') buddy = Dog('Buddy') fido.add_trick('구르기') buddy.add_trick('두 발로 서기') buddy.add_trick('뽀뽀하기') fido.tricks #%% md trick 을 클래스 변수로 선언해 fido의 tricks 변수에 buddy에게 넣은 장난까지 모두 출력됐다. 이럴 땐 tricks를 인스턴스 변수로 선언해야 한다. #%% class Dog: def __init__(self, name): self.name = name self.tricks = [] # 인스턴스 변수 생성 def add_trick(self, trick): self.tricks.append(trick) fido = Dog('Fido') buddy = Dog('Buddy') fido.add_trick('구르기') buddy.add_trick('두 발로 서기') buddy.add_trick('뽀뽀하기') fido.tricks, buddy.tricks #%% md ### (4) 심화/ 데이터 은닉과 이름 장식 #%% class BookReader: country = 'South Korea' # 클래스 변수 country 선언 dir(BookReader) # dir() 는 파이썬 기본 함수로, 클래스 내부에 들어 있는 객체들을 확인하는 명령문이다. #%% BookReader.country = 'USA' # 클래스 변수 값 변경하기 BookReader.country #%% md ''' dir(BookReader) 리스트 맨 마지막에 있는 country 변수는 너무 쉽게 접근, 수정할 수 있다. 이게 무슨 문제일까 생각할 수도 있지만, 클래스 변수로 쉽게 변경할 수 없는 값을 집어 넣었는데 아무나 이 값을 쉽게 변경할 수 있다면 이 함수에 대한 신뢰도는 떨어지기 마련이다. 그래서 객체 지향 언어에서는 데이터 은닉 혹은 캡슐화라는 개념을 사용하고 있다. 이런 데이터는 외부에 노출하지 말고 숨기자는 의도이다. 하지만 파이썬에서는 이를 위한 강력한 도구를 제공하고 있지 않다. 가령, 자바는 클래스 변수는 밖에서 아예 접근이 불가능하도록 하는 접근 제한자를 가지고 있어 어떤 방식으로든 바로 참조를 할 수 없게 돼 있다. 대신, 파이썬은 변수명 앞에 __ 가 있는 것에 한하여 이름을 변경해 버리는 Name Mangling 기법을 제공한다. ''' #%% class BookReader: __country = 'South Korea' # 클래스 변수 country 선언 (Name Mangling) dir(BookReader) #%% md ''' dir( )로 BookReader 클래스의 내부를 다시 확인해 보니, 리스트 첫 번째 항목에 변형된 변수명을 확인할 수 있다. 변형된 규칙은 _[클래스명]__[변수명]이다. 이렇게 변형된 변수는 기존 변수명으로는 값을 확인할 수 없게 된다. 다음 소스 코드를 확인해 보자. 속성 에러가 떠서 클래스를 정의할 때 사용했던 변수명으로는 접근이 불가능한 것을 확인할 수 있다. BookReader.__country #%% md 이런 클래스 변수는 어떻게 수정하는 게 좋을까? 클래스 안에 이 변수를 수정하기 위한 메소드를 선언해 호출하는 방식이 좋다. #%% class BookReader: __country = 'South Korea' # 클래스 변수 country 선언 (Name Mangling) def update_country(self, country): # country 변경 메소드 선언 self.__country = country # country 값 변경 def get_country(self): # country 값 반환 메소드 선언 return self.__country # country 값 반환 br = BookReader() # BookReader 인스턴스 생성 br.get_country() #%% br.update_country('USA') br.get_country() #%% md ### (5) 객체 지향의 꽃, 상속 (Inheritance) 객체 지향 언어에서의 상속은 말 그대로 부모 클래스가 자식 클래스에게 무언가를 물려 주는 것이다. 파이썬에서는 부모 클래스를 베이스 클래스(Base Class)라고 하고, 자식 클래스는 파생 클래스(Derived Class)라고 부른다. -Base Class : 부모 클래스. 자식 클래스들에게 물려 줄 속성과 메소드들을 정의한다. -Derived Class : 자식 클래스. 부모의 속성, 메소드를 물려 받는다. 상속은 왜 필요할까? 중복 코드를 최소화 하고, 클래스 간 계층 관계를 형성해 현실 세계와의 괴리를 줄이기 위해서. #%% md #### - 부모 클래스 Human 선언 #%% class Human: country = 'South Korea' # 클래스 변수 country 선언 def __init__(self, name): # 초기화 함수 재정의 self.name = name # 인스턴스 변수 name 선언 def eat_meal(self): print(self.name + ' is eating meal!!') #%% md #### - Human의 자식 클래스인 BookReader 클래스 선언 #%% class BookReader(Human): # Human의 자식 클래스인 BookReader 클래스 선언 def read_book(self): print(self.name + ' is reading Book!!') class DrumPlayer(Human): # Human의 자식 클래스인 DrumPlayer 클래스 선언 def play_drum(self): print(self.name + ' is playing Drum!!') br = BookReader('Christ') # BookReader 인스턴스 생성 (부모 init 활용) br.country #%% br.read_book() #%% dp = DrumPlayer('Sean') # DrumPlayer 인스턴스 생성 (부모 init 활용) dp.country #%% dp.play_drum() #%% br.eat_meal() #%% md #### - 자식 클래스 추가 #%% class BookWriter(Human): def write_book(self): print(self.name + ' is writing Book!!') #%% md 이미 만들어진 인스턴스나 클래스의 부모 클래스를 찾는 방법 !! 이미 만들어진 인스턴스나 클래스의 부모 클래스를 찾는 방법. 본인이 어떤 클래스의 인스턴스인지를 확인하는 방법은 __class__ 속성 값을 확인하는 것이다. 부모 클래스인 베이스 클래스 확인을 위해서는 __bases__ 속성 값을 확인하면 된다. #%% br.__class__ # br 인스턴스의 타입 확인 #%% BookReader.__class__ # BookReader 클래스의 타입 확인 #%% BookReader.__bases__ # BookReader의 부모 클래스 확인 #%% Human.__bases__ #%% md 우리가 만드는 모든 클래스의 부모 클래스는 object 클래스다. 상속 계층 구조의 가장 높은 곳에 위치한 녀석이다. 다시 한번 파이썬의 모든 것은 객체라는 것이 확인 됐다. (object,) 인 이유는 부모 클래스가 한 개가 아닌 여러 개가 될 수도 있다는 것을 암시한다. #%% md #### - 부모 클래스를 두 개 갖는 자식 클래스 #%% class Developer: # Devloper 부모 클래스 선언 def coding(self): # coding 메소드 선언 print(self.name + ' is developer!!') class ProgramBookWriter(Human, Developer): def write_book(self): print(self.name + ' is writing Book!!') pbw = ProgramBookWriter('Chris') # 인스턴스 생성 pbw.eat_meal() # Human 메소드 호출 #%% pbw.coding() # Developer 메소드 호출 #%% pbw.write_book() # ProgramBookWriter 메소드 호출 #%% ProgramBookWriter.__bases__ #%% md 이처럼 여러 클래스를 하나의 자식 클래스가 상속 받는 것을 다중 상속이라고 한다. #%% md ### (6) 심화/ 다형성 (polymorphism) #%% class Developer: # Developer 부모 클래스 선언 def __init__(self, name): # 초기화 시 name을 받기 위한 재정의 self.name = name def coding(self): # coding 메소드 선언 print(self.name + ' is developer!!') class PythonDeveloper(Developer): # PythonDeveloper 자식 클래스 선언 def coding(self): # coding 메소드 선언 print(self.name + ' is Python developer!!') class JavaDeveloper(Developer): # JavaDeveloper 자식 클래스 선언 def coding(self): print(self.name + ' is Java developer!!') class CPPDeveloper(Developer): # CPPDeveloper 부모 클래스 선언 def coding(self): print(self.name + ' is C++ developer!!') #%% pd = PythonDeveloper('Sooyoun') # PythonDeveloper 인스턴스 생성 jd = JavaDeveloper('Jason') cd = CPPDeveloper('Bryan') pd.coding() #%% jd.coding() #%% cd.coding() #%% md 이렇게 부모 클래스와 동일한 이름의 메소드를 그대로 자식 클래스에서 구현해 재정의 하는 것을 다향성의 구현이라고 한다. #%% class CPPDeveloper(Developer): # CPPDeveloper 부모 클래스 선언 def coding(self): # coding 메소드 선언 super().coding() # 부모 인스턴스의 coding() 함수 호출 print(self.name + ' is C++ developer!!') #%% md 3번째 줄이 핵심이다. super()를 통해 부모 인스턴스를 확보한 뒤 점 기호(.)를 통해 coding() 함수를 호출하고 있다. #%% cd = CPPDeveloper('Bryan') # 자식 클래스 인스턴스 생성 cd.coding() # 자식 클래스 메소드 호출 #%% md 출력 결과를 보면 부모의 coding() 함수와 본인의 coding() 함수 내 출력문이 출력됐다. 이런 식의 super() 클래스 호출은 초기화 함수 호출시에도 많이 활용된다. 가령, __init__() 함수를 재정의하면 부모의 초기화 함수 코드를 사용하지 못하기 때문에 super()를 활용해 사용한다. 예를 들어, 자식 클래스의 초기화 함수 내 super().__init__()를 호출하면 부모의 초기화 함수를 호출할 수 있다. |
사실 잘 이해 안 된다.
한 번 코드로 보자.
1. 새로운 클래스 생성
새로운 클래스를 만들기 위해서는 class 키워드를 사용한다.
1 2 | class Flight: pass |
2. 새로운 객체 생성
1 | f = Flight() # 생성자(constructor) |
3. 매서드 작성
매서드는 클래스에 들어 있는 함수다.
1 2 3 | class Flight: def number(self): return 'SN060' |
파이썬 매서드의 첫 번째 파라미터 이름에 관례적으로 self 를 사용한다. 호출 시 호출한 객체 자신이 전달되기 때문에 self 라고 하는 것이다.
4. 인스턴스 매서드 접근
클래스로부터 만들어진 객체를 그 클래스의 인스턴스(Instance)라고 한다.
1 | f.number() |
위 코드는 'SN060'를 출력한다.
코드 따라쓰며 연습하기 1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class Rectangle: """Find out the cost of a rectangular filed with breadth(b=120), length(I=160) It costs x(2000) rupees per 1 square unit""" def __init__(self, length, breadth, unit_cost = 0): self.length = length self.breadth = breadth self.unit_cost = unit_cost def get_area(self): return self.length * self.breadth def calculate_cost(self): area = self.get_area() return area * self.unit_cost r = Rectangle(160, 120, 2000) print("Area of Rectangle : %s sq units" % (r.get_area())) print("Cost of rectangular filed: Rs.%s" % (r.calculate_cost())) |
r = Rectangle(160, 120, 2000)
Note
- "r" is the representation of the object outside of the class.
- "self" is the representation of the object inside the class.
output :
Area of Rectangle: 19200 sq units
Cost of rectangular filed: Rs. 38400000
코드 따라쓰며 연습하기 2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ## 클래스 연습 코드 2 class Knight: def __init__(self, health, mana, armor): # 매개변수로 self, health, mana, armor 지정 self.health = health self.mana = mana self.armor = armor def slash(self): # slash 메서드 생성 print("베기") # 인스턴스 생성 x = Knight(health = 542.4, mana = 210.3, armor = 38) print(x.health, x.mana, x.armor) x.slash() |
코드 출처 : 파이썬 코딩 도장
출력 결과 :
542.4 210.3 38
베기
코드 따라쓰며 연습하게 3)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # 클래스 연습 코드 3 class Customer(object): """ A customer of ABC Bank with a checking account. Customers have the following properties: Attributes: name : A string representing the customer's name. balance : A float tracking the current balance of the customer's account. """ def __init__(self, name, balance=0.0): """Return a Customer Object whose name is *name* and starting balance is *balance*.""" self.name = name self.balance = balance # class method def withdraw(self, amount): """Return the balance remaining after withdrawing *amount* collors.""" if amount > self.balance: raise RuntimeError('Amount greater than available balance.') self.balance -= amount return self.balance # class method def deposit(self, amount): """Return the balance remaining after depositing *amount* dollors.""" self.balance += amount return self.balance Ryu = Customer('Ryu Han', 1000.0) # 기존 1000원 Ryu.withdraw(500) # 500원 인출 Ryu.deposit(700) # 700원 예금 |
코드 출처 : Jeff Knupp
출력 결과 :
1200.0 ( 1000원 든 통장에서 500원 인출하고 700원 예금하면, 통장에 1200원 남음)
코드 따라쓰며 연습하게 4)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import math class Point(object): def __init__(self, x = 0, y = 0): self.x = x # 데이터 속성 (attribute) self.y = y def distance_from_origin(self): # 메서드 속상 return math.hypot(self.x, self.y) # .hypot( ) 함수는 직각삼각형의 빗변 계산 def __eq__(self, other): return self.x == other.x and self.y == other.y def __repr__(self): return "point ({0.x!r}, {0.y!r})".format(self) def __str__(self): return "({0.x!r}, {0.y!r})".format(self) |
코드 출처 : <파이썬 구조와 알고리즘>
0 Comments
Post a Comment