성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>파이썬 - class의 정적 함수를 동적으로 교체</h1> <p> 지난 글에서,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 파이썬 3.x에서의 동적 함수 추가 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13380'>https://www.sysnet.pe.kr/2/0/13380</a> </pre> <br /> 동적으로 외부의 함수를 내부에 추가하는 방법을 알아봤는데요, 이번에는 이미 정의된 함수를 대체하는 방법을 알아보겠습니다. 우선, 예제를 볼까요? ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > class MyObject: def __init__(self): pass @staticmethod def set_name(text): MyObject.name = text current_module = __import__(__name__) class_type = current_module.__dict__.get('MyObject') print(class_type, type(class_type)) """ 출력 결과 <class '__main__.MyObject'> <class 'type'> """ </pre> <br /> 이렇게 구한 class_type은 "MyObject" 이름으로 접근한 것과 완전히 동일한 타입 인스턴스입니다. 그렇기 때문에 다음과 같이 멤버를 접근하는 것도 가능합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > class_type.set_name('hello world') # MyObject.set_name 호출과 동일 print(MyObject.name) # 출력 결과: hello world </pre> <br /> 그런데, 저 set_name 정적 메서드를 동적으로 접근하려면 어떻게 해야 할까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > set_name_method = <span style='color: blue; font-weight: bold'>class_type.__dict__</span>.get('set_name') print(set_name_method, type(set_name_method)) """ 출력 결과 <staticmethod object at 0x000001B55CE77DC0> <class 'staticmethod'> """ </pre> <br /> __dict__ 통해 얻은 경우 예상했던 대로 (decorator로 지정한) staticmethod 타입의 인스턴스가 나오는데요, 따라서 이렇게 얻은 set_name_method로는 호출이 안 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > set_name_method('hello world') # 오류 발생 TypeError: 'staticmethod' object is not callable </pre> <br /> <a target='tab' href='https://www.sysnet.pe.kr/2/0/13380'>지난 글에서 다룬 staticmethod</a>의 사용법과 비교해 보면 재미있는 결과를 얻게 되는데요,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > def f_static(arg): print('f_static', arg) MyObject.fs = staticmethod(f_static) MyObject.fs('hello world') # 정상적으로 호출 print(MyObject.fs, type(MyObject.fs)) # <function f_static at 0x000001DA86207280> <class 'function'> </pre> <br /> 위의 코드에서도 f_static을 staticmethod 타입으로 감쌌지만 MyObject.fs의 타입이 "staticmethod"가 아닌 function으로 나온다는 차이점이 있습니다.<br /> <br /> 어쨌든, (__dict__를 통해) 동적으로 구한 staticmethod 인스턴스는 decorator가 지정된 함수를 반환하는 __func__을 통해야만 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > set_name_method.__func__('hello world') print(MyObject.name) # 출력 결과: hello world </pre> <br /> <hr style='width: 50%' /><br /> <br /> 그렇다면, 위와 같이 정의된 정적 함수를 아래의 (클래스가 아닌 모듈에 속한) 함수로,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > name = None def global_set_name(text): global name name = text </pre> <br /> 교체하려면 어떻게 해야 할까요? 간단하게는 class 이름 또는 그것의 type 인스턴스를 접근해 바꿀 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > # 클래스 이름을 사용해도 되고, MyObject.set_name = global_set_name MyObject.set_name('hello world-1') print(name) # 출력 결과: hello world-1 # 동적으로 구한 class 'type'의 인스턴스를 이용해도 됨 class_type.set_name = global_set_name class_type.set_name('hello world-2') print(name) # 출력 결과: hello world-2 </pre> <br /> 그런데, 'set_name' 함수를 (__dict__를 통해) 동적으로 접근하고 싶은 경우라면 사정이 달라집니다. 해당 함수를 구하는 경우에는 __dict__를 이용할 수 있었지만, 이걸로는 교체까진 되지 않습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > class_type.__dict__['set_name'] = global_set_name # 오류 발생: <span style='color: blue; font-weight: bold'>TypeError: 'mappingproxy' object does not support item assignment</span> </pre> <br /> class_type.__dict__는 mappingproxy 타입으로 read-only라서 저런 오류가 발생합니다. 이에 대해 검색해 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > How to modify class __dict__ (a mappingproxy)? [duplicate] ; <a target='tab' href='https://stackoverflow.com/questions/20019333/how-to-modify-class-dict-a-mappingproxy'>https://stackoverflow.com/questions/20019333/how-to-modify-class-dict-a-mappingproxy</a> </pre> <br /> 파이썬의 setattr 내장 함수를 이용하라고 하는군요. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > setattr(class_type, 'set_name', global_set_name) class_type.set_name('hello world') print(name) # global_set_name 함수로 교체됐으므로 전역 name 변수의 값이 바뀜 # 출력 결과: hello world </pre> <br /> <hr style='width: 50%' /><br /> <br /> 그 외 class의 instance 함수는 decorator가 지정되지 않은 유형이므로 __func__ 등을 고려하지 않아도 된다는 점만 빼고는 위의 원칙을 그대로 적용할 수 있습니다.<br /> <br /> 또한, setattr의 두 번째 인자가 멤버를 구분하는 데 있어 키 타입으로 str 문자열을 사용한다는 점에서 <a target='tab' href='https://www.sysnet.pe.kr/2/0/13433'>파이썬에서는 같은 이름의 다른 인자를 갖는 메서드 오버로딩이 지원되지 않음</a>을 짐작할 수 있을 것입니다.<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1092
(왼쪽의 숫자를 입력해야 합니다.)