class Cacheable: _cache = {} def create_cached(cls, value): if not cls._cache.has_key(value): print 'cache miss' rslt = cls(value) cls._cache[value] = rslt else: print 'cache hit' rslt = cls._cache[value] return rslt create_cached = classmethod(create_cached) class X(Cacheable): def __init__(self, value): self.value = value x = X.create_cached('test') # X instance created x = X.create_cached('test2') # X instance created x = X.create_cached('test') # X instance taken from cache
classmethod를 사용하면 메소드가 상속되었을때 derived class를 클래스 메소드의 첫번째 인자로 줍니다. 그래서 위에처럼 이를 cls로 받아서 생성자를 부른다던가 – cls(value) 부분 – 할 수 있음. 호.. 신기하군요. C++의 CRTP와 비슷해보이네요.
반면 자바처럼 static method를 만들기 위해 classmethod를 쓰는 것은 반대하며 대신 별도의 파일로 메소드들을 선언하면 그것이 곧 모듈이다..라는 군요. 그러니까
>>> class Foo: ... def bar(cls): ... print cls ... bar = classmethod(bar) ... >>> Foo.bar() __main__.Foo >>>
이렇게 하지 말란거죠. (참고: 위에처럼 bar가 중복 사용되면 메소드가 가려지고 변수가 살아남음) 된다고 해서 마구해서는 안된다..라는 것이 또 파이썬의 중요한 핵심 축인 듯. 예를 들어, 파이썬에서도 core class들을 수정할 수 있으나 이런 형태는 monkey patch 라고 불리며 피해야 할 코딩패턴이라는군요. 반면 루비의 경우엔 core class의 수정이 가능하다는 것이 중요한 코딩 테크닉으로 쓰이는데, 그와 같은 예가 바로 이전에 포스팅한 Ruby Linguistics가 있죠. 이런 것은 커뮤니티의 마인드 차이가 참 큰 듯..