μ½”λ“œ - 패캠 μˆ˜μ—… μ½”λ“œ μ°Έκ³  (패캠 μˆ˜μ—… 정리)

 

 

<이전 κΈ€>

https://silvercoding.tistory.com/27

 

[python 심화] 10. copy & deep copy

μ½”λ“œ - 패캠 μˆ˜μ—… μ½”λ“œ μ°Έκ³  (패캠 μˆ˜μ—… 정리) <이전 κΈ€> https://silvercoding.tistory.com/26 https://silvercoding.tistory.com/25 이번 ν¬μŠ€νŠΈμ—μ„œλŠ” λ°μ½”λ ˆμ΄ν„°λ₯Ό μ•Œμ•„λ³Ό 것이닀. λ°μ½”λ ˆμ΄ν„°λŠ” μ–΄λ ΅λ‹€κ³  느..

silvercoding.tistory.com

 

 

 

- Class  Getter & Setter 

* 클래슀 μ„ μ–Έ 

class VectorP(object):
    def __init__(self, x, y):
        self.__x = float(x)
        self.__y = float(y)

    def __iter__(self):
        return (i for i in (self.__x, self.__y)) # Generator

 

 

* 객체 μ„ μ–Έ 

v = VectorP(20, 40)

 

* 였λ₯˜

print('EX1-1 - ', v.__x, v.__y)  # ---> 직접 μ ‘κ·Ό λΆˆκ°€

 AttributeError: 'VectorP' object has no attribute '__x' 

 μ–Έλ”λ°” 2개둜 μ„ μ–Έν•œ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λŠ” 객체λ₯Ό ν†΅ν•œ 직접 접근이 λΆˆκ°€λŠ₯ ν•˜λ‹€. 

 

 

 

 

- Getter & Setter 

: 더 μ•ˆμ „ν•œ ν”„λ‘œκ·Έλž˜λ°μ„ ν•  수 μžˆλ‹€. 

class VectorP(object):
    def __init__(self, x, y):
        self.__x = float(x)
        self.__y = float(y)

    def __iter__(self):
        return (i for i in (self.__x, self.__y)) # Generator

    @property
    def x(self):
        print('Called Property X')
        return self.__x

    @x.setter
    def x(self, v):
        print('Called Property X setter')
        self.__x = float(v)
    
    @property
    def y(self):
        print('Called Property Y')
        return self.__y

    @y.setter
    def y(self, v):
        print('Called Property Y setter')        
        if v < 30: 
            raise ValueError('30 Below is not possible')
        self.__y = float(v)

λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•˜μ—¬ @property, @x.setter @y.setter 밑에 x와 yλ₯Ό μ •μ˜ν•΄ μ€€λ‹€. 

 

 

print('EX1-2 - ', dir(v), v.__dict__)
v.x = 10
print('EX1-3 - ', v.x, v.y)

 EX1-2 -  ['_VectorP__x', '_VectorP__y', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'x', 'y'] {'_VectorP__x': 20.0, '_VectorP__y': 40.0} 
 Called Property X 
 Called Property Y 
 EX1-3 -  10.0 40.0 

Getter와 Setterλ₯Ό μ΄μš©ν•˜μ—¬ self.__x λ³€μˆ˜μ— self.x 의 ν˜•νƒœλ‘œ 접근이 κ°€λŠ₯ν•΄ μ‘Œλ‹€. v.x=10 을 μ΄μš©ν•˜μ—¬ 값을 λ°”κΏ€ 수 μžˆλŠ” 것 λ˜ν•œ λ³Ό 수 μžˆλ‹€. 

 

# Iter 확인 
for val in v:
    print('EX1-4 - ', val)

 EX1-4 -  10.0 
 EX1-4 -  40.0 

κ΅¬ν˜„ν•΄ 놓은 __iter__ λ©”μ†Œλ“œλ₯Ό ν™•μΈν•˜μ˜€λ‹€. 

 

 

 

- __slot__ 

: 파이썬 μΈν„°ν”„λ¦¬ν„°μ—κ²Œ 톡보 , ν•΄λ‹Ή ν΄λž˜μŠ€κ°€ κ°€μ§€λŠ” 속성을 μ œν•œ 

* __dict__ 

: 속성 μ΅œμ ν™” -> λ‹€μˆ˜ 객체 생성 μ‹œ λ©”λͺ¨λ¦¬ μ‚¬μš© 곡간 λŒ€ν­ κ°μ†Œ 

