Python_2 - jjin-choi/study_note GitHub Wiki

Β§ ν΄λž˜μŠ€μ™€ 객체

1. μΈμŠ€ν„΄μŠ€μ˜ λ¬Έμžμ—΄ ν‘œν˜„μ‹

  • μΈμŠ€ν„΄μŠ€μ˜ λ¬Έμžμ—΄ ν‘œν˜„μ‹μ„ λ°”κΎΈλ €λ©΄ str() 와 repr() λ©”μ†Œλ“œλ₯Ό μ •μ˜ν•œλ‹€.
    • 객체λ₯Ό 좜λ ₯ν•  경우 κΈ°λ³Έμ μœΌλ‘œλŠ” str() ν•¨μˆ˜κ°€ ν˜ΈμΆœλœλ‹€.
    • !r 은 κΈ°λ³Έκ°’μœΌλ‘œ repr() ν•¨μˆ˜κ°€ ν˜ΈμΆœλœλ‹€.
    • { } κΈ°λ³Έκ°’μœΌλ‘œ str() ν•¨μˆ˜κ°€ ν˜ΈμΆœλœλ‹€.
    • repr() ν•¨μˆ˜λŠ” 객체λ₯Ό μ„ μ–Έν–ˆμ„ λ•Œ ν˜•νƒœ κ·ΈλŒ€λ‘œλ₯Ό λ§Œλ“€μ–΄μ•Ό 함.
    • ν˜•νƒœ κ·ΈλŒ€λ‘œ λΌλŠ”κ±΄, 예λ₯Ό λ“€μ–΄ μ•„λž˜μ—μ„œ Pair(A, B) 라고 ν•˜λ©΄ repr 도 κ·ΈλŒ€λ‘œ 좜λ ₯λ˜λ„λ‘ ν•΄μ•Όν•œλ‹€.
    • λ‚˜μ€‘μ— eval(repr(x)) == x 와 같은 textλ₯Ό λ§Œλ“œλŠ” 것이 ν‘œμ€€μ΄λ‹€.
    • repr(x) λ₯Ό eval 에 λ„£μœΌλ©΄ μ‹€μ œ 객체가 μƒμ„±λœλ‹€.
  1 class Pair:
  2     def __init__(self, x, y):
  3         self.x = x
  4         self.y = y
  5  
  6     def __repr__(self):
  7         return f'Pair ({self.x!r}, {self.y!r})'
  8  
  9     def __str__(self):
 10         return f'({self.x}, {self.y})'
 11  
 12 p = Pair(3, 4)
 13 print (p)  

2. 객체의 μ½˜ν…μŠ€νŠΈ 관리 ν”„λ‘œν† μ½œ (with) 지원

  • 객체가 context management protocol (with) 을 μ§€μ›ν•˜κ²Œ κ΅¬ν˜„
    • 쌍으둜 λ§Œλ“œλŠ” 과정을 μžλ™ν™” ν•  λ•Œ νŽΈλ¦¬ν•˜λ‹€.
    • with λ¬Έ λ§Œλ‚˜λ©΄ enter() λ©”μ†Œλ“œκ°€ 호좜
    • with λ¬Έ λΉ μ Έ λ‚˜κ°ˆλ•ŒλŠ” exit() λ©”μ†Œλ“œκ°€ 호좜
    • 객체에 λ‚΄λΆ€ ν•¨μˆ˜λ‘œ κ΅¬ν˜„ν•΄λ‘μž !
c = LazeConnection(('www.python.org', 80))
with c as s:   # ← c 의 __enter__() 호좜
   ...
               # ← c 의 __exit__() 호좜
print ("End")
  • user κ°€ ν•„μš”ν•  λ•Œλ§Œ socket을 λ§Œλ“€κΈ° μœ„ν•΄ LazyConnection classλ₯Ό λ§Œλ“€μ–΄λ³΄μž.
    • with c as s : λ₯Ό ν•˜λ©΄ enter() 의 return 값이 as s 둜 return λœλ‹€.
    • with λ‚΄λΆ€μ˜ μ½”λ“œ (context) κ°€ 정상 μ’…λ£Œ λ˜μ—ˆκ±°λ‚˜ 비정상 μ’…λ£Œ λ˜μ—ˆλ”λΌλ„ exit() 이 λ°˜λ“œμ‹œ μ‹€ν–‰λ˜μ–΄μ•Ό ν•˜λŠ” κ²½μš°μ—λŠ” with 둜 ν•˜λ©΄ λœλ‹€.

