함수 인자 전달 규칙

Beginner

This tutorial is from open-source community. Access the source code

소개

이 랩에서는 Python 함수 인자 전달 규칙에 대해 배우게 됩니다. 또한 데이터 클래스에 재사용 가능한 구조를 만들고 객체 지향 설계 원칙을 적용하여 코드를 단순화할 것입니다.

이 연습의 목표는 stock.py 파일을 더 체계적인 방식으로 다시 작성하는 것입니다. 시작하기 전에, 참조용으로 stock.py의 기존 작업을 orig_stock.py라는 새 파일에 복사하십시오. 생성할 파일은 structure.pystock.py입니다.

함수 인자 전달 이해하기

Python 에서 함수는 특정 작업을 수행하기 위해 일련의 문을 함께 그룹화할 수 있게 해주는 기본적인 개념입니다. 함수를 호출할 때, 종종 인자라고 부르는 일부 데이터를 제공해야 합니다. Python 은 이러한 인자를 함수에 전달하는 다양한 방법을 제공합니다. 이러한 유연성은 더 깔끔하고 유지 관리하기 쉬운 코드를 작성하는 데 도움이 되므로 매우 유용합니다. 이러한 기술을 프로젝트에 적용하기 전에, 이러한 인자 전달 규칙을 자세히 살펴보겠습니다.

작업 백업 생성하기

stock.py 파일을 변경하기 전에 백업을 생성하는 것이 좋습니다. 이렇게 하면 실험 중에 문제가 발생하더라도 항상 원래 버전으로 돌아갈 수 있습니다. 백업을 생성하려면 터미널을 열고 다음 명령을 실행하십시오.

cp stock.py orig_stock.py

이 명령은 터미널에서 cp (복사) 명령을 사용합니다. stock.py 파일을 가져와 orig_stock.py라는 사본을 만듭니다. 이렇게 하면 원래 작업이 안전하게 보존됩니다.

함수 인자 전달 탐색하기

Python 에는 다양한 유형의 인자를 사용하여 함수를 호출하는 여러 가지 방법이 있습니다. 각 방법을 자세히 살펴보겠습니다.

1. 위치 인자 (Positional Arguments)

함수에 인자를 전달하는 가장 간단한 방법은 위치를 사용하는 것입니다. 함수를 정의할 때 매개변수 목록을 지정합니다. 함수를 호출할 때, 정의된 순서와 동일한 순서로 이러한 매개변수에 대한 값을 제공합니다.

다음은 예시입니다.

def calculate(x, y, z):
    return x + y + z

## 위치 인자로 호출
result = calculate(1, 2, 3)
print(result)  ## 출력: 6

이 예제에서 calculate 함수는 세 개의 매개변수 x, y, z를 받습니다. calculate(1, 2, 3)으로 함수를 호출하면 값 1x에 할당되고, 2y에 할당되고, 3z에 할당됩니다. 그런 다음 함수는 이러한 값을 더하여 결과를 반환합니다.

2. 키워드 인자 (Keyword Arguments)

위치 인자 외에도 이름으로 인자를 지정할 수도 있습니다. 이것을 키워드 인자를 사용한다고 합니다. 키워드 인자를 사용하면 인자의 순서에 대해 걱정할 필요가 없습니다.

다음은 예시입니다.

## 위치 인자와 키워드 인자를 혼합하여 호출
result = calculate(1, z=3, y=2)
print(result)  ## 출력: 6

이 예제에서는 먼저 x에 대한 위치 인자 1을 전달합니다. 그런 다음 키워드 인자를 사용하여 yz의 값을 지정합니다. 키워드 인자의 순서는 올바른 이름을 제공하는 한 중요하지 않습니다.

3. 시퀀스 및 딕셔너리 언패킹 (Unpacking Sequences and Dictionaries)

Python 은 *** 구문을 사용하여 시퀀스 및 딕셔너리를 인자로 전달하는 편리한 방법을 제공합니다. 이것을 언패킹이라고 합니다.

튜플을 위치 인자로 언패킹하는 예는 다음과 같습니다.

## 튜플을 위치 인자로 언패킹
args = (1, 2, 3)
result = calculate(*args)
print(result)  ## 출력: 6