: ν•΄λ‹Ή ν΄λž˜μŠ€μ— λ§Œλ“€μ–΄μ§„ μΈμŠ€ν„΄μŠ€ 속성 관리에 λ”•μ…”λ„ˆλ¦¬ λŒ€μ‹  set ν˜•νƒœλ₯Ό μ‚¬μš© 

 

class TestA(object):
    __slots__ = ('a', )

class TestB(object):
    pass

 

 

* 객체 생성 

use_slot = TestA()
no_slot = TestB()

 

* μ‚¬μš©

print('EX2-1 - ', use_slot)
# print('EX2-2 - ', use_slot.__dict__)  # 속성 κ°’ 확인 --> dictionary이기 λ•Œλ¬Έμ— μ•ˆλ¨ 
print('EX2-3 - ', no_slot)
print('EX2-3 - ', no_slot.__dict__)

 EX2-1 -  <__main__.TestA object at 0x000001BE68801C78> 
 EX2-3 -  <__main__.TestB object at 0x000001BE68A4D6A0> 
 EX2-3 -  {} 

 

 

* λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰ 비ꡐ

import timeit

# 츑정을 μœ„ν•œ ν•¨μˆ˜ μ„ μ–Έ 
def repeat_outer(obj):
    def repeat_inner():
        obj.a = 'TEST'
        del obj.a
    return repeat_inner

obj.a = 'TEST' λ₯Ό μ„ μ–Έν•˜κ³  obj.aλ₯Ό μ‚­μ œν•˜λŠ” μ‹œκ°„μ„ μΈ‘μ •ν•˜κΈ° μœ„ν•œ ν•¨μˆ˜λ₯Ό μƒμ„±ν•œλ‹€. 

 

print(min(timeit.repeat(repeat_outer(use_slot), number=100000))) 
print(min(timeit.repeat(repeat_outer(no_slot), number=100000)))

 0.015717999999999982 
 0.018735899999999972 

100000λ²ˆμ„ λ°˜λ³΅ν•˜μ—¬ κ°€μž₯ μž‘μ€ μ‹œκ°„μ„ 좜λ ₯ν•΄ λ³΄μ•˜μ„ λ•Œ, slot을 μ‚¬μš©ν•œ 클래슀의 객체가 더 λΉ λ₯Έ 것을 μ•Œ 수 μžˆλ‹€. 

 

 

 

- 객체 μŠ¬λΌμ΄μ‹±

class ObjectS:
    def __init__(self):
        self._numbers = [n for n in range(1, 100, 3)]

    def __len__(self):
        return len(self._numbers)

    def __getitem__(self, idx):
        return self._numbers[idx]

μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λ₯Ό 리슀트 νƒ€μž…μœΌλ‘œ μƒμ„±ν•˜κ³ , __len__, __getitem__ λ©”μ†Œλ“œλ₯Ό μ„ μ–Έν•΄ 놓은 ObjectS 클래슀λ₯Ό μƒμ„±ν•œλ‹€. 

 

* 객체 생성

s = ObjectS()

 

print('EX3-1 - ', s.__dict__)    
print('EX3-2 - ', len(s))
print('EX3-3 - ', len(s._numbers))  # __len__ 이 μ—†μœΌλ©΄ . 
print('EX3-4 - ', s[1:100])
print('EX3-5 - ', s[-1])
print('EX3-6 - ', s[::10])

 EX3-1 -  {'_numbers': [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49,  
 52, 55, 58, 61, 64, 67, 70, 73, 76, 79, 82, 85, 88, 91, 94, 97]} 

 EX3-2 -  33 
 EX3-3 -  33 

__len__ λ©”μ†Œλ“œλ₯Ό μ„ μ–Έν•΄ 놓지 μ•ŠλŠ”λ‹€λ©΄ EX3-3κ³Ό 같이 μž‘μ„±ν•˜μ—¬ 리슀트의 길이λ₯Ό 확인할 수 μžˆλ‹€. 
 EX3-4 -  [4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 52, 55, 58, 61,  
 64, 67, 70, 73, 76, 79, 82, 85, 88, 91, 94, 97] 
 EX3-5 -  97 
 EX3-6 -  [1, 31, 61, 91] 

 

