Python 진급 학습은 Python 클래스의 원조-원류를 탐색합니다.

16290 단어 Python원류
Python은 대상을 향한 언어이기 때문에 Python의 숫자, 문자열, 목록, 집합, 사전, 함수, 클래스 등은 모두 대상이다.type()를 사용하여 Python의 객체 유형 보기

In [11]: #  

In [12]: type(10)
Out[12]: int

In [13]: type(3.1415926)
Out[13]: float

In [14]: #  

In [15]: type('a')
Out[15]: str

In [16]: type("abc")
Out[16]: str

In [17]: #  

In [18]: type(list)
Out[18]: type

In [19]: type([])
Out[19]: list

In [20]: #  

In [21]: type(set)
Out[21]: type

In [22]: my_set = {1, 2, 3}

In [23]: type(my_set)
Out[23]: set

In [24]: #  

In [25]: type(dict)
Out[25]: type

In [26]: my_dict = {'name': 'hui'}

In [27]: type(my_dict)
Out[27]: dict

In [28]: #  

In [29]: def func():
    ...:     pass
    ...:

In [30]: type(func)
Out[30]: function

In [31]: #  

In [32]: class Foo(object):
    ...:     pass
    ...:

In [33]: type(Foo)
Out[33]: type

In [34]: f = Foo()

In [35]: type(f)
Out[35]: __main__.Foo

In [36]: # type

In [37]: type(type)
Out[37]: type

알 수 있다
숫자1는 int 형식의 대상입니다.
문자열abc은str 형식의 대상입니다
목록, 집합, 사전은 type 형식의 대상이며, 생성된 대상은 각각 list、set、dict 형식에 속한다
함수func는function 형식의 대상입니다
사용자 정의 클래스Foo가 만든 대상fFoo 유형이고 그 클래스 자체Foo는 type 형식의 대상이다.type 그 자체도 type 유형의 대상이다

클래스도 대상


클래스는 같은 기능과 같은 속성을 가진 대상의 집합이다
대부분의 프로그래밍 언어에서, 클래스는 대상을 어떻게 생성하는지 설명하는 코드 세그먼트입니다.Python에서는 다음과 같은 이점이 있습니다.

In [1]: class ObjectCreator(object):
   ...:     pass
   ...:

In [2]: my_object = ObjectCreator()

In [3]: print(my_object)
<__main__.ObjectCreator object at 0x0000021257B5A248>
하지만 파이썬의 클래스는 이뿐만이 아니다.클래스 역시 하나의 대상이다.네, 맞아요. 바로 상대예요.키워드class를 사용하면 Python 해석기가 실행될 때 대상을 만들 수 있습니다.
다음 코드 세그먼트:

>>> class ObjectCreator(object):
…       pass
…
메모리에 대상을 만들 것입니다. 이름은 ObjectCreator 입니다.이 객체(클래스 객체 ObjectCreator)는 객체(인스턴스 객체)를 작성할 수 있습니다.그러나 그 본질은 여전히 하나의 대상이기 때문에 당신은 그것에 대해 다음과 같은 조작을 할 수 있다.
1. 변수에 값을 부여할 수 있다
2. 복사할 수 있다
3. 당신은 그것을 위해 속성을 증가시킬 수 있습니다
4. 함수 매개 변수로 전달할 수 있다
다음 예제:

In [39]: class ObjectCreator(object):
    ...:     pass
    ...:

In [40]: print(ObjectCreator)
<class '__main__.ObjectCreator'>

In [41]:#  

In [41]: def out(obj):
    ...:     print(obj)
    ...:

In [42]: out(ObjectCreator)
<class '__main__.ObjectCreator'>

In [43]: # hasattr  

In [44]: hasattr(ObjectCreator, 'name')
Out[44]: False

In [45]: #  

In [46]: ObjectCreator.name = 'hui'

In [47]: hasattr(ObjectCreator, 'name')
Out[47]: True

In [48]: ObjectCreator.name
Out[48]: 'hui'

In [49]: #  

In [50]: obj = ObjectCreator

