Python 기초의 원 프로그래밍 지식 총결산

1. 앞말


우선 파이썬의 모든 것은 대상이다.그리고Python은 많은 특수한 방법, 원류 등등'원 프로그래밍'메커니즘을 제공했다.대상의 동적 속성 추가 방법 같은 것은Python에서'원 프로그래밍'이라고 할 수 없지만 일부 정적 언어에서는 일정한 기교가 필요한 것이다.파이썬 프로그래머도 헷갈리기 쉬운 것들을 이야기합시다.
우리는 먼저 대상을 차원별로 나눈다. 보통 우리는 하나의 대상이 그 유형이 있다는 것을 알고 있다. 예전에Python은 유형도 대상으로 실현했다.이렇게 해서 우리는 실례 대상과 유형 대상이 생겼다.이것은 두 차원이다.조금만 기초가 있는 독자들은 원류라는 물건의 존재를 알게 될 것이다. 간단히 말하면 원류는'류'의'류', 즉 류보다 높은 차원의 물건이다.이것은 또 하나의 차원이 생겼다.또 있어요?

2. ImportTime vs RunTime


만약 우리가 각도를 바꾸면, 굳이 이전의 세 단계와 같은 표준을 사용할 필요가 없다.Import Time과 Run Time은 경계가 뚜렷하지 않고 말 그대로 두 시간, 가져올 때와 실행할 때를 구분합니다.
모듈을 가져올 때 무슨 일이 일어날까요?전역 역할 영역의 문장 (비정의적인 문장) 이 실행됩니다.함수 정의는요?함수 대상이 만들어지지만 코드는 실행되지 않습니다.클래스 정의는요?클래스 대상이 만들어지고 클래스 정의 영역의 코드가 실행되며 클래스 방법의 코드도 실행되지 않습니다.
실행할 때는요?함수와 방법의 코드가 실행됩니다.물론 네가 먼저 그것들을 호출해야 한다.

삼, 원류


그래서 우리는 원류와 클래스는 ImportTime에 속한다고 말할 수 있다.import의 모듈이 만들어지면 그것들은 만들어진다.인스턴스 객체는 RunTime에 속하며 import 하나로는 인스턴스 객체를 만들지 않습니다.모듈 역할 영역에서 실례화 클래스를 실행하면 실례 대상도 만들어지기 때문에 너무 절대적으로 말할 수 없습니다.단지 우리는 통상적으로 그것들을 함수에 쓰기 때문에 이렇게 구분한다.
만약 당신이 발생하는 실례 대상의 특성을 제어하고 싶다면 어떻게 해야 합니까?너무 간단합니다. 클래스 정의에서 __ 다시 쓰기init__방법그렇다면 우리는 류의 일부 성질을 통제해야 합니까?이런 수요가 있습니까?당연히 있지!
고전적인 단례 모델은 여러 가지 실현 방식이 있다는 것을 모두가 알고 있다.요구는 한 종류에 하나의 실례만 있을 수 있다는 것이다.
가장 간단한 실현 방법은 이렇다

class _Spam:
    def __init__(self):
        print("Spam!!!")

_spam_singleton =None

def Spam():
    global _spam_singleton
    if _spam_singleton is not None:
        return _spam_singleton
    else:
        _spam_singleton = _Spam()
        return _spam_singleton
공장 모델은 그다지 우아하지 않다.우리는 한 종류에 한 가지 실례만 있을 수 있도록 수요를 다시 한 번 살펴보자.우리가 클래스에서 정의한 방법은 모두 실례 대상의 행위이다. 그러면 클래스의 행위를 바꾸려면 더욱 높은 차원의 것이 필요하다.원류는 이때 등장하기에 적합하지 않다.앞에서 말했듯이 원류는 류의 류이다.즉, 원류의 __init__ 방법은 류의 초기화 방법이다.우리는 또한 __call__ 이 물건이 실례를 함수처럼 호출할 수 있다는 것을 알고 있다. 그러면 원류의 이 방법은 클래스가 실례화될 때 호출되는 방법이다.
코드를 쓸 수 있습니다.

class Singleton(type):
    def __init__(self, *args, **kwargs):
        self._instance = None
        super().__init__(*args, **kwargs)

    def __call__(self, *args, **kwargs):
        if self._instance is None:
            self._instance = super().__call__(*args, **kwargs)
            return self._instance
        else:
            return self._instance


class Spam(metaclass=Singleton):
    def __init__(self):
        print("Spam!!!")
주로 두 군데가 일반적인 클래스 정의와 다르다. 하나는 Singleton의 기본 클래스는 type이고, 하나는 Spam이 정의한 곳에는 metaclass=Singleton이 있다.type이 뭐예요?이것은object의 하위 클래스이고,object는 그것의 실례이다.즉, type은 모든 종류의 종류, 즉 가장 기본적인 원류로 모든 종류가 발생할 때 필요한 조작을 규정한다.그래서 사용자 정의 클래스는 하위 클래스화 type이 필요합니다.또한 type도 하나의 대상이기 때문에object의 하위 클래스입니다.좀 이해가 안 돼요. 대충 알면 돼요.

4. 장식기


우리 다시 장식기를 이야기합시다.대부분의 사람들은 장식기가 파이썬에서 가장 이해하기 어려운 개념 중의 하나라고 생각한다.사실 그것은 문법 설탕에 불과하고 함수를 이해한 후에도 대상이다.자신의 장식기를 쉽게 쓸 수 있을 거예요.

from functools import wraps

def print_result(func):

    @wraps(func)
    def wrappper(*args, **kwargs):
        result = func(*args, **kwargs)
        print(result)
        return result

    return wrappper