__getitem__ λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ 객체 μžμ²΄μ—μ„œ 인덱싱과 μŠ¬λΌμ΄μ‹±μ„ κ°€λŠ₯ν•˜κ²Œ λ§Œλ“€μ—ˆλ‹€. λ§Œμ•½ __getitem__ λ©”μ†Œλ“œλ₯Ό μƒμ„±ν•˜μ§€ μ•Šμ•˜λ‹€λ©΄ λ‹€μŒκ³Ό 같은 μ—λŸ¬κ°€ λ‚œλ‹€.

 

 Traceback (most recent call last): 
  File "c:/Users/sooki/Desktop/python_high/chapter05_02.py", line 114, in <module>      
    print('EX3-4 - ', s[1:100])
 TypeError: 'ObjectS' object is not subscriptable 

 

 

 

 

- 파이썬 좔상 클래슀 

https://docs.python.org/3/library/collections.abc.html

 

collections.abc — Abstract Base Classes for Containers — Python 3.9.6 documentation

collections.abc — Abstract Base Classes for Containers New in version 3.3: Formerly, this module was part of the collections module. Source code: Lib/_collections_abc.py This module provides abstract base classes that can be used to test whether a class

docs.python.org

1. 자체적으둜 객체 생성 λΆˆκ°€ 

2. 상속을 ν†΅ν•΄μ„œ 'μžμ‹ 클래슀' μ—μ„œ 생성해야 함 

3. 개발과 κ΄€λ ¨λœ κ³΅ν†΅λœ λ‚΄μš© (ν•„λ“œ, λ©”μ†Œλ“œ) μΆ”μΆœ 및 ν†΅ν•©ν•΄μ„œ κ³΅ν†΅λœ λ‚΄μš©μœΌλ‘œ μž‘μ„±ν•˜κ²Œ ν•˜λŠ” 것

 

 

 

** Sequence 상속 받지 μ•Šμ•˜μ§€λ§Œ, μžλ™μœΌλ‘œ __iter__, __contain__ κΈ°λŠ₯ μž‘λ™ 

** 객체 전체λ₯Ό μžλ™μœΌλ‘œ 쑰사 -> μ‹œν€€μŠ€ ν”„λ‘œν† μ½œ 

class IterTestA():
    def __getitem__(self, idx):
        return range(1, 50, 2)[idx] # range(1, 50, 2)

__getitem__ λ©”μ†Œλ“œλ₯Ό μ„ μ–Έν•œ IterTestA 클래슀λ₯Ό μƒμ„±ν•œλ‹€. 

 

 

* 객체 생성

i1 = IterTestA()

 

print('EX4-1 - ', i1[4])
print('EX4-2 - ', i1[4:10])
print('EX4-3 - ', 3 in i1[1:10])  # __contain__ κ΅¬ν˜„ν•˜μ§€ μ•Šμ•„λ„ μ‚¬μš©λ¨ 
print('EX4-4 - ', [i for i in i1]) # κ΅¬ν˜„ν•˜μ§€ μ•Šμ€ __iter__ μ‹€ν–‰

 EX4-1 -  9 
 EX4-2 -  range(9, 21, 2) 
 EX4-3 -  True 
 EX4-4 -  [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49] 

인덱싱과 μŠ¬λΌμ΄μ‹±μ΄ κ°€λŠ₯ν•˜λ„λ‘ __getitem__ λ©”μ†Œλ“œλ§Œ 생성을 ν•΄ λ†“μ•˜μ§€λ§Œ , 4-3, 4-4 κ°€ 싀행이 λ˜λŠ” 것을 λ³Ό 수 μžˆλ‹€. __contain__κ³Ό __iter__λ©”μ†Œλ“œλ₯Ό 클래슀 내에 μƒμ„±ν•˜μ§€ μ•Šμ•˜μ–΄λ„ 싀행이 된 것이닀. 

 

 

 

 

- Sequence 상속 

: μš”κ΅¬μ‚¬ν•­μΈ μΆ”μƒλ©”μ†Œλ“œλ₯Ό λͺ¨λ‘ κ΅¬ν˜„ν•΄μ•Ό λ™μž‘ 

from collections.abc import Sequence

class IterTestB(Sequence):
    def __getitem__(self, idx):
        return range(1, 50, 2)[idx] # range(1, 50, 2)

    def __len__(self, idx):
        return len(range(1, 50, 2)[idx])

Sequenceλ₯Ό 상속 λ°›λŠ” IterTestB 클래슀λ₯Ό μƒμ„±ν•œλ‹€.  __getitem__, __len__ <--- 이 λ‘κ°œμ˜ λ©”μ†Œλ“œλ₯Ό κ΅¬ν˜„ν•˜μ§€ μ•ŠμœΌλ©΄ λ™μž‘ν•˜μ§€ μ•ŠλŠ”λ‹€. 