In [51]: obj()
Out[51]: <__main__.ObjectCreator at 0x212596a7248>

In [52]:

2. 동적으로 클래스 만들기


클래스도 대상이기 때문에, 실행할 때 다른 모든 대상처럼 동적으로 만들 수 있습니다.우선, 함수에 클래스를 만들 수 있습니다. class 키워드를 사용하면 됩니다.

def cls_factory(cls_name):
    """
     
    :param: cls_name  
    """
    if cls_name == 'Foo':
        class Foo():
            pass
        return Foo  #  , 

    elif cls_name == 'Bar':
        class Bar():
            pass
        return Bar
IPython 퀴즈

MyClass = cls_factory('Foo')

In [60]: MyClass
Out[60]: __main__.cls_factory.<locals>.Foo #  , 

In [61]: MyClass()
Out[61]: <__main__.cls_factory.<locals>.Foo at 0x21258b1a9c8>
그러나 이것은 아직 동적이지 않다. 왜냐하면 너는 여전히 전체 종류의 코드를 스스로 작성해야 하기 때문이다.클래스도 대상이기 때문에 어떤 것을 통해 생성되어야 한다.
class 키워드를 사용하면 Python 해석기가 자동으로 이 대상을 만듭니다.그러나 Python의 대부분의 일과 마찬가지로, Python은 여전히 당신에게 수동으로 처리하는 방법을 제공합니다.

3. type으로 클래스 만들기


type에는 동적 생성 클래스가 완전히 다른 기능이 있습니다.
type는 클래스의 설명을 매개 변수로 받아들여서 클래스를 되돌려줍니다.(전입 파라미터에 따라 같은 함수가 두 가지 완전히 다른 용법을 가지고 있다는 것은 어리석은 일이지만, 이것은 Python에서 뒤로 호환성을 유지하기 위한 것이다)
type은 다음과 같이 작동합니다.
type (클래스 이름, 상위 클래스 이름으로 구성된 원조 (계승된 경우 비어 있을 수 있음), 속성을 포함하는 사전 (이름과 값)
예를 들어 다음 코드:

In [63]: class Test:
    ...:     pass
    ...:

In [64]: Test()
Out[64]: <__main__.Test at 0x21258b34048>

In [65]:
수동으로 다음과 같이 만들 수 있습니다.

In [69]:#  type 

In [69]: Test2 = type('Test2', (), {})

In [70]: Test2()
Out[70]: <__main__.Test2 at 0x21259665808>
우리는 Test2를 클래스 이름으로 사용하고 그것을 변수로 삼아 클래스의 인용으로 삼을 수도 있다.종류와 변수는 다르다. 여기는 일을 복잡하게 할 아무런 이유가 없다.즉, type 함수 중 첫 번째 실삼은 다른 이름이라고 할 수도 있고, 이 이름은 클래스의 이름을 나타낸다

In [71]: UserCls = type('User', (), {})

In [72]: print(UserCls)
<class '__main__.User'>

In [73]:
이 두 종류를 테스트하기 위해 help 사용

In [74]: #   help   Test 

In [75]: help(Test)
Help on class Test in module __main__:

class Test(builtins.object)
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)


In [76]: #   help   Test2 

In [77]: help(Test2)
Help on class Test2 in module __main__:

class Test2(builtins.object)
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)


In [78]:

4. type을 사용하여 속성이 있는 클래스 만들기


type는 클래스에 대한 속성을 정의하는 사전을 받아들입니다. 따라서

Parent = type('Parent', (), {'name': 'hui'})
번역:

class Parent(object):
	name = 'hui'
또한 Parent 를 일반 클래스처럼 사용할 수 있습니다.

In [79]: Parent = type('Parent', (), {'name': 'hui'})

In [80]: print(Parent)
<class '__main__.Parent'>

In [81]: Parent.name
Out[81]: 'hui'

In [82]: p = Parent()

In [83]: p.name
Out[83]: 'hui'
물론 당신은 이 종류를 계승할 수 있습니다. 코드는 다음과 같습니다.