@print_result
def add(x, y):
    return x + y
# :
#add = print_result(add)

add(1, 3)
여기에 우리는 장식기 @wraps를 사용했습니다. 이것은 우리가 되돌아오는 내부 함수인 wrapper와 원래의 함수가 같은 함수 서명을 가지도록 하는 것입니다. 기본적으로 우리는 장식기를 쓸 때 그것을 추가해야 합니다.
주석에 @decorator와 같은 형식은func=decorator(func)와 같다는 점을 이해하면 우리는 더 많은 종류의 장식기를 쓸 수 있다.예를 들어 유형 장식기, 그리고 장식기를 하나의 유형으로 쓴다.

def attr_upper(cls):
    for attrname,value in cls.__dict__.items():
        if isinstance(value,str):
            if not value.startswith('__'):
                setattr(cls,attrname,bytes.decode(str.encode(value).upper()))
    return cls    

@attr_upper
class Person:
    sex = 'man'

print(Person.sex) # MAN
일반적인 장식기와 유형 장식기가 실현하는 차이점을 주의해라.

5. 데이터에 대한 추상적인 C 설명자


만약에 우리가 어떤 클래스가 같은 특성을 가지게 하거나 클래스 정의에 대한 제어를 실현하고자 한다면, 우리는 하나의 클래스를 사용자 정의하여 이러한 클래스의 클래스가 되도록 할 수 있다.만약 우리가 어떤 함수들이 같은 기능을 가지고 있고 코드를 복사해서 한 번 붙이고 싶지 않다면, 우리는 장식기를 정의할 수 있다.그렇다면 만약에 우리가 실례의 속성에 어떤 공통된 특징을 가지게 하고 싶다면?누군가는property를 사용할 수 있다고 말할 수도 있습니다. 물론입니다.그러나 이러한 논리는 모든 종류가 정의될 때 한 번 써야 한다.만약 우리가 이 클래스의 실례적인 일부 속성을 모두 같은 특징을 가지게 하려고 한다면, 묘사부호 클래스를 사용자 정의할 수 있다.
여기 저희가 예를 좀 드릴게요.

class TypedField:
    def __init__(self, _type):
        self._type = _type

    def __get__(self, instance, cls):
        if instance is None:
            return self
        else:
            return getattr(instance, self.name)

    def __set_name__(self, cls, name):
        self.name = name

    def __set__(self, instance, value):
        if not isinstance(value, self._type):
            raise TypeError('Expected' + str(self._type))
        instance.__dict__[self.name] = value

class Person:
    age = TypedField(int)
    name = TypedField(str)

    def __init__(self, age, name):
        self.age = age
        self.name = name

jack = Person(15, 'Jack')
jack.age = '15'  #  
이 안에 몇 가지 캐릭터가 있는데 TypedField는 묘사부호류이고 속성Person은 묘사부호류의 실례이다. 묘사부호는 Person, 즉 클래스의 속성이지 실례적인 속성이 존재하는 것이 아닌 것처럼 보인다.그러나 실제로 Person의 인스턴스가 같은 이름의 속성에 액세스하면 설명자가 작동합니다.주의해야 할 것은 Python3.5 및 이전 버전에는 __set_name__라는 특수한 방법이 없다. 이것은 클래스 정의에서 묘사자가 어떤 이름을 지었는지 알고 싶다면 묘사자가 실례화될 때 현식으로 전달해야 한다는 것을 의미한다. 즉, 매개 변수가 하나 더 필요하다는 것이다.그러나 Python3.6에서 이 문제는 해결되었고 묘사부류 정의에서 __set_name__ 이 방법을 다시 쓰면 된다.또 주의해야 할 것은 __get__의 작법은 기본적으로 instance에 대한 판단이 필수적이다. 그렇지 않으면 잘못을 보고할 수 있다.원인도 이해하기 어렵지 않으니 자세히 말하지 않겠다.

6. 하위 클래스의 생성을 제어하는 방법 - 원류를 대체하는 방법


Python3.6에서 우리는 __init_subclass__특수한 방법은 하위 클래스의 생성을 정의하는 것이다. 그러면 우리는 어떤 상황에서 원류라는 싫은 것에서 벗어날 수 있다.

class PluginBase:
    subclasses = []

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.subclasses.append(cls)

class Plugin1(PluginBase):
    pass

class Plugin2(PluginBase):
    pass
소결, 예를 들어 원류 등 원 프로그래밍은 대다수 사람들에게 좀 까다롭고 이해하기 어려워서 대다수 때도 그것들을 사용할 필요가 없다.그러나 대부분의 프레임워크 뒤의 실현은 이런 기교를 사용해야만 사용자가 쓴 코드를 간결하고 이해하기 쉽게 할 수 있다.이러한 기교를 더욱 깊이 있게 이해하고 싶다면, 예를 들면, (이 글의 내용은 그것들을 참고한 것이다), 또는 공식 문서의 일부 장, 예를 들어 위에서 말한 묘사부호 wTo, 그리고 데이터 모델 1절 등을 참고할 수 있다.또는 파이썬의 원본 코드를 직접 보십시오. 파이썬으로 쓴 것과 CPython의 원본 코드를 포함합니다.
그것들을 충분히 이해한 후에 사용해야지, 이런 기교를 어디에서나 사용할 생각은 하지 말아야 한다는 것을 명심해라.
파이썬 기초의 원 프로그래밍 지식에 대한 이 글을 소개합니다. 파이썬 원 프로그래밍에 대한 더 많은 내용은 저희 이전의 글을 검색하거나 아래의 관련 글을 계속 훑어보십시오. 앞으로 많은 응원 부탁드립니다!

좋은 웹페이지 즐겨찾기