소개
이 랩에서는 Python 의 속성 접근에 대해 배우게 됩니다. getattr() 및 setattr()과 같은 함수를 사용하여 객체 속성을 효과적으로 조작하는 방법을 탐구할 것입니다.
또한, 바운드 메서드 (bound methods) 를 실험해 볼 것입니다. 이 랩은 이러한 개념들을 안내하며, 과정에서 tableformat.py라는 파일을 생성하게 됩니다.
이 랩에서는 Python 의 속성 접근에 대해 배우게 됩니다. getattr() 및 setattr()과 같은 함수를 사용하여 객체 속성을 효과적으로 조작하는 방법을 탐구할 것입니다.
또한, 바운드 메서드 (bound methods) 를 실험해 볼 것입니다. 이 랩은 이러한 개념들을 안내하며, 과정에서 tableformat.py라는 파일을 생성하게 됩니다.
Python 에서 객체는 기본적인 개념입니다. 객체는 값을 위한 명명된 컨테이너와 같은 속성에 데이터를 저장할 수 있습니다. 속성을 객체에 속하는 변수라고 생각할 수 있습니다. 이러한 속성에 접근하는 방법에는 여러 가지가 있습니다. 가장 간단하고 일반적으로 사용되는 방법은 점 (.) 표기법입니다. 그러나 Python 은 속성 작업 시 더 많은 유연성을 제공하는 특정 함수도 제공합니다.
Stock 객체를 생성하고 점 표기법을 사용하여 속성을 조작하는 방법을 살펴보겠습니다. 점 표기법은 객체의 속성에 접근하고 수정하는 간단하고 직관적인 방법입니다.
먼저, 새 터미널을 열고 Python 대화형 셸을 시작합니다. 여기에서 Python 코드를 한 줄씩 작성하고 실행할 수 있습니다.
## Open a new terminal and run Python interactive shell
python3
## Import the Stock class from the stock module
from stock import Stock
## Create a Stock object
s = Stock('GOOG', 100, 490.1)
## Get an attribute
print(s.name) ## Output: 'GOOG'
## Set an attribute
s.shares = 50
print(s.shares) ## Output: 50
## Delete an attribute
del s.shares
## If we try to access s.shares now, we'll get an AttributeError
위 코드에서 먼저 stock 모듈에서 Stock 클래스를 가져옵니다. 그런 다음 s라는 Stock 클래스의 인스턴스를 생성합니다. name 속성의 값을 가져오려면 s.name을 사용합니다. shares 속성의 값을 변경하려면 단순히 s.shares에 새 값을 할당합니다. 그리고 속성을 제거하려면 del 키워드 다음에 속성 이름을 사용합니다.
Python 은 속성 조작에 매우 유용한 네 가지 내장 함수를 제공합니다. 이러한 함수는 특히 속성을 동적으로 처리해야 할 때 속성 작업 시 더 많은 제어를 제공합니다.
getattr() - 이 함수는 속성의 값을 가져오는 데 사용됩니다.setattr() - 속성의 값을 설정할 수 있습니다.delattr() - 이 함수를 사용하여 속성을 삭제할 수 있습니다.hasattr() - 이 함수는 객체에 속성이 있는지 확인합니다.이러한 함수를 사용하는 방법을 살펴보겠습니다.
## Create a new Stock object
s = Stock('GOOG', 100, 490.1)
## Get an attribute
print(getattr(s, 'name')) ## Output: 'GOOG'
## Set an attribute
setattr(s, 'shares', 50)
print(s.shares) ## Output: 50
## Check if an attribute exists
print(hasattr(s, 'name')) ## Output: True
print(hasattr(s, 'symbol')) ## Output: False
## Delete an attribute
delattr(s, 'shares')
print(hasattr(s, 'shares')) ## Output: False
이러한 함수는 특히 속성을 동적으로 작업해야 할 때 유용합니다. 하드 코딩된 속성 이름 대신 변수 이름을 사용할 수 있습니다. 예를 들어, 속성 이름을 저장하는 변수가 있는 경우 해당 변수를 이러한 함수에 전달하여 해당 속성에 대한 작업을 수행할 수 있습니다. 이를 통해 코드에서 더 많은 유연성을 얻을 수 있으며, 특히 다양한 객체와 속성을 보다 동적으로 처리할 때 유용합니다.
getattr() 함수는 Python 에서 객체의 속성에 동적으로 접근할 수 있게 해주는 강력한 도구입니다. 이는 객체를 일반적인 방식으로 처리하려는 경우 특히 유용합니다. 특정 객체 유형에 특정한 코드를 작성하는 대신, getattr()을 사용하여 필요한 속성이 있는 모든 객체로 작업할 수 있습니다. 이러한 유연성은 코드를 더 재사용 가능하고 적응 가능하게 만듭니다.
getattr() 함수를 사용하여 객체의 여러 속성에 접근하는 방법을 먼저 배우겠습니다. 이는 객체에서 특정 정보를 추출해야 할 때 일반적인 시나리오입니다.
먼저, 이전 셸을 닫았다면 Python 대화형 셸을 엽니다. 터미널에서 다음 명령을 실행하여 이 작업을 수행할 수 있습니다.
## Open a Python interactive shell if you closed the previous one
python3
다음으로, Stock 클래스를 가져오고 Stock 객체를 생성합니다. Stock 클래스는 name, shares, price와 같은 속성을 가진 주식을 나타냅니다.
## Import the Stock class and create a stock object
from stock import Stock
s = Stock('GOOG', 100, 490.1)
이제 접근하려는 속성 이름 목록을 정의합니다. 이 목록은 속성을 반복하고 해당 값을 출력하는 데 도움이 됩니다.
## Define a list of attribute names
fields = ['name', 'shares', 'price']
마지막으로, for 루프를 사용하여 속성 이름 목록을 반복하고 getattr()을 사용하여 각 속성에 접근합니다. 각 반복에 대해 속성 이름과 해당 값을 출력합니다.
## Access each attribute using getattr()
for name in fields:
print(f"{name}: {getattr(s, 'name')}" if name == 'name' else f"{name}: {getattr(s, name)}")
이 코드를 실행하면 다음과 같은 출력이 표시됩니다.
name: GOOG
shares: 100
price: 490.1
이 출력은 getattr() 함수를 사용하여 Stock 객체의 여러 속성의 값에 접근하고 출력할 수 있음을 보여줍니다.
getattr() 함수는 또한 유용한 기능을 제공합니다. 즉, 접근하려는 속성이 존재하지 않는 경우 기본값을 지정하는 기능입니다. 이는 코드에서 AttributeError가 발생하지 않도록 하고 코드를 더 강력하게 만들 수 있습니다.
이것이 어떻게 작동하는지 살펴보겠습니다. 먼저, Stock 객체에 존재하지 않는 속성에 접근하려고 합니다. getattr()을 사용하고 기본값 'N/A'를 제공합니다.
## Try to access an attribute that doesn't exist
print(getattr(s, 'symbol', 'N/A')) ## Output: 'N/A'
이 경우, symbol 속성이 Stock 객체에 존재하지 않으므로 getattr()은 기본값 'N/A'를 반환합니다.
이제 이것을 기존 속성에 접근하는 것과 비교해 보겠습니다. Stock 객체에 존재하는 name 속성에 접근합니다.
## Compare with an existing attribute
print(getattr(s, 'name', 'N/A')) ## Output: 'GOOG'
여기서 getattr()은 name 속성의 실제 값인 'GOOG'를 반환합니다.
getattr() 함수는 객체 모음을 처리해야 할 때 더욱 강력해집니다. 이를 사용하여 주식 포트폴리오를 처리하는 방법을 살펴보겠습니다.
먼저, stock 모듈에서 read_portfolio 함수를 가져옵니다. 이 함수는 CSV 파일에서 주식 포트폴리오를 읽고 Stock 객체 목록을 반환합니다.
## Import the portfolio reading function
from stock import read_portfolio
다음으로, read_portfolio 함수를 사용하여 portfolio.csv라는 CSV 파일에서 포트폴리오를 읽습니다.
## Read the portfolio from CSV file
portfolio = read_portfolio('portfolio.csv')
마지막으로, for 루프를 사용하여 포트폴리오의 Stock 객체 목록을 반복합니다. 각 주식에 대해 getattr()을 사용하여 name 및 shares 속성에 접근하고 해당 값을 출력합니다.
## Print the name and shares of each stock
for stock in portfolio:
print(f"Stock: {getattr(stock, 'name')}, Shares: {getattr(stock, 'shares')}")
이 접근 방식은 속성 이름을 문자열로 사용할 수 있으므로 코드를 더 유연하게 만듭니다. 이러한 문자열은 인수로 전달되거나 데이터 구조에 저장될 수 있으므로 코드의 핵심 로직을 수정하지 않고도 접근하려는 속성을 쉽게 변경할 수 있습니다.
프로그래밍에서 속성 접근은 객체의 속성과 상호 작용할 수 있게 해주는 기본적인 개념입니다. 이제 속성 접근에 대해 배운 내용을 실습해 보겠습니다. 유용한 유틸리티인 테이블 포맷터를 만들 것입니다. 이 포맷터는 객체 모음을 가져와 표 형식으로 표시하여 데이터를 더 쉽게 읽고 이해할 수 있도록 합니다.
먼저, 새 Python 파일을 만들어야 합니다. 이 파일에는 테이블 포맷터에 대한 코드가 포함됩니다.
파일을 만들려면 다음 단계를 따르세요.
/home/labex/project/ 디렉토리에 tableformat.py로 저장합니다.이제 파일이 있으므로 tableformat.py 내부에 print_table() 함수에 대한 코드를 작성해 보겠습니다. 이 함수는 객체를 테이블 형식으로 서식 지정하고 인쇄하는 역할을 합니다.
def print_table(objects, fields):
"""
Print a collection of objects as a formatted table.
Args:
objects: A sequence of objects
fields: A list of attribute names
"""
## Print the header
headers = fields
for header in headers:
print(f"{header:>10}", end=' ')
print()
## Print the separator line
for header in headers:
print("-" * 10, end=' ')
print()
## Print the data
for obj in objects:
for field in fields:
value = getattr(obj, field)
print(f"{value:>10}", end=' ')
print()
이 함수가 수행하는 작업을 자세히 살펴보겠습니다.
getattr() 함수를 사용하여 각 객체의 속성 값에 접근합니다.이제 print_table() 함수가 예상대로 작동하는지 테스트해 보겠습니다.
## Open a Python interactive shell
python3
## Import our modules
from stock import read_portfolio
import tableformat
## Read the portfolio data
portfolio = read_portfolio('portfolio.csv')
## Print the portfolio as a table with name, shares, and price columns
tableformat.print_table(portfolio, ['name', 'shares', 'price'])
위 코드를 실행하면 다음과 같은 출력이 표시됩니다.
name shares price
---------- ---------- ----------
AA 100 32.2
IBM 50 91.1
CAT 150 83.44
MSFT 200 51.23
GE 95 40.37
MSFT 50 65.1
IBM 100 70.44
print_table() 함수의 가장 큰 장점 중 하나는 유연성입니다. fields 목록을 변경하기만 하면 표시되는 열을 변경할 수 있습니다.
## Just show shares and name
tableformat.print_table(portfolio, ['shares', 'name'])
이 코드를 실행하면 다음과 같은 출력이 생성됩니다.
shares name
---------- ----------
100 AA
50 IBM
150 CAT
200 MSFT
95 GE
50 MSFT
100 IBM
이 접근 방식의 강력함은 일반성에 있습니다. 표시하려는 속성 이름을 알고 있는 한, 동일한 print_table() 함수를 사용하여 모든 유형의 객체에 대한 테이블을 인쇄할 수 있습니다. 이는 테이블 포맷터를 프로그래밍 도구 상자에서 매우 유용한 도구로 만듭니다.
Python 에서 메서드는 호출할 수 있는 특별한 유형의 속성입니다. 객체를 통해 메서드에 접근할 때, 우리는 이를 "바운드 메서드 (bound method)"라고 부릅니다. 바운드 메서드는 본질적으로 특정 객체에 연결된 메서드입니다. 즉, 객체의 데이터에 접근하여 해당 데이터를 조작할 수 있습니다.
Stock 클래스를 사용하여 바운드 메서드를 탐색해 보겠습니다. 먼저, 객체의 속성으로 메서드에 접근하는 방법을 살펴보겠습니다.
## Open a Python interactive shell
python3
## Import the Stock class and create a stock object
from stock import Stock
s = Stock('GOOG', 100, 490.10)
## Access the cost method without calling it
cost_method = s.cost
print(cost_method) ## Output: <bound method Stock.cost of <stock.Stock object at 0x...>>
## Call the method
result = cost_method()
print(result) ## Output: 49010.0
## You can also do this in one step
print(s.cost()) ## Output: 49010.0
위 코드에서 먼저 Stock 클래스를 가져와서 인스턴스를 생성합니다. 그런 다음 실제로 호출하지 않고 s 객체의 cost 메서드에 접근합니다. 이렇게 하면 바운드 메서드가 생성됩니다. 이 바운드 메서드를 호출하면 객체의 데이터를 기반으로 비용을 계산합니다. 또한 한 단계로 객체에서 메서드를 직접 호출할 수도 있습니다.
메서드에 접근하는 또 다른 방법은 getattr() 함수를 사용하는 것입니다. 이 함수를 사용하면 이름으로 객체의 속성을 가져올 수 있습니다.
## Get the cost method using getattr
cost_method = getattr(s, 'cost')
print(cost_method) ## Output: <bound method Stock.cost of <stock.Stock object at 0x...>>
## Call the method
result = cost_method()
print(result) ## Output: 49010.0
## Get and call in one step
result = getattr(s, 'cost')()
print(result) ## Output: 49010.0
여기서는 getattr()을 사용하여 s 객체에서 cost 메서드를 가져옵니다. 이전과 마찬가지로 바운드 메서드를 호출하여 결과를 얻을 수 있습니다. 그리고 한 줄로 메서드를 가져와 호출할 수도 있습니다.
바운드 메서드는 항상 접근한 객체에 대한 참조를 유지합니다. 즉, 메서드를 변수에 저장하더라도, 해당 메서드가 속한 객체를 알고 있으며 객체의 데이터에 접근할 수 있습니다.
## Store the cost method in a variable
c = s.cost
## Call the method
print(c()) ## Output: 49010.0
## Change the object's state
s.shares = 75
## Call the method again - it sees the updated state
print(c()) ## Output: 36757.5
이 예제에서는 cost 메서드를 변수 c에 저장합니다. c()를 호출하면 객체의 현재 데이터를 기반으로 비용을 계산합니다. 그런 다음 s 객체의 shares 속성을 변경합니다. c()를 다시 호출하면 업데이트된 데이터를 사용하여 새로운 비용을 계산합니다.
바운드 메서드에는 이에 대한 더 많은 정보를 제공하는 두 가지 중요한 속성이 있습니다.
__self__: 이 속성은 메서드가 바인딩된 객체를 참조합니다.__func__: 이 속성은 메서드를 나타내는 실제 함수 객체입니다.## Get the cost method
c = s.cost
## Examine the bound method attributes
print(c.__self__) ## Output: <stock.Stock object at 0x...>
print(c.__func__) ## Output: <function Stock.cost at 0x...>
## You can manually call the function with the object
print(c.__func__(c.__self__)) ## Output: 36757.5 (same as c())
여기서는 바운드 메서드 c의 __self__ 및 __func__ 속성에 접근합니다. __self__가 s 객체이고 __func__가 cost 함수임을 알 수 있습니다. 객체를 인수로 전달하여 함수를 수동으로 호출할 수도 있으며, 이는 바운드 메서드를 직접 호출하는 것과 동일한 결과를 제공합니다.
sell() 메서드와 같이 인수를 사용하는 메서드에서 바운드 메서드가 어떻게 작동하는지 살펴보겠습니다.
## Get the sell method
sell_method = s.sell
## Examine the method
print(sell_method) ## Output: <bound method Stock.sell of <stock.Stock object at 0x...>>
## Call the method with an argument
sell_method(25)
print(s.shares) ## Output: 50
## Call the method manually using __func__ and __self__
sell_method.__func__(sell_method.__self__, 10)
print(s.shares) ## Output: 40
이 예제에서는 sell 메서드를 바운드 메서드로 가져옵니다. 인수를 사용하여 호출하면 s 객체의 shares 속성이 업데이트됩니다. 또한 __func__ 및 __self__ 속성을 사용하여 인수를 전달하여 메서드를 수동으로 호출할 수도 있습니다.
바운드 메서드를 이해하면 Python 의 객체 시스템이 내부적으로 어떻게 작동하는지 이해하는 데 도움이 되며, 이는 디버깅, 메타 프로그래밍 및 고급 프로그래밍 패턴을 만드는 데 유용할 수 있습니다.
이 랩에서는 Python 의 속성 접근 시스템과 그 기본 메커니즘에 대해 배웠습니다. 이제 점 표기법과 getattr(), setattr(), delattr(), hasattr()와 같은 함수를 사용하여 객체 속성에 접근하는 방법을 알고 있습니다. 또한 일반적이고 유연한 객체 처리를 위해 getattr()을 사용하는 방법과 모든 객체 모음에 대한 테이블 포맷터를 만드는 방법을 이해했습니다.
또한 바운드 메서드 (bound method) 의 개념과 바운드 메서드가 객체와의 연결을 유지하는 방식을 이해했습니다. 이러한 기본적인 개념은 인트로스펙션 (introspection, 내성), 리플렉션 (reflection, 반사), 메타 프로그래밍 (metaprogramming) 과 같은 고급 Python 프로그래밍 기술에 매우 중요합니다. 속성 접근을 이해하면 다양한 객체 유형을 처리할 수 있는 더 유연하고 강력한 코드를 작성할 수 있습니다.