3. μΈμŠ€ν„΄μŠ€λ₯Ό 많이 생성할 λ•Œ λ©”λͺ¨λ¦¬ μ ˆμ•½

  • 객체 μΈμŠ€ν„΄μŠ€λ§ˆλ‹€ 내뢀에 멀버λ₯Ό μ €μž₯ν•  λͺ©μ μœΌλ‘œ λ”•μ…”λ„ˆλ¦¬ (μ•ŒνŒŒλ²³ 순으둜 ꡬ성) λ₯Ό κ΅¬μ„±ν•œλ‹€.

    • μ΄λŠ” λ©”λͺ¨λ¦¬ λ‚­λΉ„μ˜ 원인이 λœλ‹€.
    • λ‚΄λΆ€ κ΅¬μ‘°λŠ” dict 이 root 만 가리킀고 있음
    • λ‚˜λ¨Έμ§€λŠ” μ‹€μ‹œκ°„ μ •λ ¬ 및 λΉ λ₯Έ 검색을 μœ„ν•œ RB tree둜 λ˜μ–΄μžˆλ‹€. λ©”λͺ¨λ¦¬ λ‚­λΉ„κ°€ μ‹¬ν•˜λ‹€.
    • RB tree 이기 λ•Œλ¬Έμ— 객체에 memberκ°€ 없더라도 λ™μ μœΌλ‘œ 생성 / μ œκ±°κ°€ κ°€λŠ₯ν•˜λ‹€.
      . 즉, d1.name = "kim" 이런 μ‹μœΌλ‘œ d1 μ΄λΌλŠ” 객체의 member에 name 이 없어도 쀑간에 μΆ”κ°€ κ°€λŠ₯ν•˜λ‹€.
      . λ˜ν•œ del d1.name 을 μ‚¬μš©ν•˜μ—¬ member λ₯Ό μ‚­μ œν•  μˆ˜λ„ μžˆλ‹€.
    • ν•˜μ§€λ§Œ λͺ¨λ“  κ°μ²΄μ—μ„œ 이런 κΈ°λŠ₯을 κΌ­ ν•„μš”λ‘œ ν•˜μ§€ μ•ŠλŠ”λ‹€..
    • 이런 κ²½μš°μ—λŠ” RB tree κΈ°λŠ₯을 μ—†μ• κ³  compact ν•œ λ°°μ—΄λ‘œ κ΄€λ¦¬ν•˜λŠ” 방법이 μžˆλŠ”λ°, λ°”λ‘œ slots 을 μ“°λ©΄ λœλ‹€.
  • __slots__을 μ •μ˜ν•˜λ©΄ νŒŒμ΄μ¬μ€ μΈμŠ€ν„΄μŠ€μ— 훨씬 더 μ••μΆ•λœ λ‚΄λΆ€ ν‘œν˜„μ‹μ„ μ‚¬μš©ν•œλ‹€.

    • μΈμŠ€ν„΄μŠ€ λ§ˆλ‹€ λ”•μ…”λ„ˆλ¦¬λ₯Ό κ΅¬μ„±ν•˜μ§€ μ•Šκ³  νŠœν”Œμ΄λ‚˜ 리슀트 값은 λΆ€ν”Όκ°€ μž‘μ€ κ³ μ • λ°°μ—΄λ‘œ μΈμŠ€ν„΄μŠ€κ°€ λ§Œλ“€μ–΄μ§„λ‹€.
    • μ΄λ ‡κ²Œ ν•˜λ©΄ dict 이 μ‚¬λΌμ§€κ²Œ λœλ‹€.
    • λ˜ν•œ, 멀버 생성 / μ œκ±°κ°€ λΆˆκ°€λŠ₯ν•˜λ‹€.
  1 class Date:
  2     __slots__ = ['year', 'month', 'day']
  3
 10 print (dir(d1)) 
  • special member : dict
    • d1.dir (ν˜Ήμ€ dir(d1)) 이라고 μ‹€ν–‰ν•˜λ©΄ λ‚΄λΆ€ member 에도 dict κ°€ μ‘΄μž¬ν•œλ‹€.