이 예제에서는 값 1, 2, 3을 포함하는 튜플 args가 있습니다. 함수 호출에서 args 앞에 * 연산자를 사용하면 Python 은 튜플을 언패킹하고 해당 요소를 calculate 함수에 위치 인자로 전달합니다.

딕셔너리를 키워드 인자로 언패킹하는 예는 다음과 같습니다.

## 딕셔너리를 키워드 인자로 언패킹
kwargs = {'y': 2, 'z': 3}
result = calculate(1, **kwargs)
print(result)  ## 출력: 6

이 예제에서는 키 - 값 쌍 'y': 2'z': 3을 포함하는 딕셔너리 kwargs가 있습니다. 함수 호출에서 kwargs 앞에 ** 연산자를 사용하면 Python 은 딕셔너리를 언패킹하고 해당 키 - 값 쌍을 calculate 함수에 키워드 인자로 전달합니다.

4. 가변 인자 (Variable Arguments) 수락

때로는 임의의 수의 인자를 수락할 수 있는 함수를 정의하고 싶을 수 있습니다. Python 을 사용하면 함수 정의에서 *** 구문을 사용하여 이 작업을 수행할 수 있습니다.

임의의 수의 위치 인자를 수락하는 함수의 예는 다음과 같습니다.

## 임의의 수의 위치 인자 수락
def sum_all(*args):
    return sum(args)

print(sum_all(1, 2))           ## 출력: 3
print(sum_all(1, 2, 3, 4, 5))  ## 출력: 15

이 예제에서 sum_all 함수는 *args 매개변수를 사용하여 임의의 수의 위치 인자를 수락합니다. * 연산자는 모든 위치 인자를 args라는 튜플로 수집합니다. 그런 다음 함수는 내장 sum 함수를 사용하여 튜플의 모든 요소를 더합니다.

임의의 수의 키워드 인자를 수락하는 함수의 예는 다음과 같습니다.

## 임의의 수의 키워드 인자 수락
def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Python", year=1991)
## 출력:
## name: Python
## year: 1991

이 예제에서 print_info 함수는 **kwargs 매개변수를 사용하여 임의의 수의 키워드 인자를 수락합니다. ** 연산자는 모든 키워드 인자를 kwargs라는 딕셔너리로 수집합니다. 그런 다음 함수는 딕셔너리의 키 - 값 쌍을 반복하고 이를 출력합니다.

이러한 기술은 다음 단계에서 더 유연하고 재사용 가능한 코드 구조를 만드는 데 도움이 됩니다. 이러한 개념에 더 익숙해지려면 Python 인터프리터를 열고 이러한 예제를 시도해 보겠습니다.

python3

Python 인터프리터에 들어가면 위의 예제를 입력해 보십시오. 이렇게 하면 이러한 인자 전달 기술에 대한 실질적인 경험을 얻을 수 있습니다.

구조체 기본 클래스 생성하기

이제 함수 인자 전달에 대한 이해가 높아졌으므로, 데이터 구조에 재사용 가능한 기본 클래스를 만들 것입니다. 이 단계는 데이터를 저장하는 간단한 클래스를 만들 때 동일한 코드를 반복해서 작성하는 것을 피하는 데 도움이 되므로 매우 중요합니다. 기본 클래스를 사용하면 코드를 간소화하고 효율성을 높일 수 있습니다.

반복적인 코드의 문제점

이전 연습에서 아래와 같이 Stock 클래스를 정의했습니다.

class Stock:
    def __init__(self, name, shares, price):
        self.name = name
        self.shares = shares
        self.price = price

__init__ 메서드를 자세히 살펴보십시오. 매우 반복적이라는 것을 알 수 있습니다. 각 속성을 하나씩 수동으로 할당해야 합니다. 이는 특히 많은 속성을 가진 많은 클래스가 있는 경우 매우 지루하고 시간이 많이 걸릴 수 있습니다.

유연한 기본 클래스 생성하기

속성 할당을 자동으로 처리할 수 있는 Structure 기본 클래스를 만들어 보겠습니다. 먼저 WebIDE 를 열고 structure.py라는 새 파일을 만듭니다. 그런 다음 이 파일에 다음 코드를 추가합니다.

