class 사용법
class MyClass: # 클래스 멤버와 메서드 정의
pass
위 코드에서 MyClass는 클래스 이름이며, 클래스 내부의 pass 문은 클래스 멤버나 메서드를 정의하는 부분입니다.
클래스를 정의한 이후에는 해당 클래스를 인스턴스화하고 사용할 수 있습니다. 클래스의 인스턴스는 클래스를 기반으로 생성된 객체(object)를 의미합니다. 클래스의 인스턴스를 생성하려면 다음과 같은 형식을 사용합니다.
my_obj = MyClass()
위 코드에서 my_obj는 MyClass 클래스를 기반으로 생성된 객체를 의미합니다. 객체를 생성한 이후에는 해당 객체에 대해 클래스 내부의 메서드나 멤버 변수에 접근할 수 있습니다.
클래스 내부에서 멤버 변수를 정의하는 방법은 다음과 같습니다.
class MyClass:
def __init__(self, arg1, arg2):
self.arg1 = arg1
self.arg2 = arg2
위 코드에서 __init__ 메서드는 클래스를 인스턴스화할 때 호출되는 특수한 메서드입니다. self 인자는 클래스 인스턴스 자체를 의미하며, arg1과 arg2는 인스턴스에 대한 멤버 변수입니다.
클래스 내부에서 메서드를 정의하는 방법은 다음과 같습니다.
class MyClass:
def my_method(self, arg1, arg2): # 메서드 내부에서 수행할 작업 정의
pass
위 코드에서 my_method는 MyClass 클래스 내부의 메서드이며, arg1과 arg2는 메서드에 전달되는 인자입니다. 클래스 내부의 메서드에서 self 인자를 사용하면 클래스의 멤버 변수에 접근할 수 있습니다.
객체 지향의 특징 파이썬에서 사용하기
- 상속
class ParentClass: # 부모 클래스 멤버와 메서드 정의
pass
class ChildClass(ParentClass): # 자식 클래스 멤버와 메서드 정의
pass
위 코드에서 ParentClass는 부모 클래스를 정의하고, ChildClass는 부모 클래스를 상속받은 자식 클래스를 정의합니다. 자식 클래스는 부모 클래스에서 정의된 모든 멤버와 메서드를 상속받습니다. 상속받은 멤버와 메서드를 자식 클래스에서 오버라이딩하거나 확장할 수 있습니다.
부모 클래스의 메서드를 오버라이딩하려면 자식 클래스에서 같은 이름의 메서드를 다시 정의하면 됩니다.
class ParentClass:
def my_method(self):
print("Parent method")
class ChildClass(ParentClass):
def my_method(self):
print("Child method")
위 코드에서 ChildClass는 ParentClass를 상속받았으며, my_method 메서드를 오버라이딩하여 부모 클래스에서 정의된 메서드를 덮어씁니다. 이제 ChildClass 객체에서 my_method를 호출하면 오버라이딩된 메서드가 실행됩니다.
my_obj = ChildClass()
my_obj.my_method() # "Child method" 출력
상속받은 메서드를 확장하려면 자식 클래스에서 부모 클래스의 메서드를 호출하고, 추가적인 작업을 수행하면 됩니다.
class ParentClass:
def my_method(self, arg):
print(f"Parent method called with arg: {arg}")
class ChildClass(ParentClass):
def my_method(self, arg): super().my_method(arg) # 부모 클래스의 메서드 호출 print("Additional work performed")
my_obj = ChildClass()
my_obj.my_method("test") # "Parent method called with arg: test"와 "Additional work performed" 출력
위 코드에서 ChildClass는 ParentClass를 상속받았으며, my_method 메서드를 오버라이딩하여 부모 클래스의 메서드를 호출하고 추가적인 작업을 수행합니다. super() 함수를 사용하여 부모 클래스의 메서드를 호출할 수 있습니다.
2. 다형성
- 함수 오버로딩(Function Overloading)
- 함수 이름은 같지만 매개변수의 개수나 타입이 다른 여러 개의 함수를 만들어서, 호출 시에 파이썬이 알아서 맞는 함수를 선택하도록 하는 방법입니다.
- 하지만, 파이썬은 함수 오버로딩을 지원하지 않습니다.
- 연산자 오버로딩(Operator Overloading)
- 연산자(+, -, *, / 등)의 동작을 다양하게 구현할 수 있도록 하는 방법입니다.
- 예를 들어, '+' 연산자를 사용하면서, 숫자뿐만 아니라 문자열, 리스트, 튜플 등 다양한 데이터 타입에 대해서도 적용이 가능하게 됩니다.
- 다형성을 활용한 함수 호출(Polymorphic Function Calls)
- 상속 관계에 있는 클래스들이 같은 이름의 메서드를 가지고 있을 때, 각 객체의 타입에 따라서 적절한 메서드를 호출할 수 있도록 하는 방법입니다.
- 예를 들어, 부모 클래스에 있는 draw() 메서드를 상속받은 여러 개의 자식 클래스가 있을 때, draw() 메서드를 호출할 때 어떤 자식 클래스의 객체를 전달하느냐에 따라서 그에 맞는 draw() 메서드가 실행됩니다.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow"
def animal_speak(animal):
print(animal.speak())
my_dog = Dog("Rufus")
my_cat = Cat("Felix")
animal_speak(my_dog) # 출력: Woof!
animal_speak(my_cat) # 출력: Meow
위 예시에서는 Animal 클래스를 상속받은 Dog와 Cat 클래스를 만들었고, animal_speak() 함수를 만들어서 매개변수로 Animal 클래스의 객체를 받습니다. animal_speak() 함수 내에서는 animal.speak() 메서드를 호출하는데, 이때 animal 객체의 타입에 따라서 적절한 speak() 메서드가 실행되어 출력됩니다.
3. 캡슐화(visibility)
- 멤버 변수 접근 제한
파이썬에서는 멤버 변수에 대한 접근 제한을 위해 이름 규칙(name mangling)을 사용합니다. 멤버 변수 이름 앞에 두 개의 언더스코어(__)를 붙이면, 해당 변수는 private 멤버로 취급되며, 클래스 외부에서 접근할 수 없습니다. 다만, 이러한 변수는 클래스 내부에서는 언제든 접근할 수 있습니다.
class MyClass:
def __init__(self, x):
self.__x = x
def get_x(self):
return self.__x
def set_x(self, x):
self.__x = x
obj = MyClass(5)
print(obj.get_x()) # 5
obj.set_x(10)
print(obj.get_x()) # 10
print(obj.__x) # 에러 발생: AttributeError: 'MyClass' object has no attribute '__x'
- 메소드 접근 제한
파이썬에서는 메소드에 대한 접근 제한을 위해 데코레이터(decorator)를 사용합니다.
@property 데코레이터를 사용하면, 해당 메소드를 속성(property)으로 취급할 수 있습니다.
이렇게 하면, 해당 속성을 읽기 전용으로 만들거나, 값을 쓰기 전에 유효성 검사를 수행하는 등의 작업을 수행할 수 있습니다.
class MyClass:
def __init__(self, x):
self.__x = x
@property
def x(self):
return self.__x
@x.setter
def x(self, x):
if x < 0:
raise ValueError("x must be non-negative")
self.__x = x
obj = MyClass(5)
print(obj.x) # 5
obj.x = 10
print(obj.x) # 10
obj.x = -1 # 에러 발생: ValueError: x must be non-negative
decorator 에 대해 알아봅시다.
먼저 알아야할 개념이 있습니다.
1. first- class objects(일등 함수)
파이썬은 함수와 클래스를 포함한 모든 객체를 first-class object로 다룹니다. 이는 다음과 같은 특징을 갖습니다.
- 변수나 데이터 구조에 할당할 수 있습니다.
def my_func(x):
return x ** 2
# 함수를 변수에 할당
f = my_func
print(f(2)) # 4
# 함수를 리스트에 추가
funcs = [my_func, abs, len]
print(funcs[0](3)) # 9
- 함수의 인자로 전달할 수 있습니다.
def apply_func(func, x):
return func(x)
# 함수를 인자로 전달
print(apply_func(my_func, 3)) # 9
- 함수의 반환값으로 사용할 수 있습니다.
def get_func():
def new_func(x):
return x ** 3
return new_func
# 함수를 반환값으로 사용
f = get_func()
print(f(2)) # 8
2. inner function(내재함수)
파이썬에서 inner function은 함수 내부에 정의된 함수를 의미합니다. inner function은 다른 함수 내부에서만 사용되며, 해당 함수의 지역(local) 영역에만 영향을 미칩니다. inner function을 정의하는 이유는 코드의 가독성을 높이고, 코드 재사용성을 높이기 위함입니다.
inner function은 다음과 같은 특징을 갖습니다.
- 함수 내부에서 정의됩니다, 외부함수의 변수를 참조할 수 있습니다.
def outer_func(x):
def inner_func(y):
return x + y
return inner_func
f = outer_func(10)
print(f(5)) # 15
- 외부 함수가 호출될 때마다 새로 생성됩니다.
def outer_func():
def inner_func():
print("inner_func called")
return inner_func
f1 = outer_func()
f2 = outer_func()
f1() # "inner_func called"
f2() # "inner_func called"
print(f1 is f2) # False
3. closure(클로져)
클로저(closure)는 함수와 그 함수가 생성될 때의 자유 변수(free variable)들로 구성된 객체입니다. 클로저는 자바스크립트에서와 마찬가지로, 함수 내부에서 선언된 변수들을 외부에서 접근할 수 없게 만들어 변수의 유효 범위(scope)를 제한하고, 함수 호출이 종료된 이후에도 함수 내부에서 선언된 변수들을 계속 사용할 수 있게 합니다.
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
closure = outer_function(10)
print(closure(5)) # 15 출력
위 코드에서 outer_function은 inner_function을 반환합니다.
inner_function은 x라는 인자를 가지고 있지 않지만, outer_function의 인자 x를 참조할 수 있습니다.
이렇게 inner_function이 outer_function의 변수 x를 참조할 수 있는 이유는, inner_function이 클로저이기 때문입니다.
클로저는 보통 함수형 프로그래밍(functional programming)에서 많이 사용됩니다. 예를 들어, 파이썬에서 map, filter, reduce 등의 고차 함수(higher-order function)를 사용할 때, 클로저를 이용해 함수를 간단하게 정의할 수 있습니다.
그래서 decorator란??
파이썬에서 decorator는 다른 함수를 수정하거나 추가적인 동작을 제공하기 위한 간단하면서도 강력한 기능입니다.
Decorator는 다른 함수를 인자로 받아, 수정된 함수를 반환하는 함수입니다. 이 수정된 함수는 일반 함수보다 더 많은 기능을 제공할 수 있습니다. 예를 들어, decorator는 함수가 호출되기 전이나 후에 추가적인 작업을 수행할 수 있습니다.
Decorator의 일반적인 구문은 "@" 기호를 사용하여 함수를 수정하는 함수 위에 적용됩니다. 예를 들어, 다음과 같이 사용할 수 있습니다.
@decorator
def my_function():
# do something
여기서 decorator는 decorator(my_function)와 동일한 기능을 합니다. 이렇게 decorator를 사용하면 함수에 대해 필요한 추가적인 작업을 간단하게 수행할 수 있습니다.
파이썬에서 decorator는 함수를 다른 함수로 감쌀 때 유용합니다. 이를 통해 코드를 간결하고 재사용 가능한 블록으로 분리할 수 있습니다. 또한 decorator는 코드 중복을 방지하고 유지 보수성을 높일 수 있는 방법입니다.
예를 들어, 다음과 같이 로깅을 위한 decorator를 정의할 수 있습니다.
def logger(func):
def wrapper(*args, **kwargs):
print('Calling function:', func.__name__)
result = func(*args, **kwargs)
print('Function call finished.')
return result
return wrapper
이 decorator는 다른 함수를 인자로 받아, 함수를 감싸는 새로운 함수를 생성합니다. 이 새로운 함수는 함수를 호출하기 전에 로깅을 출력하고, 함수를 호출한 뒤에 함수 호출이 끝났음을 알리는 로깅을 출력합니다. 이를 사용하여 다른 함수를 호출할 때 다음과 같이 로깅을 추가할 수 있습니다.
@logger
def my_function():
# do something
위의 코드에서 my_function은 decorator logger에 의해 감싸지며, 이제 호출할 때마다 함수 호출과 함께 로깅이 출력됩니다.
'언어 공부 > Python' 카테고리의 다른 글
파일,예외처리, Log Handling (0) | 2023.03.07 |
---|---|
모듈, 패키지, 프로젝트 (0) | 2023.03.07 |
파이썬식 문법 + 함수 심화 개념 (0) | 2023.03.06 |
문자열과 함수 심화 개념 (0) | 2023.03.06 |
조건, 반복문 (0) | 2023.03.06 |