2017-02-24 1 views
2

면책 조항 :속성 액세스 유형 (클래스 또는 인스턴스 사용)에 따라 함수간에 "전환"을 수행하는 방법은 무엇입니까?

이 문서가 더 문제보다 제조법이지만, 나는 웹에서 거의 참조로, 피사체가 매우 흥미로운 발견했다.

StackOverflow에서 더 많은 기사를 게시 할 수있는 곳이 있다면 알려 주시기 바랍니다.

제목 : 나는 (클래스 또는 인스턴스를 사용하여) 속성 액세스 유형에 따라 다른 함수를 호출하는 파이썬을 강제 할 방법

- 예를 들어, 파이썬이 MyClass.my_method()MyClass().my_method()에 대해 다른 메소드를 호출하도록 강요 하시겠습니까?

은 Usecase :

이 (하지만 일부 사용자 정의와, Python36 열거 기준) 우리는 사용자 정의 열거 구현이, 이제 가정 해 봅시다. 이 열거 형 사용자는 열거 형뿐만 아니라 str : class MyEnum(str, Enum)에서 상속받은 CustomEnum을 만들고자합니다. 또한 인코딩 및 디코딩 기능을 추가하려고합니다. 우리의 생각은 MyEnum.encode을 사용하여 열거 형 멤버를 포함하는 모든 객체를 인코딩하지만 enum 클래스의 인스턴스 용으로 원래 str.encode을 사용하는 것입니다. 짧게 : MyEnum.encode은 우리의 사용자 지정 인코딩 기능을 호출하고,이 관점에서 완벽하게 감지합니다. MyEnum()은 문자열이므로 MyEnum().encode은 str 클래스에서 상속받은 encode 함수를 호출해야합니다.

솔루션 :

은 스위치로 작동 기술자를 작성합니다. 내 첫 번째 게시물에 전체 대답.

+0

답변과 솔루션 부분을 게시하시기 바랍니다. – Gabriel

+1

SO (http://stackoverflow.com/documentation)의 문서 섹션에 게시 할 수 있습니다. 또는 문제 구역에만 질문을 제한하고 솔루션 섹션 –

+0

으로 직접 대답 할 수 있습니다. @utsav_deep - 문제에 대한 제 대답을 어떻게 제한합니까? 거기에 어떤 옵션이 있습니까? 죄송합니다 멍청한 질문에 대한 이러한 StackOverflow 내 첫 단계입니다. –

답변

3

솔루션 : __get__(self, instance, instance_type) :

는 지금까지 내가 아는 한, 기술자들이 클래스 또는 인스턴스에 대한 호출하는 경우 때문에 __get__ 함수 서명의, 구별 할 수있는 유일한 개체입니다. 이 속성을 사용하면 스위치를 위에 올려 놓을 수 있습니다.

class boundmethod(object):  
    def __init__(self, cls_method=None, instance_method=None, doc=None): 
     self._cls_method = cls_method 
     self._instance_method = instance_method 
     if cls_method: 
      self._method_name = cls_method.__name__ 
     elif instance_method: 
      self._method_name = instance_method.__name__ 

     if doc is None and cls_method is not None: 
      doc = cls_method.__doc__ 
     self.__doc__ = doc 

     self._method = None 
     self._object = None 

    def _find_method(self, instance, instance_type, method_name): 
     for base in instance_type.mro()[1:]: 
      method = getattr(base, method_name, None) 
      if _is_descriptor(method): 
       method = method.__get__(instance, base) 
      if method and method is not self: 
       try: 
        return method.__func__ 
       except AttributeError: 
        return method 

    def __get__(self, instance, instance_type): 
     if instance is None: 
      self._method = self._cls_method or self._find_method(instance, instance_type, self._method_name) 
      self._object = instance_type 
     else: 
      self._method = self._instance_method or self._find_method(instance, instance_type, self._method_name) 
      self._object = instance 
     return self 

    @staticmethod 
    def cls_method(obj=None): 
     def constructor(cls_method): 
      if obj is None: 
       return boundmethod(cls_method, None, cls_method.__doc__) 
      else: 
       return type(obj)(cls_method, obj._instance_method, obj.__doc__) 

     if isinstance(obj, FunctionType): 
      return boundmethod(obj, None, obj.__doc__) 
     else: 
      return constructor 

    @staticmethod 
    def instance_method(obj=None): 
     def constructor(instance_method): 
      if obj is None: 
       return boundmethod(None, instance_method, instance_method.__doc__) 
      else: 
       return type(obj)(obj._cls_method, instance_method, obj.__doc__) 

     if isinstance(obj, FunctionType): 
      return boundmethod(None, obj, obj.__doc__) 
     else: 
      return constructor 

    def __call__(self, *args, **kwargs): 
     if self._method: 
      try: 
       return self._method(self._object, *args, **kwargs) 
      except TypeError: 
       return self._method(*args, **kwargs) 
     return None 

예 :

>>> class Walkmen(object): 
...  @boundmethod.cls_method 
...  def start(self): 
...   return 'Walkmen start class bound method' 
...  @boundmethod.instance_method(start) 
...  def start(self): 
...   return 'Walkmen start instance bound method' 
>>> print Walkmen.start() 
Walkmen start class bound method 
>>> print Walkmen().start() 
Walkmen start instance bound method 

가 나는 너희들 O를 몇 가지 도움이되기를 바랍니다.

최고.

0

저는 실제로이 질문을했습니다 (Python descriptors and inheritance 나는이 질문을 보지 못했습니다). My solution은 상속에 대한 설명자와 메타 클래스를 사용합니다. my answer에서

:에

class dynamicmethod: 
    ''' 
     Descriptor to allow dynamic dispatch on calls to class.Method vs obj.Method 

     fragile when used with inheritence, to inherit and then overwrite or extend 
     a dynamicmethod class must have dynamicmethod_meta as its metaclass 
    ''' 
    def __init__(self, f=None, m=None): 
     self.f = f 
     self.m = m 

    def __get__(self, obj, objtype=None): 
     if obj is not None and self.f is not None: 
      return types.MethodType(self.f, obj) 
     elif objtype is not None and self.m is not None: 
      return types.MethodType(self.m, objtype) 
     else: 
      raise AttributeError('No associated method') 

    def method(self, f): 
     return type(self)(f, self.m) 

    def classmethod(self, m): 
     return type(self)(self.f, m) 

def make_dynamicmethod_meta(meta): 
    class _dynamicmethod_meta(meta): 
     def __prepare__(name, bases, **kwargs): 
      d = meta.__prepare__(name, bases, **kwargs) 
      for base in bases: 
       for k,v in base.__dict__.items(): 
        if isinstance(v, dynamicmethod): 
         if k in d: 
          raise ValueError('Multiple base classes define the same dynamicmethod') 
         d[k] = v 
      return d 

    return _dynamicmethod_meta 

dynamicmethod_meta=make_dynamicmethod_meta(type) 

class A(metaclass=dynamicmethod_meta): 
    @dynamicmethod 
    def a(self): 
     print('Called from obj {} defined in A'.format(self)) 

    @a.classmethod 
    def a(cls) 
     print('Called from class {} defined in A'.format(cls)) 

class B(A): 
    @a.method 
    def a(self): 
     print('Called from obj {} defined in B'.format(self)) 

A.a() 
A().a() 
B.a() 
B().a() 

결과 :

Called from class <class 'A'> defined in A 
Called from obj <A object at ...> defined in A 
Called from class <class 'B'> defined in A 
Called from obj <B object at ...> defined in B 
관련 문제