복붙노트

[PYTHON] 파이썬 : __getattr __ ()을 구현하는 방법?

PYTHON

파이썬 : __getattr __ ()을 구현하는 방법?

내 수업은 예를 들어 :

class MyClass(object):
    def __init__(self):
        self.data = {'a': 'v1', 'b': 'v2'}

그런 다음 dict의 키를 MyClass 인스턴스와 함께 사용하여 dict에 액세스하려고합니다. 예를 들면 다음과 같습니다.

ob = MyClass()
v = ob.a   # Here I expect ob.a returns 'v1'

이것이 __getattr__에 의해 구현되어야한다는 것을 알고 있지만 파이썬에 익숙하지는 않습니다. 구현 방법을 정확히 모르겠습니다.

해결법

  1. ==============================

    1.

    class MyClass(object):
    
        def __init__(self):
            self.data = {'a': 'v1', 'b': 'v2'}
    
        def __getattr__(self, attr):
            return self.data[attr]
    
    >>> ob = MyClass()
    >>> v = ob.a
    >>> v
    'v1'
    

    __setattr__을 구현할 때는주의해야합니다. 몇 가지 수정을해야합니다.

    class MyClass(object):
    
        def __init__(self):
            # prevents infinite recursion from self.data = {'a': 'v1', 'b': 'v2'}
            # as now we have __setattr__, which will call __getattr__ when the line
            # self.data[k] tries to access self.data, won't find it in the instance 
            # dictionary and return self.data[k] will in turn call __getattr__
            # for the same reason and so on.... so we manually set data initially
            super(MyClass, self).__setattr__('data', {'a': 'v1', 'b': 'v2'})
    
        def __setattr__(self, k, v):
            self.data[k] = v
    
        def __getattr__(self, k):
            # we don't need a special call to super here because getattr is only 
            # called when an attribute is NOT found in the instance's dictionary
            try:
                return self.data[k]
            except KeyError:
                raise AttributeError
    
    >>> ob = MyClass()
    >>> ob.c = 1
    >>> ob.c
    1
    

    속성을 설정할 필요가 없다면 namedtuple 만 사용하면된다. 예.

    >>> from collections import namedtuple
    >>> MyClass = namedtuple("MyClass", ["a", "b"])
    >>> ob = MyClass(a=1, b=2)
    >>> ob.a
    1
    

    기본 인수를 원하면 래퍼 클래스를 작성할 수 있습니다.

    class MyClass(namedtuple("MyClass", ["a", "b"])):
    
        def __new__(cls, a="v1", b="v2"):
            return super(MyClass, cls).__new__(cls, a, b)
    

    아니면 함수로 더 멋지게 보일 수도 있습니다.

    def MyClass(a="v1", b="v2", cls=namedtuple("MyClass", ["a", "b"])):
        return cls(a, b)
    
    >>> ob = MyClass()
    >>> ob.a
    'v1'
    
  2. ==============================

    2.파티에 늦어 지지만이 점을 더 잘 설명하는 두 가지 훌륭한 리소스를 발견했습니다 (IMHO).

    파티에 늦어 지지만이 점을 더 잘 설명하는 두 가지 훌륭한 리소스를 발견했습니다 (IMHO).

    http://western-skies.blogspot.com.br/2008/02/complete-example-of-getattr-in-python.html에서 설명한대로 self .__ dict__를 사용하여 __getattr__ 내에서 필드를 순서대로 액세스해야합니다 무한 재귀를 피할 수 있습니다. 제공된 예제는 다음과 같습니다.

    참고 : 두 번째 줄 (위)에서 파이썬 적 방법이 더 있습니다 (has_key는 분명히 파이썬 3에서 삭제되었습니다).

    if attrName not in self.__dict__:
    

    다른 리소스 (http://farmdev.com/src/secrets/magicmethod/#introducing-getattr)는 __getattr__이 객체에 속성이없는 경우에만 호출되며, hasattr은 객체가있는 경우 항상 True를 반환한다고 설명합니다. __getattr__에 대한 구현. 다음 예제를 통해 데모를 제공합니다.

  3. ==============================

    3.

    class A(object):
      def __init__(self):
         self.data = {'a': 'v1', 'b': 'v2'}
      def __getattr__(self, attr):
         try:
           return self.data[attr]
         except:
           return "not found"
    
    
    >>>a = A()
    >>>print a.a
    v1
    >>>print a.c
    not found
    
  4. ==============================

    4.나는 이것을 받아들이고 싶다.

    나는 이것을 받아들이고 싶다.

    나는 어딘가에서 그것을 가져 갔지만, 나는 기억하지 않는다.

    class A(dict):
        def __init__(self, *a, **k):
            super(A, self).__init__(*a, **k)
            self.__dict__ = self
    

    이것은 속성과 항목 액세스가 동일한 dict에 매핑되도록 객체의 __dict__을 자체와 동일하게 만듭니다.

    a = A()
    a['a'] = 2
    a.b = 5
    print a.a, a['b'] # prints 2 5
    
  5. ==============================

    5.중첩 된 사전과 사전을 처리하는 @ glglgl의 대답이 원래 사전에있는 목록의 내부에 확장 된 것을 알아 냈습니다.

    중첩 된 사전과 사전을 처리하는 @ glglgl의 대답이 원래 사전에있는 목록의 내부에 확장 된 것을 알아 냈습니다.

    class d(dict):
        def __init__(self, *a, **k): 
            super(d, self).__init__(*a, **k)
            self.__dict__ = self
            for k in self.__dict__:
                if isinstance(self.__dict__[k], dict):
                    self.__dict__[k] = d(self.__dict__[k])
                elif isinstance(self.__dict__[k], list):
                    for i in range(len(self.__dict__[k])):
                        if isinstance(self.__dict__[k][i], dict):
                            self.__dict__[k][i] = d(self.__dict__[k][i])
    
  6. ==============================

    6.생성자를 통해 클래스 사전을 초기화 할 수 있습니다.

    생성자를 통해 클래스 사전을 초기화 할 수 있습니다.

        def __init__(self,**data):
    

    그리고 그것을 다음과 같이 부르십시오.

    f = MyClass(**{'a': 'v1', 'b': 'v2'})
    

    __setattr__에서 액세스 (읽기)되는 모든 인스턴스 속성은 부모 (수퍼) 메소드를 사용하여 한 번만 선언해야합니다.

        super().__setattr__('NewVarName1', InitialValue)
    

    또는

        super().__setattr__('data', dict())
    

    그런 다음 일반적인 방법으로 액세스하거나 할당 할 수 있습니다.

        self.data = data
    

    __setattr__에서 액세스되지 않는 인스턴스 속성은 일반적인 방식으로 선언 할 수 있습니다.

        self.x = 1
    

    재정의 된 __setattr__ 메소드는 이제 새 변수를 선언하기 위해 자체 내부의 부모 메소드를 호출해야합니다.

        super().__setattr__(key,value)
    

    완전한 수업은 다음과 같이 보일 것입니다 :

    class MyClass(object):
        def __init__(self, **data):
            # The variable self.data is used by method __setattr__
            # inside this class, so we will need to declare it 
            # using the parent __setattr__ method:
            super().__setattr__('data', dict())
            self.data = data            
            # These declarations will jump to
            # super().__setattr__('data', dict())
            # inside method __setattr__ of this class:
            self.x = 1
            self.y = 2
    
        def __getattr__(self, name):
        # This will callback will never be called for instance variables
        # that have beed declared before being accessed.
            if name in self.data:
                # Return a valid dictionary item:
                return self.data[name]
            else:
                # So when an instance variable is being accessed, and
                # it has not been declared before, nor is it contained
                # in dictionary 'data', an attribute exception needs to
                # be raised.
                raise AttributeError
    
        def __setattr__(self, key, value):
            if key in self.data:
                # Assign valid dictionary items here:
                self.data[key] = value
            else:
                # Assign anything else as an instance attribute:
                super().__setattr__(key,value)
    

    테스트:

    f = MyClass(**{'a': 'v1', 'b': 'v2'})
    print("f.a = ", f.a)
    print("f.b = ", f.b)
    print("f.data = ", f.data)
    f.a = 'c'
    f.d = 'e'
    print("f.a = ", f.a)
    print("f.b = ", f.b)
    print("f.data = ", f.data)
    print("f.d = ", f.d)
    print("f.x = ", f.x)
    print("f.y = ", f.y)
    # Should raise attributed Error
    print("f.g = ", f.g)
    

    산출:

    f.a =  v1
    f.b =  v2
    f.data =  {'a': 'v1', 'b': 'v2'}
    f.a =  c
    f.b =  v2
    f.data =  {'a': 'c', 'b': 'v2'}
    f.d =  e
    f.x =  1
    f.y =  2
    Traceback (most recent call last):
      File "MyClass.py", line 49, in <module>
        print("f.g = ", f.g)
      File "MyClass.py", line 25, in __getattr__
        raise AttributeError
    AttributeError
    
  7. ==============================

    7.나는이 도구가 더 시원하다고 생각한다.

    나는이 도구가 더 시원하다고 생각한다.

    class MyClass(object):
        def __init__(self):
            self.data = {'a': 'v1', 'b': 'v2'}
        def __getattr__(self,key):
            return self.data.get(key,None)
    
  8. from https://stackoverflow.com/questions/16237659/python-how-to-implement-getattr by cc-by-sa and MIT license