## structure.py

class Structure:
    """
    간단한 데이터 구조를 생성하기 위한 기본 클래스입니다.
    _fields 및 생성자 인자로부터 객체 속성을 자동으로 채웁니다.
    """
    _fields = ()

    def __init__(self, *args):
        ## 인자 수가 _fields 의 수와 일치하는지 확인합니다.
        if len(args) != len(self._fields):
            raise TypeError(f"Expected {len(self._fields)} arguments")

        ## 속성을 설정합니다.
        for name, value in zip(self._fields, args):
            setattr(self, name, value)

이 기본 클래스에는 몇 가지 중요한 기능이 있습니다.

  1. _fields 클래스 변수를 정의합니다. 기본적으로 이 변수는 비어 있습니다. 이 변수는 클래스가 가질 속성의 이름을 저장합니다.
  2. 생성자에 전달된 인자 수가 _fields에 정의된 필드 수와 일치하는지 확인합니다. 일치하지 않으면 TypeError를 발생시킵니다. 이는 오류를 조기에 감지하는 데 도움이 됩니다.
  3. 필드 이름과 인자로 제공된 값을 사용하여 객체의 속성을 설정합니다. setattr 함수는 속성을 동적으로 설정하는 데 사용됩니다.

구조체 기본 클래스 테스트하기

이제 Structure 기본 클래스에서 상속하는 몇 가지 예제 클래스를 만들어 보겠습니다. structure.py 파일에 다음 코드를 추가합니다.

## Structure 을 사용하는 예제 클래스
class Stock(Structure):
    _fields = ('name', 'shares', 'price')

class Point(Structure):
    _fields = ('x', 'y')

class Date(Structure):
    _fields = ('year', 'month', 'day')

구현이 제대로 작동하는지 테스트하기 위해 test_structure.py라는 테스트 파일을 만들겠습니다. 이 파일에 다음 코드를 추가합니다.

## test_structure.py
from structure import Stock, Point, Date

## Stock 클래스 테스트
s = Stock('GOOG', 100, 490.1)
print(f"Stock name: {s.name}, shares: {s.shares}, price: {s.price}")

## Point 클래스 테스트
p = Point(3, 4)
print(f"Point coordinates: ({p.x}, {p.y})")

## Date 클래스 테스트
d = Date(2023, 11, 9)
print(f"Date: {d.year}-{d.month}-{d.day}")

## 오류 처리 테스트
try:
    s2 = Stock('AAPL', 50)  ## price 인자 누락
    print("This should not print")
except TypeError as e:
    print(f"Error correctly caught: {e}")

테스트를 실행하려면 터미널을 열고 다음 명령을 실행합니다.

python3 test_structure.py

다음 출력이 표시되어야 합니다.

Stock name: GOOG, shares: 100, price: 490.1
Point coordinates: (3, 4)
Date: 2023-11-9
Error correctly caught: Expected 3 arguments

보시다시피 기본 클래스가 예상대로 작동합니다. 동일한 상용구 코드를 반복해서 작성하지 않고도 새로운 데이터 구조를 정의하는 것이 훨씬 쉬워졌습니다.

객체 표현 개선하기

Structure 클래스는 객체를 생성하고 액세스하는 데 유용합니다. 그러나 현재 문자열로 자체를 표현하는 좋은 방법이 없습니다. 객체를 인쇄하거나 Python 인터프리터에서 볼 때, 명확하고 유익한 표시를 보고 싶을 것입니다. 이는 객체가 무엇이고 해당 값이 무엇인지 이해하는 데 도움이 됩니다.

Python 의 객체 표현 이해하기

Python 에는 객체를 다양한 방식으로 표현하는 데 사용되는 두 가지 특수 메서드가 있습니다. 이러한 메서드는 객체가 표시되는 방식을 제어할 수 있으므로 중요합니다.

  • __str__ - 이 메서드는 str() 함수와 print() 함수에서 사용됩니다. 객체의 사람이 읽을 수 있는 표현을 제공합니다. 예를 들어, Stock 객체가 있는 경우 __str__ 메서드는 "Stock: GOOG, 100 shares at $490.1"과 같은 것을 반환할 수 있습니다.
  • __repr__ - 이 메서드는 Python 인터프리터와 repr() 함수에서 사용됩니다. 객체의 보다 기술적이고 명확한 표현을 제공합니다. __repr__의 목표는 객체를 다시 만들 수 있는 문자열을 제공하는 것입니다. 예를 들어, Stock 객체의 경우 "Stock('GOOG', 100, 490.1)"을 반환할 수 있습니다.