i2 = IterTestB()  # ---> __getitem__, __len__ ν•¨μˆ˜κ°€ μ—†μœΌλ©΄ 객체 생성 λΆˆκ°€. (κ°•μ œμ„±μ„ λˆλ‹€.)

λ‘κ°œμ˜ λ©”μ†Œλ“œλ₯Ό ν•˜λ‚˜λΌλ„ κ΅¬ν˜„ν•˜μ§€ μ•ŠμœΌλ©΄ λ‹€μŒκ³Ό 같은 μ—λŸ¬κ°€ λ‚œλ‹€. 

TypeError: Can't instantiate abstract class IterTestB with abstract methods __len__  

 

print('EX4-5 - ', i2[4])
print('EX4-6 - ', i2[4:10])
print('EX4-7 - ', 3 in i2[1:10])

 EX4-5 -  9 
 EX4-6 -  range(9, 21, 2) 
 EX4-7 -  True 

 

 

 

 

 

 

- abc ν™œμš© 예제 

https://docs.python.org/ko/3/library/abc.html

 

abc — 좔상 베이슀 클래슀 — Python 3.9.6 λ¬Έμ„œ

abc — 좔상 베이슀 클래슀 μ†ŒμŠ€ μ½”λ“œ: Lib/abc.py 이 λͺ¨λ“ˆμ€, PEP 3119μ—μ„œ μ„€λͺ…λœ λŒ€λ‘œ, νŒŒμ΄μ¬μ—μ„œ 좔상 베이슀 클래슀 (ABC) λ₯Ό μ •μ˜ν•˜κΈ° μœ„ν•œ 기반 ꡬ쑰λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€; 이것이 μ™œ νŒŒμ΄μ¬μ— μΆ”κ°€λ˜μ—ˆ

docs.python.org

import abc

class RandomMachine(abc.ABC): # metaclass=abc.ABCMeta(3.4 μ΄ν•˜)
    # __metaclass__ = abc.ABCMeta

    #좔상 λ©”μ†Œλ“œ  ---> λ°μ½”λ ˆμ΄ν„°κ°€ 뢙은 건 무쑰건 μžμ‹ ν΄λž˜μŠ€μ—μ„œ κ΅¬ν˜„ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€.
    @abc.abstractmethod
    def load(self, iterobj):
        '''Iterable ν•­λͺ© μΆ”κ°€'''

    # 좔상 λ©”μ†Œλ“œ 
    @abc.abstractmethod
    def pick(self, iterobj):
        '''λ¬΄μž‘μœ„ ν•­λͺ© 뽑기'''

    def inspect(self):
        items = []
        while True:
            try:
                items.append(self.pick())
            except LookupError:
                break
            return tuple(sorted(items))

λ°μ½”λ ˆμ΄ν„°λ‘œ @abc.abstractmethod κ°€ 뢙은 λ©”μ†Œλ“œλŠ” 무쑰건 μžμ‹ ν΄λž˜μŠ€μ—μ„œ κ΅¬ν˜„ ν•΄μ£Όμ–΄μ•Ό ν•˜λŠ” λ©”μ†Œλ“œμ΄λ‹€ . load와 pick λ©”μ†Œλ“œμ— λ°μ½”λ ˆμ΄ν„°κ°€ λ‹¬λ €μžˆλ‹€. μœ„μ™€ 같이 abcλ₯Ό μƒμ†λ°›λŠ” μΆ”μƒν΄λž˜μŠ€μ— λ°μ½”λ ˆμ΄ν„° λ©”μ†Œλ“œλ₯Ό κ΅¬ν˜„ν•˜κ³ , λ©”μ†Œλ“œμ— 주석 μ„€λͺ…을 달아 λ†“μœΌλ©΄ μžμ‹ ν΄λž˜μŠ€μ—μ„œ μžμ„Έν•œ κ΅¬ν˜„μ„ ν•˜κ²Œλ˜λŠ” 방식이닀. 

 

import random

class CraneMachine(RandomMachine):
    def __init__(self, items):
        self._randomizer = random.SystemRandom()
        self._items = []
        self.load(items)
        
    def load(self, items):
        self._items.extend(items)
        self._randomizer.shuffle(self._items)

    def pick(self):
        try:
            return self._items.pop()
        except IndexError:
            raise LookupError('Empty Crane Box')

    def __call__(self):
        return self.pick()

