names = ['홍길동','김현주','윤나은','이지선']
enum_names = enumerate(names)
for i, name in enum_names :
print(i, name)
# 출력 :
0 홍길동
1 김현주
2 윤나은
3 이지선
names = ['홍길동','김현주','윤나은','이지선']
enum_names = enumerate(names, 1) # 1번부터 시작
enum_dict = dict(enum_names)
print(enum_dict)
# 출력 : {1: '김현주', 2: '윤나은', 3: '이지선', 4: '홍길동'}
name = '홍길동'
age = 22
# 1. 표현식 기반 문자열 조합
print("이름 : %s 나이 : %d" %(name, age))
# 2. 메소드 호출 기반 문자열 조합
print("이름 : {} 나이 : {}".format(name, age))
# 3. f-string 기반 (3.6버전부터 제공)
print(f"이름 : {name} 나이 : {age}")
# 출력 : 이름: 홍길동 나이 : 22
class Simple():
def seti(self,i):
self.i = i # 변수 자체를 동적으로 생성한다.
def geti(self):
return self.i # 에러가 나는 이유
s = Simple()
print(s.geti())
i를 주지 않았기 때문에 변수를 동적 할당하지 않았다.
에러가 나지 않도록 하려면 geti 하기 전에 s.seti(10) 같이 i 값을 미리 설정해야 한다.
class Animal :
def __init__(self, name, color, size) :
self.name = name
self.color = color
self.size = size
def eat(self) :
print('냠냠')
class Capybara (Animal) : # 상속
def __init__(self, name, color, size, weight) :
super().__init__(name, color, size) # 부모 클래스의 초기화 호출
self.weight = weight
def eat(self) :
super().eat() # 부모 클래스의 eat() 호출
print("맛있당")
capy = Capybara('카피', 'brown', 100, 60)
capy.eat() # 출력 : 냠냠 맛있다
상속(Inheritance)은 부모 클래스의 속성과 메서드를 자식 클래스가 물려받는 것이다.
자식 클래스는 부모 클래스 기능을 그대로 사용하거나 기능의 재정의(오버라이딩) 할 수 있다.
상속을 통해 코드의 재사용성을 높이고 중복을 줄일 수 있다.
예시에서는 부모 클래스(Animal)에서 동물의 기본 특징과 행동을 정의하고
자식클래스(Capybara)에서 필요에 따라 부모 클래스의 기능(eat)을 변경하거나 확장했다.
단일 상속 (Single Inheritance)
: 자식 클래스가 한 개의 부모 클래스만 상속받는 방식이다.
: 부모 클래스의 속성과 메서드를 그대로 물려받아 자식 클래스에서 활용하거나 확장한다.
: 구조가 간단하고 이해하기 쉽고 상속 계층이 단순해서 충돌이나 모호성이 적다.
다중 상속 (Multiple Inheritance)
: 자식 클래스가 여러 부모 클래스를 상속받는 방식이다.
: 부모 클래스가 둘 이상이므로 여러 클래스의 속성과 메서드를 물려받는다.
: 다양한 기능을 조합해서 강력한 클래스를 설계할 수 있다.
: 하지만 메서드 이름이 겹치거나 상속 순서가 복잡하면 충돌이나 모호성 문제가 발생할 수 있다.
class Animal:
def move(self):
print("Animal moves.")
class Bird:
def fly(self):
print("Bird flies.")
class Bat(Animal, Bird): # 다중 상속
pass
bat = Bat()
bat.move() # 출력: Animal moves.
bat.fly() # 출력: Bird flies.
1) 상속 관계에서만 사용가능하다.
: 부모 클래스에서 메서드를 자식 클래스에서 재정의하는 것이기 때문에 반드시 상속이 전제되어야 한다.
2) 메서드 이름, 매개변수, 반환값이 동일하다.
: 부모 클래스의 메서드와 같은 이름, 매개변수를 사용해야 오버라이딩으로 인식된다.
3) 부모 클래스의 메서드를 호출 가능하다.
: super()를 사용하면 부모 클래스의 원래 메서드 구현을 호출할 수 있다.
4) 다형성의 구현
: 오버라이딩은 다형성을 구현하는데 중요한 역할을 한다.
: 같은 이름의 메서드가 클래스에 따라 다르게 동작하도록 설계 가능하다.
class Car:
def __init__(self,name,color):
self.name = name
self.color = color
def show_info(self):
print(f'이름: {self.name} 이고 색상은:{self.color}')
hybrid = HybridCar("하이브리드","검정",10)
hybrid.show_info()
# 출력 : 이름: 하이브리드 이고 색상은:검정 / 배터리 용량은: 10
class HybridCar(Car) :
def __init__(self, name, color, battery):
super().__init__(name, color)
self.battery = battery
def show_info(self) :
super().show_info()
print(f"배터리 용량은 : {self.battery}")
hybrid = HybridCar("하이브리드","검정",10)
hybrid.show_info()
shape_list = [Rectangle(10,20),Triangle(10,20)]
sum_area = 0
for shape in shape_list:
sum_area += shape.area()
print(sum_area)
출력: 300
class Shape :
def __init__(self, width, height):
self.width = width
self.height = height
def area(self) :
pass
class Rectangle(Shape) :
def __init__(self, width, height):
super().__init__(width, height)
def area(self) :
return self.width * self.height
class Triangle(Shape) :
def __init__(self, width, height):
super().__init__(width, height)
def area(self) :
return self.width * self.height / 2
shape_list = [Rectangle(10,20),Triangle(10,20)]
sum_area = 0
for shape in shape_list:
sum_area += shape.area()
print(sum_area) # 출력 : 300
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
pass
dog = Dog("멍멍이")
print(dog.name) #멍멍이
print(dog.speak()) # 멍멍!
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
pass
class Dog(Animal) :
def __init__(self, name):
super().__init__(name)
def speak(self) :
return "멍멍!"
dog = Dog("멍멍이")
print(dog.name) # 출력 : 멍멍이
print(dog.speak()) # 출력 : 멍멍!
# 연산자 오버로딩
class Account :
def __init__(self, bal): # 잔액 초기화
self.bal = bal
def __add__(self, money) : # + 연산자 오버로딩
self.bal += money
def __sub__(self, money) : # - 연산자 오버로딩
self.bal -= money
# 복합 대입 연산자의 경우 i를 붙여야 한다.
# 연산 후에 다시 대입하기 때문에 return self가 필수이다.
def __iadd__(self, money) : # += 연산자 오버로딩
self.bal += money
return self # 연산 후 객체 반환
def __isub__(self, money) : # -= 연산자 오버로딩
self.bal -= money
return self
def __str__(self) : # 객체를 문자열로 표현
return str(self.bal)
my_acc = Account(0) # 초기 잔액 : 0
my_acc + 100 # 100원 추가
print(my_acc) # 출력 : 100
my_acc -= 30 # 30원 차감
print(my_acc) # 출력 : 70
연산자 오버로딩은 기존에 정의된 연산자의 동작을 사용자 정의 클래스에 맞게 재정의하는 것이다.
이를 통해 객체 간의 연산을 기본 자료형처럼 직관적으로 처리할 수 있다.
세줄요약:
1. 상속 = 재사용(reuse) = 부모에 있는 함수및 변수를 써먹을수 있다.
2. 오버라이딩은 자식꺼
3. 메서드 오버라이딩 = 클래스 상속 관계에서 똑같은 함수 이름으로 내용을 달리 하는거
어쩐지 이번에 다시 파이썬 공부를 하면서 f-string을 보고 이런 게 있었나? 싶었다.ㅋㅋㅋ
하다보니까 이게 더 편해서 이거 왜 안 배웠었지?? 했는데 나중에 추가된 버전인 것 같다.
