본문 바로가기
  • Hello_
Python

[Python] sys.modules, __getattr__, __setattr__ 활용하기

by LDwDL 2023. 2. 11.
728x90
반응형

본 포스팅에서는 sys.modules, __getattr__, __setattr__을 활용하여 모듈의 속성을 다뤄보고자 한다.

 

sys.modules[__name__]

우선 현재 사용하고 있는 모듈을 객체(object)로 가져와보자.

import sys

now_module = sys.modules[__name__]
print(now_module) # <module '__main__'>

 

__name__은 파이썬에서 현재 모듈의 이름을 문자열로 반환하는 내장 변수이며, sys.modules[__name__]은 파이썬에서 현재 모듈에 대한 참조이다. 

 

sys.modules dict에 __name__ 값으로 접근하면 현재 모듈의 모듈 객체에 대한 참조를 얻을 수 있다. 이는 모듈의 속성을 추가하거나 수정하거나 모듈 내에서 다른 모듈을 가져오는 등의 목적으로 사용될 수 있으므로 우선 현재 사용하고 있는 모듈을 'now_module'로 선언했다. 

 

getattr

getattr과 setattr은 각각 객체의 속성 값을 가져오고 설정할 수 있게 해주는 파이썬에 내장된 함수이다.

getattr(object, name[, default])개체의 명명된 속성 값을 검색하는 데 사용되며, 명명된 특성이 없으면 default 인수에 지정된 값을 반환한다 (기본값이 제공되지 않으면 AttributeError가 발생).

 

이는 예시를 통해 진행하고자 한다.

getattr(now_module,'np')
"""
--------------------------------------------------------------------------- 
AttributeError Traceback (most recent call last)
 /aidata/lung/WORKSPACE/workspace_s/deep-lung-ln-02_v2/nodulenet/_.ipynb Cell 57 in <cell line: 1>() 
----> 1 getattr(now_module,'np’) 

AttributeError: module '__main__' has no attribute 'np'
"""

 

현재 사용하고 있는 모듈에서는 np라는 속성이 선언되지 않아서 오류가 발생한다.

 

하지만 import numpy as np를 해당 모듈에 선언을 해주어 np라는 속성값을 추가해 주면 잘 인식이 된다.

import numpy as np

getattr(now_module,'np')
"""
<module 'numpy' from '/home/soobumk/.conda/envs/soobumk/lib/python3.9/site-packages/numpy/__init__.py'>
"""

 

다른 속성값도 추가해서 확인해 보자.

import matplotlib.pyplot as plt
import pandas as pd

getattr(now_module,'plt'), getattr(now_module,'pd')
"""
(<module 'matplotlib.pyplot' from '/home/soobumk/.conda/envs/soobumk/lib/python3.9/site-packages/matplotlib/pyplot.py'>,
<module 'pandas' from '/home/soobumk/.conda/envs/soobumk/lib/python3.9/site-packages/pandas/__init__.py'>)
"""

 

새롭게 추가된 plt와 pd도 잘 인식이 된다.

 

getattr과 setattr 활용

setattr(object, name, value)개체의 명명된 속성 값을 설정하는 데 사용된다. 명명된 특성이 없는 경우 지정된 이름과 값을 사용하여 새 특성으로 선언이 가능하다.

 

예를 통해 계산기 모듈을 구성하고 getattr과 setattr을 활용하여 속성값을 변경해 보자.

class Calculation():
    def __init__(self,a,b):
        self.weight = 10   # 고정된 값
        self.a = a
        self.b = b
        
    def add(self):
        c = (self.a + self.b) * self.weight
        return print('Add:', c)
        
    def subtract(self):
        d = (self.a - self.b) * self.weight
        return print('Subtract:', d)

 

위와 같이 계산기 모듈을 선언했다. 값을 넣고 인스턴스를 구성한 후에 .add와 .substract 함수를 통해 자동으로 계산이 되는 클래스를 구성했다.

 

주의 깊게 봐야 하는 건 self.weight가 인스턴스가 생성될 때 default로 10이 입력되어 함수가 작동될 때 자동으로 곱해진다는 것이다.

 

아래 예시는 2와 5를 입력하여 나온 출력이다.

getattr(now_module,'Calculation') # __main__.Calculation

cal_1 = getattr(now_module,'Calculation')(2,5) # cal_1 = Calculation(2,5)와 동일하다

cal_1.add() # Add: 70
cal_1.subtract() # Subtract: -30

 

결국 getattr(now_module,'Calculation')(2,5)은 Calculation(2,5)와 동일하며 새로운 인스턴스를 만들어주는 작업이다.

 

다음 예시는 8과 5를 입력했다.

cal_2 = getattr(now_module,'Calculation')(8,5) # cal_2 = Calculation(8,5)와 동일하다

cal_2.add() # Add: 130 
cal_2.subtract() # Subtract: 30

 

이제 여기서 self.weight 속성값을 setattr를 활용하여 변경해 보자.

cal_1 = getattr(now_module,'Calculation')(2,5)
getattr(cal_1,'a'), getattr(cal_1,'b'), getattr(cal_1,'weight')
# (2, 5, 10)

setattr(cal_1,'weight',100)
getattr(cal_1,'a'), getattr(cal_1,'b'), getattr(cal_1,'weight')
# (2, 5, 100)

cal_1.add() # Add: 700 
cal_1.subtract() # Subtract: -300

 

기본 weight가 10이었다면, setattr를 통해 weight의 속성값을 100으로 변경해 주었다. 

 

이에 따라 자동적으로 10이 아니라 100이 곱해서 값이 바뀌는 걸 확인할 수 있다.

 

동일하지만 입력값이 다른 같은 예시이다..

cal_2 = Calculation(8,5)
getattr(cal_2,'a'), getattr(cal_2,'b'), getattr(cal_2,'weight')
# (8, 5, 10)

setattr(cal_2,'weight',20)
getattr(cal_2,'a'), getattr(cal_2,'b'), getattr(cal_2,'weight')
# (8, 5, 20)

cal_2.add() # Add: 260 
cal_2.subtract() # Subtract: 60

 

weight가 10에서 20으로 바뀌어 결과도 바뀌었다.

 

 

__getattr__을 활용하여 현재 돌아가고 있는 코드 내에서 손쉽게 모듈을 가져와서 새롭게 인스턴스를 선언할 수 있도록 해준다.

또한 __setattr__를 통해 모듈 안의 속성을 바꿔가며 그때마다 인스턴스를 생성할 필요 없이 바꾸고자 하는 속성값만 바꿔가며 모듈을 활용할 수 있다.

728x90
반응형

댓글