이와 같이 abcλ₯Ό μƒμ†λ°›μ•˜λ˜ RandomMachine 클래슀λ₯Ό μƒμ†λ°›λŠ” CraneMachine 을 μƒμ„±ν•œλ‹€. μž…λ ₯ν•œ μ•„μ΄ν…œ 리슀트 μ€‘μ—μ„œ 랜덀 뽑기λ₯Ό ν•˜λŠ” ν΄λž˜μŠ€μ΄λ‹€. RandomMachineμ—μ„œ κ΅¬ν˜„ν•΄λ†“μ•˜λ˜ 좔상 λ©”μ†Œλ“œ load, pick ν•¨μˆ˜λŠ” ν•„μˆ˜λ‘œ κ΅¬ν˜„ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€. 

 

 

* μ„œλΈŒ 클래슀 확인 

print('EX5-1 - ', issubclass(RandomMachine, CraneMachine))
print('EX5-2 - ', issubclass(CraneMachine, RandomMachine))

 EX5-1 -  False 
 EX5-2 -  True 

issubclassλ₯Ό μ‚¬μš©ν•˜μ—¬ μ„œλΈŒν΄λž˜μŠ€μΈμ§€ 확인 ν•΄λ³Έλ‹€. issubclass(RandomMachine, CraneMachine)은 RandomMachine이 CraneMachine의 μ„œλΈŒν΄λž˜μŠ€λƒ? λΌλŠ” λœ»μ΄λ‹€. 

 

 

* 상속 ꡬ쑰 확인 

print('EX5-3 - ', CraneMachine.__mro__)  # 가계도λ₯Ό 보여쀀닀. 상속을 받은 μˆœμ„œλ₯Ό λ³΄μ—¬μ€Œ

 EX5-3 -  (<class '__main__.CraneMachine'>, <class '__main__.RandomMachine'>, <class 'abc.ABC'>, <class 'object'>) 

 

 

* 객체 생성

cm = CraneMachine(range(1, 100)) # 좔상 λ©”μ†Œλ“œ κ΅¬ν˜„ μ•ˆν•˜λ©΄ μ—λŸ¬

Sequenceλ₯Ό μƒμ†ν–ˆμ„ λ•Œ __getitem__, __len__ λ©”μ†Œλ“œκ°€ ν•„μˆ˜μ˜€λ‹€λ©΄, abcλ₯Ό 상속할 λ•ŒλŠ” 좔상 λ©”μ†Œλ“œλ₯Ό ν•„μˆ˜λ‘œ κ΅¬ν˜„ν•΄ μ£Όμ–΄μ•Ό ν•œλ‹€λŠ” κ°•μ œμ„±μ„ λˆλ‹€. 

 

print('EX5-4 - ', cm._items)
print('EX5-5 - ', cm.pick())
print('EX5-6 - ', cm())
print('EX5-7 - ', cm.inspect()) # --> λΆ€λͺ¨μ˜ λ©”μ†Œλ“œκ°€ μ‹€ν–‰λœλ‹€.

 EX5-4 -  [53, 83, 95, 24, 97, 2, 43, 89, 85, 3, 59, 15, 78, 12, 46, 11, 29, 72, 6, 60, 41, 51, 1, 67, 10, 88, 5, 62, 33, 18, 55, 61, 13, 63, 90, 81, 32, 65, 86, 75, 94, 71, 93, 70, 26, 54, 31, 20, 91, 35, 34, 68, 57, 42, 23, 8, 77, 69, 36, 28, 99, 17, 98, 56, 44, 22, 14, 27, 30, 48, 37, 80, 87, 52, 49, 50, 40, 74, 25, 47, 96, 9, 45, 73, 4, 16, 21, 7, 82, 39, 58, 66, 84, 19, 79, 76, 38, 64, 92] 
 EX5-5 -  92 
 EX5-6 -  64 
 EX5-7 -  (38,) 

inspectλ©”μ†Œλ“œλŠ” μžμ‹ν΄λž˜μŠ€μ—μ„œ κ΅¬ν˜„ν•΄μ£Όμ§€ μ•Šμ•„λ„ λΆ€λͺ¨μ˜ 클래슀의 λ©”μ†Œλ“œκ°€ μ‹€ν–‰λœλ‹€. 

 

 

 

 

+ Recent posts