4. 관리 속성 λ§Œλ“€κΈ° #except #exception #setter #TypeError

  • μΈμŠ€ν„΄μŠ€ 속성을 μ–»κ±°λ‚˜ μ„€μ •ν•  λ•Œ 좔가적인 처리 (type check, 검증 λ“±)을 ν•˜κ³  μ‹Άμ„λ•Œ @property μ΄μš©ν•œλ‹€.
    • ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ μ‚¬μš©λ˜λŠ” λ³€μˆ˜μ—λŠ” _λ₯Ό λΆ™μ—¬μ„œ μ‚¬μš©ν•œλ‹€.
    • python μ—μ„œλŠ” μ ‘κ·Ό μ§€μ •μž (private, public) 이 μ—†κΈ° λ•Œλ¬Έμ— getter setter 을 μ‚¬μš©ν•  ν•„μš”κ°€ μ—†μŒ.
    • 사싀은 객체 member 의 값을 λ³€κ²½ν•˜λŠ”κ²Œ λ¬Έμ œκ°€ μ—†μ§€λ§Œ, μ˜ˆμ™Έ 처리λ₯Ό λ„£κΈ° μœ„ν•΄ getter, setter λ₯Ό λ„£μ–΄μ€€ μ•„λž˜ μ½”λ“œλ‘œλ„ μΆ©λΆ„νžˆ κ°€λŠ₯.
    • 그런데 get_X, set_X ν•¨μˆ˜λ₯Ό λ§Œλ“€κ³  set_X 에 μ˜ˆμ™Έ 처리λ₯Ό λ„£μ–΄μ£ΌλŠ” 것도 λ˜λŠ”λ° μ™œ decorator 을 μ“ΈκΉŒ?
class Person:
   def __init__(self, first_name):
      self.first_name = first_name
   
   def get_first_name(self):
      return self.first_name

   def set_first_name(self, value):
      if not isinstance(value, str):
         raise TypeError('Expected a string')
      self.first_name = value

if __name__ == '__main__':
   a = Person('Guido')
   print (a.get_first_name())
   a.set_first_name('Dave')
   print (a.get_first_name())

   try:
      a.set_first_name(42)
   except TypeError as e:
      print (e)

(20.08.04 06:20 λΆ€ν„° λ‹€μ‹œ 보기)

  • @λŠ” decorator 이고 property ν•¨μˆ˜μ— getter, setterλ₯Ό λ„˜κ²¨μ£Όλ©΄ λœλ‹€.
  • property λΌλŠ” 객체가 μ‘΄μž¬ν•˜κ³ , 여기에 first_name 을 λ„£μ–΄μ„œ λ‹€μ‹œ first_name 으둜 λ°›μ•„μ˜¨ 것을 first_name.setter에 집어넣은 κ±Έ λ‹€μ‹œ first_name 으둜 λ„£μ–΄μ€Œ
  • property 객체 이름에닀가 setterλ₯Ό 집어 λ„£μ–΄μ£Όλ©΄ λœλ‹€.
    • @first_name.setter 둜 λ°μ½”λ ˆμ΄ν„°λ₯Ό μ§€μ •ν•˜λ©΄ ν•΄λ‹Ή 속성을 λ³€κ²½ν•˜λ € ν•  λ•Œ μžλ™μœΌλ‘œ ν˜ΈμΆœλœλ‹€.
    • 이 λ•Œ νƒ€μž…μ„ 검사할 수 있고 λ¬Έμžμ—΄μ΄ μ•„λ‹Œ 경우 μ˜ˆμ™Έλ₯Ό λ˜μ§„λ‹€.
  1 class Person:
  2     def __init__(self, first_name):
  3         self.first_name = first_name
  4      
  5     @property
  6     def first_name(self):
  7         return self._first_name
  8      
  9     '''
 10     def first_name(self):
 11         return self._first_name
 12      
 13     first_name = property(get_first_name)
 14     '''
 15      
 16     @first_name.setter
 17     def first_name(self, value):
 18         if not isinstance(value, str):
 19             raise TypeError('Expected a string')
 20         self._first_name = value
 21      
 22     '''
 23     first_name = first_name.setter(set_first_name)
 24     '''  
 25      
 27 if __name__ == '__main__':
 28     a = Person('Guido')
 29     print(a.first_name)
 30      
 31     a.first_name = 'Dave'
 32     print(a.first_name)
 33      
 34     try:
 35         a.first_name = 42
 36     except TypeError as e:
 37         print (e)                                             