class Child1(Parent):
    name = 'jack'
    sex =  ' '
    
class Child2(Parent):
    name = 'mary'
    sex = ' '
다음과 같이 쓸 수 있습니다.

Child1 = type('Child1', (Parent, ), {'name': 'jack', 'sex': ' '})

In [85]: Child2 = type('Child2', (Parent, ), {'name': 'mary', 'sex': ' '})

In [87]: Child1.name, Child1.sex
Out[87]: ('jack', ' ')

In [88]: Child2.name, Child2.sex
Out[88]: ('mary', ' ')
참고:
  • type의 두 번째 매개 변수, 모듈은 문자열이 아닌 부류의 이름입니다
  • 에 추가된 속성은 클래스 속성이며 실례 속성이 아니다
  • 5. type을 사용하여 방법이 있는 클래스를 만듭니다


    결국 당신은 당신의 종류를 증가시키는 방법을 원할 것입니다.적절한 서명이 있는 함수를 정의하고 속성으로 값을 부여하면 됩니다.
    인스턴스 추가 방법
    
    Child1 = type('Child1', (Parent, ), {'name': 'jack', 'sex': ' '})
    
    In [85]: Child2 = type('Child2', (Parent, ), {'name': 'mary', 'sex': ' '})
    
    In [87]: Child1.name, Child1.sex
    Out[87]: ('jack', ' ')
    
    In [88]: Child2.name, Child2.sex
    Out[88]: ('mary', ' ')
    
    정적 방법 추가
    
    In [96]: Parent = type('Parent', (), {'name': 'hui'})
    
    In [97]: #  
        
    In [98]: @staticmethod
        ...: def test_static():
        ...:     print('static method called...')
        ...:
    
    In [100]: Child4 = type('Child4', (Parent, ), {'name': 'zhangsan', 'test_static': test_static})
    
    In [101]: c4 = Child4()
    
    In [102]: c4.test_static()
    static method called...
    
    In [103]: Child4.test_static()
    static method called...
    
    클래스 추가 방법
    
    In [105]: Parent = type('Parent', (), {'name': 'hui'})
    
    In [106]: #  
    
    In [107]: @classmethod
         ...: def test_class(cls):
         ...:     print(cls.name)
         ...:
    
    In [108]: Child5 = type('Child5', (Parent, ), {'name': 'lisi', 'test_class': test_class})
    
    In [109]: c5 = Child5()
    
    In [110]: c5.test_class()
    lisi
    
    In [111]: Child5.test_class()
    lisi
    
    파이썬에서 클래스도 대상이고 동적으로 클래스를 만들 수 있다는 것을 볼 수 있습니다.이것이 바로 당신이 키워드class를 사용할 때Python 막후에서 하는 일이고 원류를 통해 이루어지는 것이다.
    비교적 완전하게 type을 사용하여 클래스를 만드는 방법:
    
    class Animal(object):
        
        def eat(self):
            print(' ')
    
    
    def dog_eat(self):
        print(' ')
    
    def cat_eat(self):
        print(' ')
    
    
    Dog = type('Dog', (Animal, ), {'tyep': ' ', 'eat': dog_eat})
    
    Cat = type('Cat', (Animal, ), {'tyep': ' ', 'eat': cat_eat})
    
    # ipython  
    In [125]: animal = Animal()
    
    In [126]: dog = Dog()
    
    In [127]: cat = Cat()
    
    In [128]: animal.eat()
     
    
    In [129]: dog.eat()
     
    
    In [130]: cat.eat()
     
    

    6. 도대체 무엇이 원류인가(드디어 주제에 이르렀다)


    원류는 바로 종류를 만드는 데 쓰이는 것이다.당신이 클래스를 만드는 것은 클래스의 실례 대상을 만들기 위한 것이지 않습니까?하지만 우리는 파이썬의 클래스도 대상이라는 것을 배웠다.
    메타클래스는 이러한 클래스(대상)를 만드는 데 사용되고, 메타클래스는 클래스의 클래스입니다. 당신은 다음과 같이 이해할 수 있습니다.
    
    MyClass = MetaClass() #  , “ ”
    my_object = MyClass() #  “ ” 
    이렇게 할 수 있는 type을 보았습니다.
    
    MyClass = type('MyClass', (), {})
    함수type가 사실상 원류이기 때문이다.type 바로 파이썬이 뒤에서 모든 클래스를 만드는 데 사용하는 원류입니다.지금 궁금해요. 그런데 왜 타입은 타입이 아니라 소문자로 쓰입니까?알겠습니다. 이것은 str와 일치성을 유지하기 위해서입니다.str는 문자열 대상을 만드는 클래스이고, int는 정수 대상을 만드는 클래스입니다.type은 클래스 대상을 만드는 클래스입니다.너는 __class__ 속성을 검사해서 이 점을 볼 수 있다.그래서 Python에서는 만물이 대상입니다.
    현재 어느 __class____class__ 속성에 대해서도 무엇일까요?
    
    In [136]: a = 10
    
    In [137]: b = 'acb'
    
    In [138]: li = [1, 2, 3]
    
    In [139]: a.__class__.__class__
    Out[139]: type
    
    In [140]: b.__class__.__class__
    Out[140]: type
    
    In [141]: li.__class__.__class__
    Out[141]: type
    
    In [142]: li.__class__.__class__.__class__
    Out[142]: type
    
    따라서 원류는 이런 대상을 만드는 것이다.type은 바로Python의 내장 원류입니다. 물론, 당신도 자신의 원류를 만들 수 있습니다.

    7. metaclass 속성


    클래스를 정의할 때 __metaclass__ 속성을 추가할 수 있습니다.
    
    class Foo(object):
        __metaclass__ = something…
        ... ...
    만약 네가 이렇게 한다면, Python은 원류로 클래스 Foo를 만들 것이다.조심해, 이 안에 기교가 좀 있어.먼저 class Foo(object) 를 쓰십시오. 그러나 클래스 Foo는 메모리에 생성되지 않았습니다.파이썬은 클래스의 정의에서 __metaclass__ 속성을 찾습니다. 찾으면 파이썬은 클래스 Foo를 만들고, 찾지 못하면 내장된 type 으로 클래스를 만듭니다.
    
    class Foo(Bar):
        pass
    Python은 다음과 같은 작업을 수행했습니다.
    1. Foo에 __metaclass__ 이 속성이 있습니까?있는 경우 파이썬은 __metaclass__를 통해 Foo라는 클래스(객체)를 만듭니다.
    2. Python이 __metaclass__를 찾지 못하면 Bar(부류)에서 __metaclass__ 속성을 계속 찾고 앞과 같은 작업을 시도합니다.
    3. 만약 Python이 어떤 부류에서도 찾을 수 없다면__metaclass__, 모듈 차원에서 __metaclass__을 찾고 같은 조작을 시도할 것이다.
    4. 만약 __metaclass__를 찾지 못한다면, 파이썬은 내장된 type 으로 이 종류의 대상을 만들 것입니다.
    지금의 문제는 __metaclass__에 어떤 코드를 놓을 수 있느냐는 것이다.
    답은 하나의 종류를 만들 수 있다는 것이다.그러면 어떤 종류를 만들 수 있습니까?type, 또는 type이나 하위 클래스화된 type에 사용할 수 있습니다.

    8. 사용자 정의 클래스


    원류의 주요 목적은 클래스를 만들 때 자동으로 클래스를 바꿀 수 있도록 하는 것이다.
    바보 같은 예를 가상해 보세요. 모듈에 있는 모든 종류의 속성은 대문자 형식이어야 합니다.여러 가지 방법이 있지만 그 중 하나는 모듈 등급 설정__metaclass__을 통해 할 수 있다.이런 방법을 채택하면 이 모듈의 모든 종류는 이 원류를 통해 만들어진다. 우리는 원류에게 모든 속성을 대문자 형식으로 바꾸는 것만 알려주면 된다.
    다행히도 __metaclass__ 실제로는 임의로 호출될 수 있으며, 정식 클래스가 필요하지 않다.그래서 우리는 여기서 간단한 함수를 예로 삼아 시작한다.
    python2 중
    
    # -*- coding:utf-8 -*-
    def upper_attr(class_name, class_parents, class_attr):
    
        # class_name   Foo
        # class_parents   object
        # class_attr  
    
        #  , __ 
        new_attr = {}
        for name, value in class_attr.items():
            if not name.startswith("__"):
                new_attr[name.upper()] = value
    
        #  type 
        return type(class_name, class_parents, new_attr)
    
    class Foo(object):
        __metaclass__ = upper_attr #  Foo upper_attr
        bar = 'bip'
    
    print(hasattr(Foo, 'bar'))
    # Flase
    print(hasattr(Foo, 'BAR'))
    # True
    
    f = Foo()
    print(f.BAR)
    
    python3 중
    
    # -*- coding:utf-8 -*-
    def upper_attr(class_name, class_parents, class_attr):
    
        # , __ 
        new_attr = {}
        for name,value in class_attr.items():
            if not name.startswith("__"):
                new_attr[name.upper()] = value
    
        # type 
        return type(class_name, class_parents, new_attr)
    
    #  () metaclass
    class Foo(object, metaclass=upper_attr):
        bar = 'bip'
    
    print(hasattr(Foo, 'bar'))
    # Flase
    print(hasattr(Foo, 'BAR'))
    # True
    
    f = Foo()
    print(f.BAR)
    
    다시 한 번, 이번에는 진정한 class 을 원류로 삼는다.
    
    class UpperAttrMetaClass(type):
        
        def __new__(cls, class_name, class_parents, class_attr):
            #  , __ 
            new_attr = {}
            for name, value in class_attr.items():
                if not name.startswith("__"):
                    new_attr[name.upper()] = value
    
            #  1: 'type' 
            return type(class_name, class_parents, new_attr)
    
            #  2: type.__new__ 
            #  OOP , 
            # return type.__new__(cls, class_name, class_parents, new_attr)
    
            
    # python3 
    class Foo(object, metaclass=UpperAttrMetaClass):
        bar = 'bip'
    
    # python2 
    class Foo(object):
    	__metaclass__ = UpperAttrMetaClass
        bar = 'bip'
    
    
    print(hasattr(Foo, 'bar'))
    #  : False
    print(hasattr(Foo, 'BAR'))
    #  : True
    
    f = Foo()
    print(f.BAR)
    #  : 'bip'
    
    
    __new__  __init__ 
    __new__ 
     __init__ 
     , , , __new__
    그렇습니다. 그 외에 원류에 관해서는 정말 더 이상 할 말이 없습니다.그러나 원류 자체로 말하자면 그것들은 사실 매우 간단하다.
    1. 차단 클래스 생성
    2. 클래스 수정
    3. 수정된 클래스 되돌리기

    총결산


    이제 우리의 큰 주제로 돌아가면 도대체 왜 당신은 이런 실수하기 쉽고 난삽한 특성을 사용합니까?
    그래, 일반적으로 말하자면, 너는 전혀 그것을 사용할 수 없다.
    "원류는 깊은 마법이다. 99퍼센트의 사용자들은 전혀 걱정할 필요가 없다. 원류를 사용해야 하는지 알고 싶다면 원류를 필요로 하지 않는다. 원류를 실제로 사용하는 사람들은 그들이 무엇을 해야 하는지 잘 알고 있으며, 왜 원류를 사용해야 하는지 설명할 필요가 없다."파이썬계의 리더 Tim Peters
    파이썬 진급 학습에 관한 이 글은 파이썬 클래스의 원조-원류를 탐색하는 데 도움이 됩니다. 파이썬 원류에 대한 더 많은 내용은 저희 이전의 글을 검색하거나 아래의 관련 글을 계속 찾아보세요. 앞으로 많은 응원 부탁드립니다!

    좋은 웹페이지 즐겨찾기