Structure 클래스에 __repr__ 메서드를 추가해 보겠습니다. 이렇게 하면 객체의 상태를 명확하게 볼 수 있으므로 코드를 디버깅하기가 더 쉬워집니다.

좋은 표현 구현하기

이제 structure.py 파일을 업데이트해야 합니다. __repr__ 메서드를 Structure 클래스에 추가합니다. 이 메서드는 객체를 다시 만드는 데 사용할 수 있는 방식으로 객체를 나타내는 문자열을 생성합니다.

def __repr__(self):
    """
    객체를 다시 만드는 데 사용할 수 있는 객체의 표현을 반환합니다.
    예: Stock('GOOG', 100, 490.1)
    """
    ## 클래스 이름 가져오기
    cls_name = type(self).__name__

    ## 모든 필드 값 가져오기
    values = [getattr(self, name) for name in self._fields]

    ## 필드와 값의 형식 지정
    args_str = ', '.join(repr(value) for value in values)

    ## 형식 지정된 문자열 반환
    return f"{cls_name}({args_str})"

다음은 이 메서드가 수행하는 단계별 작업입니다.

  1. type(self).__name__을 사용하여 클래스 이름을 가져옵니다. 이는 처리하고 있는 객체의 종류를 알려주므로 중요합니다.
  2. 인스턴스에서 모든 필드 값을 검색합니다. 이를 통해 객체가 보유한 데이터를 얻을 수 있습니다.
  3. 클래스 이름과 값을 사용하여 문자열 표현을 생성합니다. 이 문자열은 객체를 다시 만드는 데 사용할 수 있습니다.

개선된 표현 테스트하기

향상된 구현을 테스트해 보겠습니다. test_repr.py라는 새 파일을 만듭니다. 이 파일은 클래스의 일부 인스턴스를 생성하고 해당 표현을 인쇄합니다.

## test_repr.py
from structure import Stock, Point, Date

## 인스턴스 생성
s = Stock('GOOG', 100, 490.1)
p = Point(3, 4)
d = Date(2023, 11, 9)

## 표현 인쇄
print(repr(s))
print(repr(p))
print(repr(d))

## 직접 인쇄도 인터프리터에서 __repr__을 사용합니다.
print(s)
print(p)
print(d)

테스트를 실행하려면 터미널을 열고 다음 명령을 입력합니다.

python3 test_repr.py

다음 출력이 표시되어야 합니다.

Stock('GOOG', 100, 490.1)
Point(3, 4)
Date(2023, 11, 9)
Stock('GOOG', 100, 490.1)
Point(3, 4)
Date(2023, 11, 9)

이 출력은 이전보다 훨씬 더 유익합니다. Stock('GOOG', 100, 490.1)을 보면 객체가 무엇을 나타내는지 즉시 알 수 있습니다. 이 문자열을 복사하여 코드에서 객체를 다시 만드는 데 사용할 수도 있습니다.

좋은 표현의 이점

좋은 __repr__ 구현은 디버깅에 매우 유용합니다. 인터프리터에서 객체를 보거나 프로그램 실행 중에 로깅할 때, 명확한 표현은 문제를 빠르게 식별하는 데 도움이 됩니다. 객체의 정확한 상태를 확인하고 무엇이 잘못될 수 있는지 이해할 수 있습니다.

속성 이름 제한하기

현재 Structure 클래스는 인스턴스에 모든 속성을 설정할 수 있습니다. 초보자에게는 처음에는 편리해 보일 수 있지만, 실제로 많은 문제를 야기할 수 있습니다. 클래스를 사용할 때는 특정 속성이 존재하고 특정 방식으로 사용될 것으로 예상합니다. 사용자가 속성 이름을 잘못 입력하거나 원래 설계에 포함되지 않은 속성을 설정하려고 하면 찾기 어려운 오류가 발생할 수 있습니다.

