목차
소개
静态方法
类方法
其他的魔术方法
__getattr__
应用
__getitem__
백엔드 개발 파이썬 튜토리얼 Python의 매직 설명자

Python의 매직 설명자

Mar 18, 2017 am 11:36 AM
python

소개

설명자(descriptor)는 Python 언어에서 심오하지만 중요한 흑마술입니다. Python 언어의 핵심으로 널리 사용됩니다. 설명자에 능숙하면 Python 추가됩니다. 프로그래머의 도구 상자에 속임수를 쓰세요. 이 글에서는 디스크립터의 정의와 몇 가지 일반적인 시나리오에 대해 이야기하고, 글 마지막에 , __getattr, __getattribute__ 세 가지 __getitem__매직 메소드를 추가하겠습니다. 속성 액세스를 포함합니다.

설명자 정의

descr__get__(self, obj, objtype=None) --> value
descr.__set__(self, obj, value) --> None
descr.__delete__(self, obj) --> None
로그인 후 복사

(객체 속성)가 위의 세 가지 메서드 중 하나를 정의하는 한 이 클래스는 설명자 클래스라고 부를 수 있습니다. object attribute

설명자 기본

다음 예에서는

클래스를 만들고 RevealAcess 메서드를 구현합니다. 이제 이 클래스를 설명자 클래스라고 부를 수 있습니다. __get__

class RevealAccess(object):
    def __get__(self, obj, objtype):
        print('self in RevealAccess: {}'.format(self))
        print('self: {}\nobj: {}\nobjtype: {}'.format(self, obj, objtype))
class MyClass(object):
    x = RevealAccess()
    def test(self):
        print('self in MyClass: {}'.format(self))
로그인 후 복사

EX1 인스턴스 속성

다음으로

메소드의 각 매개변수의 의미를 살펴보겠습니다. 다음 예에서 __get__는 RevealAccess 클래스 인스턴스 x, self는 MyClass 클래스의 인스턴스 m이고, obj는 이름에서 알 수 있듯이 MyClass 클래스 자체입니다. 출력 문에서 볼 수 있듯이 objtype 액세스 설명자 m.xx 메서드를 호출합니다. __get__

>>> m = MyClass()
>>> m.test()
self in MyClass: <__main__.MyClass object at 0x7f19d4e42160>
>>> m.x
self in RevealAccess: <__main__.RevealAccess object at 0x7f19d4e420f0>
self: <__main__.RevealAccess object at 0x7f19d4e420f0>
obj: <__main__.MyClass object at 0x7f19d4e42160>
objtype: <class &#39;__main__.MyClass&#39;>
로그인 후 복사

EX2 클래스 속성

속성이 클래스를 통해 직접 액세스되는 경우 x 연결은 직접 None이므로 이해하기 쉽습니다. , MyClass 인스턴스가 존재하지 않기 때문입니다. obj

>>> MyClass.x
self in RevealAccess: <__main__.RevealAccess object at 0x7f53651070f0>
self: <__main__.RevealAccess object at 0x7f53651070f0>
obj: None
objtype: <class &#39;__main__.MyClass&#39;>
로그인 후 복사

설명자 원리

설명자 트리거