5. λΆ€λͺ¨ 클래슀의 λ©”μ†Œλ“œ 호좜

  • λΆ€λͺ¨μ˜ λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λ €λ©΄ super() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•œλ‹€.
  1 class A:
  2     def spam(self):
  3         print ('A.spam')
  4         
  5 class B(A):
  6     def spam(self):
  7         print ('B.spam')
  8         super().spam()    
  9         
 10         
 11 if __name__ == '__main__':
 12     b = B()
 13     b.spam()
  • super()λŠ” 일반적으둜 init() λ©”μ†Œλ“œμ—μ„œ λΆ€λͺ¨λ₯Ό μ œλŒ€λ‘œ μ΄ˆκΈ°ν™” ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λœλ‹€.
 16 class A: 
 17     def __init__(self):
 18         print ('\nA.__init__() : ', end='')
 19         self.x = 0
 20          
 21 class B(A):
 22     def __init__(self):
 23         super().__init__()
 24         print ('\nB.__init__() : ', end='')
 25         self.y = 1     
 26          
 27 if __name__ == '__main__':
 28     b = B()
 29     print (b.x, b.y)
  • proxy λŒ€λ¦¬μž λ””μžμΈ pattern ...
    • python 의 νŠΉλ³„ λ©”μ†Œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ“œν•œ μ½”λ“œμ—μ„œ super()λ₯Ό μ‚¬μš©ν•˜κΈ°λ„ ν•œλ‹€.

    • getattr(self, name): μžμ‹ μ—κ²Œ μ—†λŠ” 속성을 μ ‘κ·Ό ν–ˆμ„ λ•Œ 호좜됨. κ·Έ λ•Œ κ·Έ 속성 (λ³€μˆ˜) 이름이 name 으둜 μ „λ‹¬λœλ‹€.

    • μžμ‹ μ—κ²Œ μžˆλŠ” 속성에 μ ‘κ·Όν–ˆμ„ λ•Œμ—λŠ” __getattr__μ—λŠ” μ ‘κ·Όν•˜μ§€ μ•ŠμŒ. μžκΈ°κ°€ ν¬ν•¨ν•˜κ³  μžˆλŠ” 멀버인 _obj 에 μ ‘κ·Όν• λ•Œμ—λŠ” ν˜ΈμΆœλ˜μ§€ μ•ŠμŒ.

    • μ•„λž˜ μ½”λ“œμ—μ„œ pλŠ” a와 λ˜‘κ°™μ€ 역할을 ν•˜κ³  있게 λœλ‹€.

    • get 으둜 κΊΌλ‚΄μ˜€λŠ” 건 Proxy κ°€ ν•  수 μžˆλŠ”λ° κ³Όμ—° set 도 κ°€λŠ₯ν• κΉŒ ?

    • setattr(self, name, value): μžμ‹ μ—κ²Œ μžˆκ±°λ‚˜ μ—†λŠ” 경우 호좜됨. 즉 무쑰건 호좜됨 !

    • setattr() κ΅¬ν˜„μ— 이름 확인이 λ“€μ–΄ μžˆλ‹€. λ§Œμ•½ 이름이 λ°‘μ€„λ‘œ μ‹œμž‘ν•˜λ©΄ super()λ₯Ό μ‚¬μš©ν•΄μ„œ setattr() 의 μ›λž˜ κ΅¬ν˜„μ„ ν˜ΈμΆœν•œλ‹€.

  1 class Proxy:
  2     def __init__(self, obj):
  3         self._obj = obj
  4      
  5     def __getattr__(self, name):
  6         print (f"Proxy.__getattr__(name = {name})")
  7         return getattr(self._obj, name)
  8      
  9     def __setattr__(self, name, value):
 10         print (f"Proxy.__setattr__(name = {name}, value = {value})")
 11         if name.startswith('_'):
 12             # λ‚΄ ν•¨μˆ˜λŠ” 이미 μ˜€λ²„λΌμ΄λ”© λ˜μ—ˆκΈ° λ•Œλ¬Έμ— λΆ€λͺ¨μͺ½μ— μžˆλŠ” __setattr__ 을 μ‚¬μš©ν•΄μ£Όλ©΄ λœλ‹€. 
 13             super().__setattr__(name, value)
 14         else:
 15             setattr(self._obj, name, value)
 16      
 17 if __name__ == '__main__':
 18     class A:
 19         def __init__(self, x):
 20             self.x = x
 21         def spam(self):
 22             print ("A.spam")
 25     a = A(42)
 26     p = Proxy(a)
 27      
 28     print (p.x)
 29     print (p._obj)
 30     print (p.spam())
 31      
 32     p.x = 37
 33     print ('should be 37 : ', p.x)
 34     print ('should be 37 : ', a.x)          