속성 제한의 필요성

속성 이름을 제한해야 하는 이유를 이해하기 위해 간단한 시나리오를 살펴보겠습니다. 다음 코드를 고려하십시오.

s = Stock('GOOG', 100, 490.1)
s.shares = 50      ## 올바른 속성 이름
s.share = 60       ## 속성 이름의 오타 - 업데이트 대신 새 속성 생성

두 번째 줄에 오타가 있습니다. shares 대신 share를 작성했습니다. Python 에서는 오류를 발생시키는 대신 share라는 새 속성을 생성합니다. 이는 shares 속성을 업데이트하고 있다고 생각하지만 실제로 새 속성을 생성하고 있을 수 있으므로 미묘한 버그로 이어질 수 있습니다. 이로 인해 코드가 예기치 않게 동작하고 디버깅하기가 매우 어려울 수 있습니다.

속성 제한 구현하기

이 문제를 해결하기 위해 __setattr__ 메서드를 재정의할 수 있습니다. 이 메서드는 객체에 속성을 설정하려고 할 때마다 호출됩니다. 이를 재정의하여 어떤 속성을 설정할 수 있고 어떤 속성을 설정할 수 없는지 제어할 수 있습니다.

structure.pyStructure 클래스를 다음 코드로 업데이트하십시오.

def __setattr__(self, name, value):
    """
    속성 설정을 _fields 에 정의된 속성 또는 밑줄로 시작하는 속성 (private 속성) 으로 제한합니다.
    """
    if name.startswith('_'):
        ## private 속성 설정 허용 (_로 시작)
        super().__setattr__(name, value)
    elif name in self._fields:
        ## _fields 에 정의된 속성 설정 허용
        super().__setattr__(name, value)
    else:
        ## 다른 속성에 대해 오류 발생
        raise AttributeError(f'No attribute {name}')

이 메서드의 작동 방식은 다음과 같습니다.

  1. 속성 이름이 밑줄 (_) 로 시작하는 경우, 이는 private 속성으로 간주됩니다. Private 속성은 종종 클래스 내부적인 목적으로 사용됩니다. 이러한 속성은 클래스의 내부 구현의 일부이므로 설정하도록 허용합니다.
  2. 속성 이름이 _fields 목록에 있는 경우, 이는 클래스 설계에 정의된 속성 중 하나임을 의미합니다. 이러한 속성은 클래스의 예상된 동작의 일부이므로 설정하도록 허용합니다.
  3. 속성 이름이 이러한 조건 중 어느 것도 충족하지 않는 경우, AttributeError를 발생시킵니다. 이는 사용자에게 클래스에 존재하지 않는 속성을 설정하려고 한다는 것을 알려줍니다.

속성 제한 테스트하기

이제 속성 제한을 구현했으므로 예상대로 작동하는지 테스트해 보겠습니다. 다음 코드로 test_attributes.py라는 파일을 만듭니다.

## test_attributes.py
from structure import Stock

s = Stock('GOOG', 100, 490.1)

## 이것은 작동해야 합니다 - 유효한 속성
print("Setting shares to 50")
s.shares = 50
print(f"Shares is now: {s.shares}")

## 이것은 작동해야 합니다 - private 속성
print("\nSetting _internal_data")
s._internal_data = "Some data"
print(f"_internal_data is: {s._internal_data}")

## 이것은 실패해야 합니다 - 유효하지 않은 속성
print("\nTrying to set an invalid attribute:")
try:
    s.share = 60  ## 속성 이름의 오타
    print("This should not print")
except AttributeError as e:
    print(f"Error correctly caught: {e}")

테스트를 실행하려면 터미널을 열고 다음 명령을 입력합니다.

python3 test_attributes.py

다음 출력이 표시되어야 합니다.

Setting shares to 50
Shares is now: 50

Setting _internal_data
_internal_data is: Some data

Trying to set an invalid attribute:
Error correctly caught: No attribute share

이 출력은 이제 클래스가 우발적인 속성 오류를 방지함을 보여줍니다. 유효한 속성과 private 속성을 설정할 수 있지만, 유효하지 않은 속성을 설정하려고 하면 오류가 발생합니다.