위의 예에서는 각각 인스턴스 속성과 클래스 속성의 관점에서 설명자의 사용법을 나열했습니다. 내부 원리 분석:

  • 에 액세스하면 기본 클래스 객체의 __getattribute__ 메서드가 실제로 호출됩니다. 이 메서드에서는 obj.d가 实例属性로 변환됩니다. type(obj).__dict__[&#39;d&#39;].__get__(obj, type(obj))

  • 에 액세스하면 cls.d를 类属性로 변환하는 메타클래스 유형의 __getattribute__ 메서드를 호출하는 것과 같습니다. 여기서 __get__( )의 obj는 다음과 같습니다. 인스턴스가 없기 때문에 없음입니다. cls.__dict__[&#39;d&#39;].__get__(None, cls)

매직 메소드에 대해 간단히 이야기해보겠습니다. 이 메소드는 객체의 속성에 접근할 때 무조건 호출됩니다. 자세한 내용은 __getattribute__, __getattr 과 같습니다. 기사 마지막 부분에 추가 보충 자료를 작성하겠지만 지금은 자세히 다루지 않겠습니다. __getitem__

설명자 우선순위

먼저 설명자는 두 가지 유형으로 나뉩니다.

  • 객체가 __get__() 및 __set__() 메서드를 모두 정의하는 경우 , 이 설명자를

    이라고 합니다. data descriptor

  • 객체가 __get__() 메서드만 정의하는 경우 이 설명자를

    이라고 합니다. non-data descriptor

속성에 액세스할 때 네 가지 상황이 있습니다.

  • 데이터 설명자

  • 인스턴스 사전

  • 비데이터 설명자

  • __getattr__()

우선순위 크기는

data descriptor > instance dict > non-data descriptor > __getattr__()
로그인 후 복사

이게 무슨 뜻인가요? 즉, 동일한 이름을 가진

data descriptor->d가 인스턴스 객체 obj에 나타나면 instance attribute->dobj.d 속성에 액세스할 때 데이터 설명자의 우선순위가 더 높기 때문에 Python은 d을 호출합니다. 대신 obj.__dict__['d']를 호출하는 대신. 그러나 설명자가 데이터 설명자가 아닌 경우 Python은 type(obj).__dict__[&#39;d&#39;].__get__(obj, type(obj))을 호출합니다. obj.__dict__[&#39;d&#39;]

속성

설명자를 사용할 때마다 설명자 클래스를 정의하는 것은 매우 번거로운 작업 같습니다. Python은 속성에 데이터 설명자를 추가하는 간결한 방법을 제공합니다.

property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
로그인 후 복사

fget, fset 및 fdel은 각각 클래스의 getter, setter 및 deleter 메서드입니다. 다음 예를 사용하여 속성 사용 방법을 설명합니다.

class Account(object):
    def __init__(self):
        self._acct_num = None
    def get_acct_num(self):
        return self._acct_num
    def set_acct_num(self, value):
        self._acct_num = value
    def del_acct_num(self):
        del self._acct_num
    acct_num = property(get_acct_num, set_acct_num, del_acct_num, &#39;_acct_num property.&#39;)
로그인 후 복사

acct가 Account의 인스턴스인 경우 acct.acct_num은 getter를 호출하고 acct.acct_num = value는 setter를 호출하며 del acct_num.acct_num 삭제자를 호출합니다.

>>> acct = Account()
>>> acct.acct_num = 1000
>>> acct.acct_num
1000
로그인 후 복사

Python은 간단한 애플리케이션 시나리오를 위한 속성을 생성하는 데 사용할 수 있는

데코레이터도 제공합니다. 속성 개체에는 해당 데코레이팅된 함수의 접근자 함수를 통해 속성의 복사본을 만드는 데 사용할 수 있는 getter, setter 및 delete 데코레이터 메서드가 있습니다. @property

class Account(object):
    def __init__(self):
        self._acct_num = None
    @property
     # the _acct_num property. the decorator creates a read-only property
    def acct_num(self):
        return self._acct_num
    @acct_num.setter
    # the _acct_num property setter makes the property writeable
    def set_acct_num(self, value):
        self._acct_num = value
    @acct_num.deleter
    def del_acct_num(self):
        del self._acct_num
로그인 후 복사

속성을 읽기 전용으로 설정하려면 setter 메소드를 제거하면 됩니다.

런타임에 설명자 만들기

런타임에 속성을 추가할 수 있습니다:

class Person(object):
    def addProperty(self, attribute):
        # create local setter and getter with a particular attribute name
        getter = lambda self: self._getProperty(attribute)
        setter = lambda self, value: self._setProperty(attribute, value)
        # construct property attribute and add it to the class
        setattr(self.__class__, attribute, property(fget=getter, \
                                                    fset=setter, \
                                                    doc="Auto-generated method"))
    def _setProperty(self, attribute, value):
        print("Setting: {} = {}".format(attribute, value))
        setattr(self, &#39;_&#39; + attribute, value.title())
    def _getProperty(self, attribute):
        print("Getting: {}".format(attribute))
        return getattr(self, &#39;_&#39; + attribute)
로그인 후 복사
rrree

정적 메서드 및 클래스 메서드

설명자를 사용하여 구현을 시뮬레이션할 수 있습니다. Python의

@staticmethod. 먼저 아래 표를 살펴보겠습니다. @classmethod

TransformationCalled from an ObjectCalled from a Class
functionf(obj, *args)f(*args)
staticmethodf(*args)f(*args)
classmethodf(type(obj), *args)f(klass, *args)

静态方法

对于静态方法fc.fC.f是等价的,都是直接查询object.__getattribute__(c, ‘f’)或者object.__getattribute__(C, ’f‘)。静态方法一个明显的特征就是没有self变量。

静态方法有什么用呢?假设有一个处理专门数据的容器类,它提供了一些方法来求平均数,中位数等统计数据方式,这些方法都是要依赖于相应的数据的。但是类中可能还有一些方法,并不依赖这些数据,这个时候我们可以将这些方法声明为静态方法,同时这也可以提高代码的可读性。

使用非数据描述符来模拟一下静态方法的实现:

class StaticMethod(object):
    def __init__(self, f):
        self.f = f
    def __get__(self, obj, objtype=None):
        return self.f
로그인 후 복사

我们来应用一下:

class MyClass(object):
    @StaticMethod
    def get_x(x):
        return x
print(MyClass.get_x(100))  # output: 100
로그인 후 복사

类方法

Python的@classmethod@staticmethod的用法有些类似,但是还是有些不同,当某些方法只需要得到类的引用而不关心类中的相应的数据的时候就需要使用classmethod了。

使用非数据描述符来模拟一下类方法的实现:

class ClassMethod(object):
    def __init__(self, f):
        self.f = f
    def __get__(self, obj, klass=None):
        if klass is None:
            klass = type(obj)
        def newfunc(*args):
            return self.f(klass, *args)
        return newfunc
로그인 후 복사

其他的魔术方法

首次接触Python魔术方法的时候,我也被__get__, __getattribute__, __getattr__, __getitem__之间的区别困扰到了,它们都是和属性访问相关的魔术方法,其中重写__getattr____getitem__来构造一个自己的集合类非常的常用,下面我们就通过一些例子来看一下它们的应用。

__getattr__

Python默认访问类/实例的某个属性都是通过__getattribute__来调用的,__getattribute__会被无条件调用,没有找到的话就会调用__getattr__。如果我们要定制某个类,通常情况下我们不应该重写__getattribute__,而是应该重写__getattr__,很少看见重写__getattribute__的情况。

从下面的输出可以看出,当一个属性通过__getattribute__无法找到的时候会调用__getattr__

In [1]: class Test(object):
    ...:     def __getattribute__(self, item):
    ...:         print(&#39;call __getattribute__&#39;)
    ...:         return super(Test, self).__getattribute__(item)
    ...:     def __getattr__(self, item):
    ...:         return &#39;call __getattr__&#39;
    ...:
In [2]: Test().a
call __getattribute__
Out[2]: &#39;call __getattr__&#39;
로그인 후 복사

应用

对于默认的字典,Python只支持以obj[&#39;foo&#39;]形式来访问,不支持obj.foo的形式,我们可以通过重写__getattr__让字典也支持obj[&#39;foo&#39;]的访问形式,这是一个非常经典常用的用法:

class Storage(dict):
    """
    A Storage object is like a dictionary except `obj.foo` can be used
    in addition to `obj[&#39;foo&#39;]`.
    """
    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError as k:
            raise AttributeError(k)
    def __setattr__(self, key, value):
        self[key] = value
    def __delattr__(self, key):
        try:
            del self[key]
        except KeyError as k:
            raise AttributeError(k)
    def __repr__(self):
        return &#39;<Storage &#39; + dict.__repr__(self) + &#39;>&#39;
로그인 후 복사

我们来使用一下我们自定义的加强版字典:

>>> s = Storage(a=1)
>>> s[&#39;a&#39;]
1
>>> s.a
1
>>> s.a = 2
>>> s[&#39;a&#39;]
2
>>> del s.a
>>> s.a
...
AttributeError: &#39;a&#39;
로그인 후 복사

__getitem__

getitem用于通过下标[]的形式来获取对象中的元素,下面我们通过重写__getitem__来实现一个自己的list。

class MyList(object):
    def __init__(self, *args):
        self.numbers = args
    def __getitem__(self, item):
        return self.numbers[item]
my_list = MyList(1, 2, 3, 4, 6, 5, 3)
print my_list[2]
로그인 후 복사

这个实现非常的简陋,不支持slice和step等功能,请读者自行改进,这里我就不重复了。

应用

下面是参考requests库中对于__getitem__的一个使用,我们定制了一个忽略属性大小写的字典类。

程序有些复杂,我稍微解释一下:由于这里比较简单,没有使用描述符的需求,所以使用了@property装饰器来代替,lower_keys的功能是将实例字典中的键全部转换成小写并且存储在字典self._lower_keys中。重写了__getitem__方法,以后我们访问某个属性首先会将键转换为小写的方式,然后并不会直接访问实例字典,而是会访问字典self._lower_keys去查找。赋值/删除操作的时候由于实例字典会进行变更,为了保持self._lower_keys和实例字典同步,首先清除self._lower_keys的内容,以后我们重新查找键的时候再调用__getitem__的时候会重新新建一个self._lower_keys

class CaseInsensitiveDict(dict):
    @property
    def lower_keys(self):
        if not hasattr(self, &#39;_lower_keys&#39;) or not self._lower_keys:
            self._lower_keys = dict((k.lower(), k) for k in self.keys())
        return self._lower_keys
    def _clear_lower_keys(self):
        if hasattr(self, &#39;_lower_keys&#39;):
            self._lower_keys.clear()
    def __contains__(self, key):
        return key.lower() in self.lower_keys
    def __getitem__(self, key):
        if key in self:
            return dict.__getitem__(self, self.lower_keys[key.lower()])
    def __setitem__(self, key, value):
        dict.__setitem__(self, key, value)
        self._clear_lower_keys()
    def __delitem__(self, key):
        dict.__delitem__(self, key)
        self._lower_keys.clear()
    def get(self, key, default=None):
        if key in self:
            return self[key]
        else:
            return default
로그인 후 복사

我们来调用一下这个类:

>>> d = CaseInsensitiveDict()
>>> d[&#39;ziwenxie&#39;] = &#39;ziwenxie&#39;
>>> d[&#39;ZiWenXie&#39;] = &#39;ZiWenXie&#39;
>>> print(d)
{&#39;ZiWenXie&#39;: &#39;ziwenxie&#39;, &#39;ziwenxie&#39;: &#39;ziwenxie&#39;}
>>> print(d[&#39;ziwenxie&#39;])
ziwenxie
# d[&#39;ZiWenXie&#39;] => d[&#39;ziwenxie&#39;]
>>> print(d[&#39;ZiWenXie&#39;])
ziwenxie
로그인 후 복사

위 내용은 Python의 매직 설명자의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

PS 페더 링은 어떻게 전환의 부드러움을 제어합니까? PS 페더 링은 어떻게 전환의 부드러움을 제어합니까? Apr 06, 2025 pm 07:33 PM

깃털 통제의 열쇠는 점진적인 성격을 이해하는 것입니다. PS 자체는 그라디언트 곡선을 직접 제어하는 ​​옵션을 제공하지 않지만 여러 깃털, 일치하는 마스크 및 미세 선택으로 반경 및 구배 소프트를 유연하게 조정하여 자연스럽게 전이 효과를 달성 할 수 있습니다.

설치 후 MySQL을 사용하는 방법 설치 후 MySQL을 사용하는 방법 Apr 08, 2025 am 11:48 AM

이 기사는 MySQL 데이터베이스의 작동을 소개합니다. 먼저 MySQLworkBench 또는 명령 줄 클라이언트와 같은 MySQL 클라이언트를 설치해야합니다. 1. MySQL-Uroot-P 명령을 사용하여 서버에 연결하고 루트 계정 암호로 로그인하십시오. 2. CreateABase를 사용하여 데이터베이스를 작성하고 데이터베이스를 선택하십시오. 3. CreateTable을 사용하여 테이블을 만들고 필드 및 데이터 유형을 정의하십시오. 4. InsertInto를 사용하여 데이터를 삽입하고 데이터를 쿼리하고 업데이트를 통해 데이터를 업데이트하고 DELETE를 통해 데이터를 삭제하십시오. 이러한 단계를 마스터하고 일반적인 문제를 처리하는 법을 배우고 데이터베이스 성능을 최적화하면 MySQL을 효율적으로 사용할 수 있습니다.

MySQL은 지불해야합니다 MySQL은 지불해야합니다 Apr 08, 2025 pm 05:36 PM

MySQL에는 무료 커뮤니티 버전과 유료 엔터프라이즈 버전이 있습니다. 커뮤니티 버전은 무료로 사용 및 수정할 수 있지만 지원은 제한되어 있으며 안정성이 낮은 응용 프로그램에 적합하며 기술 기능이 강합니다. Enterprise Edition은 안정적이고 신뢰할 수있는 고성능 데이터베이스가 필요하고 지원 비용을 기꺼이 지불하는 응용 프로그램에 대한 포괄적 인 상업적 지원을 제공합니다. 버전을 선택할 때 고려 된 요소에는 응용 프로그램 중요도, 예산 책정 및 기술 기술이 포함됩니다. 완벽한 옵션은없고 가장 적합한 옵션 만 있으므로 특정 상황에 따라 신중하게 선택해야합니다.

PS 페더 링을 설정하는 방법? PS 페더 링을 설정하는 방법? Apr 06, 2025 pm 07:36 PM

PS 페더 링은 이미지 가장자리 블러 효과로, 가장자리 영역에서 픽셀의 가중 평균에 의해 달성됩니다. 깃털 반경을 설정하면 흐림 정도를 제어 할 수 있으며 값이 클수록 흐려집니다. 반경을 유연하게 조정하면 이미지와 요구에 따라 효과를 최적화 할 수 있습니다. 예를 들어, 캐릭터 사진을 처리 할 때 더 작은 반경을 사용하여 세부 사항을 유지하고 더 큰 반경을 사용하여 예술을 처리 할 때 흐릿한 느낌을줍니다. 그러나 반경이 너무 커서 가장자리 세부 사항을 쉽게 잃을 수 있으며 너무 작아 효과는 분명하지 않습니다. 깃털 효과는 이미지 해상도의 영향을받으며 이미지 이해 및 효과 파악에 따라 조정해야합니다.

PS 깃털은 이미지 품질에 어떤 영향을 미칩니 까? PS 깃털은 이미지 품질에 어떤 영향을 미칩니 까? Apr 06, 2025 pm 07:21 PM

PS 페더 링은 이미지 세부 사항 손실, 색상 포화 감소 및 노이즈 증가로 이어질 수 있습니다. 충격을 줄이려면 더 작은 깃털 반경을 사용하고 레이어를 복사 한 다음 깃털을 복사 한 다음 깃털 전후에 이미지 품질을 조심스럽게 비교하는 것이 좋습니다. 또한 깃털이 모든 경우에 적합하지는 않으며 때로는 마스크와 같은 도구가 이미지 가장자리를 처리하는 데 더 적합합니다.

MySQL 설치 후 데이터베이스 성능을 최적화하는 방법 MySQL 설치 후 데이터베이스 성능을 최적화하는 방법 Apr 08, 2025 am 11:36 AM

MySQL 성능 최적화는 설치 구성, 인덱싱 및 쿼리 최적화, 모니터링 및 튜닝의 세 가지 측면에서 시작해야합니다. 1. 설치 후 innodb_buffer_pool_size 매개 변수와 같은 서버 구성에 따라 my.cnf 파일을 조정해야합니다. 2. 과도한 인덱스를 피하기 위해 적절한 색인을 작성하고 Execution 명령을 사용하여 실행 계획을 분석하는 것과 같은 쿼리 문을 최적화합니다. 3. MySQL의 자체 모니터링 도구 (showprocesslist, showstatus)를 사용하여 데이터베이스 건강을 모니터링하고 정기적으로 백업 및 데이터베이스를 구성하십시오. 이러한 단계를 지속적으로 최적화함으로써 MySQL 데이터베이스의 성능을 향상시킬 수 있습니다.

고로드 애플리케이션의 MySQL 성능을 최적화하는 방법은 무엇입니까? 고로드 애플리케이션의 MySQL 성능을 최적화하는 방법은 무엇입니까? Apr 08, 2025 pm 06:03 PM

MySQL 데이터베이스 성능 최적화 안내서 리소스 집약적 응용 프로그램에서 MySQL 데이터베이스는 중요한 역할을 수행하며 대규모 트랜잭션 관리를 담당합니다. 그러나 응용 프로그램 규모가 확장됨에 따라 데이터베이스 성능 병목 현상은 종종 제약이됩니다. 이 기사는 일련의 효과적인 MySQL 성능 최적화 전략을 탐색하여 응용 프로그램이 고 부하에서 효율적이고 반응이 유지되도록합니다. 실제 사례를 결합하여 인덱싱, 쿼리 최적화, 데이터베이스 설계 및 캐싱과 같은 심층적 인 주요 기술을 설명합니다. 1. 데이터베이스 아키텍처 설계 및 최적화 된 데이터베이스 아키텍처는 MySQL 성능 최적화의 초석입니다. 몇 가지 핵심 원칙은 다음과 같습니다. 올바른 데이터 유형을 선택하고 요구 사항을 충족하는 가장 작은 데이터 유형을 선택하면 저장 공간을 절약 할 수있을뿐만 아니라 데이터 처리 속도를 향상시킬 수 있습니다.

MySQL 설치 오류 솔루션 MySQL 설치 오류 솔루션 Apr 08, 2025 am 10:48 AM

MySQL 설치 실패에 대한 일반적인 이유 및 솔루션 : 1. 잘못된 사용자 이름 또는 비밀번호 또는 MySQL 서비스가 시작되지 않았으므로 사용자 이름과 비밀번호를 확인하고 서비스를 시작해야합니다. 2. 포트 충돌, MySQL 청취 포트를 변경하거나 포트 3306을 차지하는 프로그램을 닫아야합니다. 3. 종속성 라이브러리가 없으므로 시스템 패키지 관리자를 사용하여 필요한 종속성 라이브러리를 설치해야합니다. 4. 권한이 부족하면 Sudo 또는 관리자 권한을 사용하여 설치 프로그램을 실행해야합니다. 5. 잘못된 구성 파일, 구성이 올바른지 확인하려면 my.cnf 구성 파일을 확인해야합니다. 꾸준하고 신중하게 확인하는 것만으로 만 MySQL을 원활하게 설치할 수 있습니다.

See all articles