# output
''' 맨 μ²˜μŒμ— __init__ ν•¨μˆ˜μ—μ„œ _obj λ₯Ό set ν•  λ•Œμ—λ„ __setattr__ 이 ν˜ΈμΆœλœλ‹€. 
Proxy.__setattr__(name = _obj, value = <__main__.A object at 0x7f863c9e4668>)
Proxy.__getattr__(name = x)
42
<__main__.A object at 0x7f863c9e4668>
Proxy.__getattr__(name = spam)
A.spam
None
Proxy.__setattr__(name = x, value = 37)
Proxy.__getattr__(name = x)
should be 37 :  37
should be 37 :  37
  • 닀이아λͺ¬λ“œ 상속
    • μ•„λž˜ μ½”λ“œμ²˜λŸΌ C μ—μ„œ λΆ€λͺ¨λ₯Ό 각각 ν˜ΈμΆœν•˜λ©΄ base 의 μ΄ˆκΈ°ν™”κ°€ 2번 μ΄ˆκΈ°ν™” λ˜μ–΄λ²„λ¦°λ‹€.
  1 class Base:
  2     def __init__(self):
  3         print ('Base.__init__')
  4      
  5 class A(Base):
  6     def __init__(self):
  7         Base.__init__(self)
  8         print ('A.__init__')
 10 class B(Base):
 11     def __init__(self):
 12         Base.__init__(self)
 13         print ('B.__init__')
 14      
 15 class C(A,B):
 16     def __init__(self):
 17         A.__init__(self)
 18         B.__init__(self)
 19         print ('C.__init__')
 20      
 21 if __name__ == '__main__':
 22     c = C() 
  • C.mro λΌλŠ” 멀버가 μžˆλ‹€. (method resolution order)
    • superκ°€ λΆ€λͺ¨μͺ½μ„ ν˜ΈμΆœμ„ ν•  λ•Œ μ–΄λ–€ 경둜둜 ν˜ΈμΆœν• μ§€μ— λŒ€ν•œ order
    • python μ—μ„œλŠ” baseλ₯Ό ν•œλ²ˆλ§Œ ν˜ΈμΆœν•΄μ£ΌκΈ° μœ„ν•œ 방법이 ν•„μš”ν•œλ°, λ°”λ‘œ super()λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.
  1 class Base:
  2     def __init__(self):
  3         print ('Base.__init__')
  4          
  5 class A(Base):
  6     def __init__(self):
  7         #Base.__init__(self)
  8         super().__init__()
  9         print ('A.__init__')
 10          
 11 class B(Base):
 12     def __init__(self):
 13         #Base.__init__(self)
 14         super().__init__()
 15         print ('B.__init__')
 16          
 17 class C(A,B):
 18     def __init__(self):
 19         #A.__init__(self)
 20         #B.__init__(self)
 21         super().__init__()     
 22         print ('C.__init__')
 23    
 24          
 25 if __name__ == '__main__':
 26     c = C()
 27     print (C.__mro__)
  • C μœ„μ— λΆ€λͺ¨κ°€ A μœ„μ— λΆ€λͺ¨κ°€ B μœ„μ— λΆ€λͺ¨κ°€ Base 인 것.
  • μ™œ A μœ„μ— λΆ€λͺ¨κ°€ B 이지 ?
  • C κ°€ μƒμ†λœ μˆœμ„œλŒ€λ‘œ super λ₯Ό κ²°μ •ν•œλ‹€. (class C(A, B) : 라고 ν–ˆκΈ° λ•Œλ¬Έμ— C의 λΆ€λͺ¨λŠ” A, B)
  • ν•¨μˆ˜λ₯Ό μ°ΎλŠ” μˆœμ„œκ°€ C.mro
# output
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>)

6. μ„œλΈŒν΄λž˜μŠ€μ—μ„œ ν”„λ‘œνΌν‹° ν™•μž₯

  • deleter

    • property κ°€ del 둜 μ§€μ›Œμ§€λ €κ³  ν•  λ•Œ ν˜ΈμΆœλ˜λŠ” ν•¨μˆ˜
  • μ„œλΈŒ ν΄λž˜μŠ€μ—μ„œ, λΆ€λͺ¨ ν΄λž˜μŠ€μ— μ •μ˜ν•œ ν”„λ‘œνΌν‹°μ˜ κΈ°λŠ₯을 ν™•μž₯ ν•˜κ³  싢을 λ•Œ

    • super() κ΄„ν˜Έ μ•ˆμ—λŠ” 사싀 self 둜 ν˜ΈμΆœλœλ‹€.
    • getter μ—μ„œλŠ” μƒλž΅ν•΄λ„ λ˜λŠ”λ° setter 와 deleter μ—μ„œλŠ” μƒλž΅ν•˜λ©΄ μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.
    • super(SubPerson, XX) XX μžλ¦¬μ—λŠ” μžμ‹ 클래슀의 νƒ€μž…μ΄λ‚˜ μΈμŠ€ν„΄μŠ€ νƒ€μž…μ„ 넣을 수 μžˆλ‹€.
    • XX μžλ¦¬μ— λ„£λŠ” 값은, λΆ€λͺ¨μ— μžˆλŠ” class λ³€μˆ˜μΈμ§€, instance λ³€μˆ˜μΈμ§€μ— 따라 λ‹€λ₯΄λ‹€.
    • class λ³€μˆ˜μ— μ ‘κ·Όν•˜λ €κ³  ν•  λ•Œμ—λŠ” class type을 λ°˜λ“œμ‹œ 지정해야 ν•œλ‹€. (???)
    • λΆ€λͺ¨ λ©”μ†Œλ“œμ— λ„λ‹¬ν•˜κΈ° μœ„ν•œ μœ μΌν•œ 방법은, μΈμŠ€ν„΄μŠ€ λ³€μˆ˜κ°€ μ•„λ‹Œ 클래슀 λ³€μˆ˜λ‘œ μ ‘κ·Όν•΄μ•Ό ν•œλ‹€.
    • super(SubPerson, SubPerson) 이런 μ‹μœΌλ‘œ ...
  • property λ₯Ό 보면,

    • name = property(name) <- property 의 객체일 뿐, self.name 이 μ•„λ‹ˆλ‹€.
    • 즉 name 은 class λ³€μˆ˜μ΄λ‹€.
  1 class Person:                                         
  2     def __init__(self, name):                         
  3         self.name = name                              
  4                                                       
  5     # getter                                          
  6     @property                                         
  7     def name(self):                                   
  8         return self._name           
  9      
 10     # setter                                          
 11     @name.setter                                      
 12     def name(self, value):                            
 13         if not isinstance(value, str):                
 14             raise TypeError("Expected a string")      
 15         self._name = value                            
 16                                                       
 17     # deleter                                         
 18     @name.deleter                                     
 19     def name(self):                                   
 20         raise AttributeError("Can't delete attribute")            

7. μƒˆλ‘œμš΄ ν΄λž˜μŠ€λ‚˜ μΈμŠ€ν„΄μŠ€ 속성 λ§Œλ“€κΈ°

  • descriptor

    • get set delete λ₯Ό μž¬μ •μ˜ν•œ class λ₯Ό descriptor 라고 ν•œλ‹€.
    • μ™„μ „νžˆ μƒˆλ‘œμš΄ μ’…λ₯˜μ˜ μΈμŠ€ν„΄μŠ€ 속성을 λ§Œλ“€λ €λ©΄, κ·Έ κΈ°λŠ₯을 λ””μŠ€ν¬λ¦½ν„° 클래슀 ν˜•νƒœλ‘œ μ •μ˜ν•΄μ•Ό ν•œλ‹€.
    • property 도 dscriptor κ΅¬ν˜„μ²΄ 쀑 ν•˜λ‚˜μ΄λ‹€.
  • https://docs.python.org/ko/3/howto/descriptor.html

class Integer:
    def __init__(self, name):
        self.name = name

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

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

    def __delete__(self, instance):
        del instance.__dict__[self.name]

class Point:
    x = Integer('x')
    y = Integer('y')
    def __init__(self, x, y):
        self.x = x
        self.y = y

if __name__ == '__main__':
    p = Point(2, 3)
    print(p.x)
    p.y = 5
    try:
        p.x = 2.3
    except TypeError as e:
        print(e)

8. 자료 ꡬ쑰 μ΄ˆκΈ°ν™” λ‹¨μˆœν™”ν•˜κΈ°

  • 자료 ꡬ쑰둜 μ‚¬μš©ν•˜λŠ” 클래슀λ₯Ό μž‘μ„±ν•˜κ³  μžˆλŠ”λ°, 반볡적으둜 λΉ„μŠ·ν•œ init() ν•¨μˆ˜λ₯Ό 맀번 μž‘μ„±ν•΄μ•Ό ν•œλ‹€.
    • Struct λΌλŠ” λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ init 을 ν•œλ²ˆ ν•΄μ£Όλ©΄ μžμ‹ class μ—μ„œ μ˜€λ²„λΌμ΄λ”© ν•˜μ§€ μ•ŠλŠ” ν•œ, λΆ€λͺ¨μ˜ init 이 ν˜ΈμΆœλœλ‹€.
class Structure:
    _fields= []
    def __init__(self, *args):
        # argument μˆ˜κ°€ 각 class의 field μˆ˜μ™€ 같은지 check 
        if len(args) != len(self._fields):
            raise TypeError('Expected {} arguments'.format(len(self._fields)))

        for name, value in zip(self._fields, args):
            setattr(self, name, value)
        
# 각 class λ§ˆλ‹€ μžμ‹ μ˜ field λ₯Ό μ •μ˜ν•˜κ³  그에 맞게 init λ˜λ„λ‘ ν•œλ‹€. 
if __name__ == '__main__':
    class Stock(Structure):
        _fields = ['name', 'shares', 'price']

    class Point(Structure):
        _fields = ['x','y']

    class Circle(Structure):
        _fields = ['radius']
        def area(self):
            return math.pi * self.radius ** 2

if __name__ == '__main__':
    s = Stock('ACME', 50, 91.1)
    print(s.name, s.shares, s.price)

    p = Point(2,3)
    print(p.x, p.y)

    c = Circle(4.5)
    print(c.radius)

    try:
        s2 = Stock('ACME', 50)
    except TypeError as e:
        print(e)
  • κ°€λ³€μΈμž 뿐만 μ•„λ‹ˆλΌ ν‚€μ›Œλ“œ κ°€λ³€μΈμžλ„ λ°›κΈ° μœ„ν•΄μ„œλŠ” μ•„λž˜μ™€ 같이 κ΅¬ν˜„ν•œλ‹€.
    • args κ°€ field 보닀 μž‘κΈ°λ§Œ ν•˜λ©΄ 됨
class Structure:
    _fields= []
    def __init__(self, *args, **kwargs):
        if len(args) > len(self._fields):
            raise TypeError('Expected {} arguments'.format(len(self._fields)))

        for name, value in zip(self._fields, args):
            setattr(self, name, value)

        # args λ‹€μŒλΆ€ν„°λŠ” ν‚€μ›Œλ“œ 인자λ₯Ό λ°›μ•„μ£Όλ©΄ λœλ‹€. 
        for name in self._fields[len(args):]:
            setattr(self, name, kwargs.pop(name))

        if kwargs:
            raise TypeError('Invalid argument(s): {}'.format(','.join(kwargs)))
        
if __name__ == '__main__':
    class Stock(Structure):
        _fields = ['name', 'shares', 'price']

    s1 = Stock('ACME', 50, 91.1)
    s2 = Stock('ACME', 50, price=91.1)
    s3 = Stock('ACME', shares=50, price=91.1)
  • λ˜λŠ” extra_args μ΄μš©ν•΄μ„œ μ•„λž˜μ™€ 같이 κ΅¬ν˜„λ„ κ°€λŠ₯
    _fields= []
    def __init__(self, *args, **kwargs):
        if len(args) != len(self._fields):
            raise TypeError('Expected {} arguments'.format(len(self._fields)))
       
        for name, value in zip(self._fields, args):
            setattr(self, name, value)

        print (f"[TEST] kwargs.keys() - self._fields")
        extra_args = kwargs.keys() - self._fields
        for name in extra_args:
            setattr(self, name, kwargs.pop(name))
        if kwargs:
            raise TypeError('Duplicate values for {}'.format(','.join(kwargs)))
        
if __name__ == '__main__':
    class Stock(Structure):
        _fields = ['name', 'shares', 'price']

    s1 = Stock('ACME', 50, 91.1)
    s2 = Stock('ACME', 50, 91.1, date='6/1/2020')

10. μΈν„°νŽ˜μ΄μŠ€, 좔상 베이슀 클래슀 μ •μ˜

  • body κ°€ μ—†λŠ” 좔상 ν•¨μˆ˜λ₯Ό λ§Œλ“€μ–΄ 보자
  • module : ABCMeta, abstractmethod (좔상 클래슀, 좔상 λ©”μ†Œλ“œ) β€» ABC : ABstraCt
  • 기본적으둜 좔상 ν•¨μˆ˜κ°€ ν•˜λ‚˜λΌλ„ μžˆλŠ” ν΄λž˜μŠ€λŠ” 객체가 될 수 μ—†μŒ
  • abstractmethod λ₯Ό λ°μ½”λ ˆμ΄ν„°λŠ” ν•΄λ‹Ή ν•¨μˆ˜λ₯Ό 좔상 λ©”μ„œλ“œλ‘œ λ§Œλ“€μ–΄μ€€λ‹€.
  • a = IStream() 을 ν•˜λ©΄ μ—λŸ¬ λ°œμƒ
    • 좔상 λ©”μ„œλ“œ 이기 λ•Œλ¬Έμ— λ°˜λ“œμ‹œ read write λ₯Ό κ΅¬ν˜„ν•΄μ•Ό 함.
    • IStream ν΄λž˜μŠ€λŠ” μƒμ†ν•œ ν΄λž˜μŠ€μ—κ²Œ spec에 κ΅¬μ„±λ˜μ–΄μžˆλŠ” λͺ¨λ“  ν•¨μˆ˜ (μ—¬κΈ°μ„œλŠ”, readν•¨μˆ˜μ™€ writeν•¨μˆ˜)λ₯Ό κ΅¬ν˜„ν•˜λ„λ‘ κ°•μ œν•œλ‹€.
from abc import ABCMeta, abstractmethod

class IStream(metaclass=ABCMeta):
    @abstractmethod
    def read(self, maxbytes=-1):
        pass
    @abstractmethod
    def write(self, data):
        pass

class SocketStream(IStream):
    def read(self, maxbytes=-1):
        print('reading')
    def write(self, data):
        print('writing')

def serialize(obj, stream):
    if not isinstance(stream, IStream):
        raise TypeError('Expected an IStream')
    print('serializing')

if __name__ == '__main__':
    try:
        a = IStream()
    except TypeError as e:
        print(e)

    a = SocketStream()
    a.read()
    a.write('data')

    serialize(None, a)

    import sys

    try:
        serialize(None, sys.stdout)
    except TypeError as e:
        print(e)

    import io
    IStream.register(io.IOBase)

    serialize(None, sys.stdout)
from abc import ABCMeta, abstractmethod

class A(metaclass=ABCMeta):
    # 가상 ν•¨μˆ˜λ‘œ λ¨Όμ € λ§Œλ“€κ³  property λ“  λ‹€λ₯Έ decorator λ₯Ό 써쀀닀. 
    @property
    @abstractmethod
    def name(self):
        pass

    @name.setter
    @abstractmethod
    def name(self, value):
        pass

    @classmethod
    @abstractmethod
    def method1(cls):
        pass

    @staticmethod
    @abstractmethod
    def method2():
        pass

10 의 04:10 λΆ€ν„° λ‹€μ‹œ 보기

11 λΆ€ν„° λ‹€μ‹œ 보기

13. μˆœν™˜ 자료 κ΅¬μ‘°μ—μ„œ λ©”λͺ¨λ¦¬ 관리

  • μˆœν™˜μ΄ μžˆλŠ” 자료 ꡬ쑰λ₯Ό μƒμ„±ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ—μ„œ λ©”λͺ¨λ¦¬ κ΄€λ¦¬μ˜ λ¬Έμ œκ°€ 있음

  • μƒν˜Έ μ°Έμ΄ˆκ°€ μžˆλŠ” κ΅¬μ‘°μ—μ„œλŠ” weakref 라이브러리λ₯Ό μ‚¬μš©ν•˜λŠ” μ•½ν•œ 참쑰둜 λ§Œλ“œλŠ” 것을 κ³ λ €ν•œλ‹€.

  • ref count 은, root = Node ('parent') λ₯Ό ν•˜λŠ” μˆœκ°„, 자기 μžμ‹ μ΄ 가리킀기 λ•Œλ¬Έμ—, ref = 1 이 되고, μžμ‹κ³Ό μƒν˜Έ 참초 λ˜λŠ” μˆœκ°„, (root.add_child(c1)) ref = 2 κ°€ λœλ‹€.

  • λ”°λΌμ„œ del root 만 ν•˜κ²Œ 되면 root κ°€ 자기 μžμ‹ μ„ 가리킀지 μ•Šκ²Œ λ˜μ„œ ref = 1 이 될 뿐, Node μžμ²΄λŠ” λ‚¨μ•„μžˆμ–΄ memory leak 이 λ°œμƒν•œλ‹€.

class Data:
   def __del__(self):
      print('Data.__del__')

class Node: 
   def __init__(self):
      self.data = Data()
      self.parent = None
      self.children = []

   def add_child(self, child):
      self.children.append(child)
      child.parent = self

if __name__ = "__main__":
   a = Data()
   del a
   a = Node()
   a.add_child(Node())
  • 이λ₯Ό μœ„ν•΄μ„œ gc (garbage collector) λ₯Ό μ§€μšΈ 수 μžˆλ‹€.
import gc
gc.collect()
  • ν•˜μ§€λ§Œ 계속 이λ₯Ό μˆ˜ν–‰ν•΄ 쀄 수 μ—†κΈ° λ•Œλ¬Έμ—, weak pointer λ₯Ό μ‚¬μš©ν•˜μž !