속성 제한의 가치

속성 이름 제한은 견고하고 유지 관리 가능한 코드를 작성하는 데 매우 중요합니다. 그 이유는 다음과 같습니다.

  1. 속성 이름의 오타를 잡는 데 도움이 됩니다. 속성 이름을 입력할 때 실수를 하면 새 속성을 생성하는 대신 코드가 오류를 발생시킵니다. 이렇게 하면 개발 프로세스 초기에 오류를 찾고 수정하기가 더 쉬워집니다.
  2. 클래스 설계에 존재하지 않는 속성을 설정하려는 시도를 방지합니다. 이렇게 하면 클래스가 의도한 대로 사용되고 코드가 예측 가능하게 동작하도록 보장합니다.
  3. 새로운 속성의 우발적인 생성을 방지합니다. 새로운 속성을 생성하면 예기치 않은 동작이 발생하고 코드를 이해하고 유지 관리하기가 더 어려워질 수 있습니다.

속성 이름을 제한함으로써 코드를 더 신뢰할 수 있고 사용하기 쉽게 만듭니다.

Stock 클래스 다시 작성하기

이제 잘 정의된 Structure 기본 클래스가 있으므로 Stock 클래스를 다시 작성할 차례입니다. 이 기본 클래스를 사용하면 코드를 단순화하고 더 체계적으로 만들 수 있습니다. Structure 클래스는 Stock 클래스에서 재사용할 수 있는 일련의 공통 기능을 제공하며, 이는 코드 유지 관리 및 가독성에 큰 이점을 제공합니다.

새 Stock 클래스 만들기

stock.py라는 새 파일을 만들어 보겠습니다. 이 파일에는 다시 작성된 Stock 클래스가 포함됩니다. 다음은 stock.py 파일에 넣어야 하는 코드입니다.

## stock.py
from structure import Structure

class Stock(Structure):
    _fields = ('name', 'shares', 'price')

    @property
    def cost(self):
        """
        주식 * 가격으로 비용을 계산합니다.
        """
        return self.shares * self.price

    def sell(self, nshares):
        """
        일정 수의 주식을 판매합니다.
        """
        self.shares -= nshares

이 새로운 Stock 클래스가 수행하는 작업을 자세히 살펴보겠습니다.

  1. Structure 클래스에서 상속합니다. 즉, Stock 클래스는 Structure 클래스에서 제공하는 모든 기능을 사용할 수 있습니다. 한 가지 이점은 Structure 클래스가 속성 할당을 자동으로 처리하므로 __init__ 메서드를 직접 작성할 필요가 없다는 것입니다.
  2. Stock 클래스의 속성을 지정하는 튜플인 _fields를 정의합니다. 이러한 속성은 name, sharesprice입니다.
  3. cost 속성은 주식의 총 비용을 계산하도록 정의됩니다. shares 수에 price를 곱합니다.
  4. sell 메서드는 주식 수를 줄이는 데 사용됩니다. 판매할 주식 수를 사용하여 이 메서드를 호출하면 현재 주식 수에서 해당 수를 뺍니다.

새 Stock 클래스 테스트하기

Stock 클래스가 예상대로 작동하는지 확인하기 위해 테스트 파일을 만들어야 합니다. 다음 코드로 test_stock.py라는 파일을 만들어 보겠습니다.

## test_stock.py
from stock import Stock

## 주식 생성
s = Stock('GOOG', 100, 490.1)

## 속성 확인
print(f"Stock: {s}")
print(f"Name: {s.name}")
print(f"Shares: {s.shares}")
print(f"Price: {s.price}")
print(f"Cost: {s.cost}")

## 일부 주식 판매
print("\nSelling 20 shares...")
s.sell(20)
print(f"Shares after selling: {s.shares}")
print(f"Cost after selling: {s.cost}")

## 유효하지 않은 속성을 설정하려고 시도
print("\nTrying to set an invalid attribute:")
try:
    s.prices = 500  ## 유효하지 않은 속성 ('price'여야 함)
    print("This should not print")
except AttributeError as e:
    print(f"Error correctly caught: {e}")

이 테스트 파일에서는 먼저 stock.py 파일에서 Stock 클래스를 가져옵니다. 그런 다음 이름 'GOOG', 100 주, 가격 490.1 로 Stock 클래스의 인스턴스를 만듭니다. 주식의 속성을 인쇄하여 올바르게 설정되었는지 확인합니다. 그 후, 20 주를 판매하고 새로운 주식 수와 새로운 비용을 인쇄합니다. 마지막으로, 유효하지 않은 속성 prices를 설정하려고 합니다 (이것은 price여야 합니다). Stock 클래스가 올바르게 작동하면 AttributeError를 발생시켜야 합니다.

테스트를 실행하려면 터미널을 열고 다음 명령을 입력합니다.

python3 test_stock.py

예상 출력은 다음과 같습니다.

Stock: Stock('GOOG', 100, 490.1)
Name: GOOG
Shares: 100
Price: 490.1
Cost: 49010.0

Selling 20 shares...
Shares after selling: 80
Cost after selling: 39208.0

Trying to set an invalid attribute:
Error correctly caught: No attribute prices

단위 테스트 실행하기

이전 연습에서 단위 테스트가 있는 경우 새 구현에 대해 실행할 수 있습니다. 터미널에서 다음 명령을 입력합니다.

python3 teststock.py

일부 테스트가 실패할 수 있습니다. 이는 아직 구현하지 않은 특정 동작이나 메서드를 예상하기 때문일 수 있습니다. 걱정하지 마세요! 향후 연습에서 이 기반을 계속 구축할 것입니다.

진행 상황 검토

지금까지 달성한 내용을 잠시 검토해 보겠습니다.

  1. 재사용 가능한 Structure 기본 클래스를 만들었습니다. 이 클래스는 다음과 같습니다.

    • 속성 할당을 자동으로 처리하여 많은 반복적인 코드를 작성하지 않아도 됩니다.
    • 객체를 인쇄하고 디버깅하기 쉽게 만드는 좋은 문자열 표현을 제공합니다.
    • 오류를 방지하기 위해 속성 이름을 제한하여 코드를 더욱 강력하게 만듭니다.
  2. Stock 클래스를 다시 작성했습니다. 다음은 다음과 같습니다.

    • 공통 기능을 재사용하기 위해 Structure 클래스에서 상속합니다.
    • 필드 및 도메인 관련 메서드만 정의하여 클래스를 집중적이고 깔끔하게 유지합니다.
    • 명확하고 단순한 설계를 통해 이해하고 유지 관리하기 쉽습니다.

이 접근 방식은 코드에 몇 가지 이점이 있습니다.

  • 반복이 줄어들기 때문에 유지 관리가 더 용이합니다. 공통 기능에서 변경해야 하는 경우 Structure 클래스에서만 변경하면 됩니다.
  • Structure 클래스에서 제공하는 더 나은 오류 검사로 인해 더 강력합니다.
  • 각 클래스의 책임이 명확하기 때문에 가독성이 더 좋습니다.

향후 연습에서는 이 기반을 계속 구축하여 보다 정교한 주식 포트폴리오 관리 시스템을 만들 것입니다.

요약

이 랩에서는 Python 의 함수 인자 전달 규칙에 대해 배우고 이를 적용하여 더 체계적이고 유지 관리 가능한 코드베이스를 구축했습니다. Python 의 유연한 인자 전달 메커니즘을 탐구하고, 데이터 객체를 위한 재사용 가능한 Structure 기본 클래스를 만들었으며, 더 나은 디버깅을 위해 객체 표현을 개선했습니다.

또한 일반적인 오류를 방지하기 위해 속성 유효성 검사를 추가하고 새로운 구조를 사용하여 Stock 클래스를 다시 작성했습니다. 이러한 기술은 코드 재사용을 위한 상속, 데이터 무결성을 위한 캡슐화, 공통 인터페이스를 통한 다형성과 같은 주요 객체 지향 설계 원칙을 보여줍니다. 이러한 원칙을 적용하여 반복을 줄이고 오류를 줄여 더욱 강력하고 유지 관리 가능한 코드를 개발할 수 있습니다.