Naver boostcamp -ai tech/week 01

부족한 python 채우기

끵뀐꿩긘 2022. 9. 20. 22:00
배우지 않으면 곧 늙고 쇠해진다  - 주자
목차
1. python의 특징
2. Conda / Jupyter notebook
3. parameter/ argument
4.  파이썬 출력(%-format, str.format(), f-string)
5. 문자열 메서드
6. type hints
7. Python docstring 예시
8. Python Coding Convention
9. 값이 하나인 튜플 생성
10. namedtuple
11. set / frozenset
12. counter
13. join, 일급함수
14. map, filter, reduce
15. comprehension
16. iterator, generator
17.가변인자(*args, **kwargs)
18. Class
19. 클로저
20. 데코레이터
21. 프로퍼티
22. __name__ & __main__
23. 객체의 비교와 복사
24.  pprint
25.  mypy
26.  모듈 & 패키지
27.  예외 처리(Exception Handling)
28.  File Handling
29.  pickle
30. logging  / configparser / argparser > 미완성
31. 파이썬 Max int value, Max float value
32. unpacking &zip
33. python scope & global/nonlocal
34. pgetattr, setattr, hasattr,delattr, dir
35. class의 magic method
36. NotImplementedError와 NotImplemented
37. functools.partial

 

1. python의 특징

플랫폼 독집적인 인터프리터 언어(소스 코드를 실행 시점에 해석), 객체지향, 동적 타이핑(프로그램이 실행하는 시점에 사용해야할 데이터에 대한 타입 결정) 언어

 

2. Conda / Jupyter notebook

conda: 파이썬 가상환경 설정( 패키지 충돌 방지)

jupyter notebook: python shell과 편집 도구를 합친 Ipython 대화형 파이썬 셸 -> colab, jupyter 단축키 알아두기

 

3. parameter/ argument

parameter: 함수의 입력 값 인터페이스

argument: 실제 Parameter에 대입된 값

def f(x): # parameter
 return 2 * x + 7
 
print(f(2)) # argument

 

4.  파이썬 출력(%-format, str.format(), f-string)

print("Product: %s, Price per unit: %f." % ("Apple", 5.243) # %format
print("Product: {0}, Price per unit: {1:.3f}.".format("Apple", 5.243)) # str.format
print(f"Hello, {name}. You are {age}.") # f-string

각각 소수점 자릿수, 글자 정렬 등 여러 옵션이 있음

 

5. 문자열 메서드

find(찾을문자, 찾기시작할위치) -> 문자의 위치 : 문자가 어디있는지

startswith(시작하는문자, 시작지점) -> boolean : 문자열로 시작하는지

endswith(끝나는문자, 문자열의시작, 문자열의끝) ->  boolean : 문자열로 끝나는지

strip() : 좌우공백 삭제

title() 과 capitalize() 차이: title()은 모든 단어의 첫 글자를 대문자로 바꾼다 capitalize()는 문장의 첫 단어의 첫 글자만 대문자로 바꾼다

split(): split()처럼 안이 비어있는 경우 공백을 무시하고 가져온다

ex.

 '  ab c '.split() # ['a','b','c]
 '  ab c '.split(" ") #['','','a','b','','c','']

 

6. type hints

def do_function(var_name: var_type) -> return_type: # 타입힌트 지정
	pass
   
a: int = 7 # 타입힌트 지정

강제성은 없음, 타입힌트와 다른 자료형을 넣어도 오류가 나지 않는다.

 

7. Python docstring 예시

 def print_test(self, param1, param2) :
        """함수 설명 제목

         함수에 대한 설명문

        Args:
            인수의 이름 (인수의 데이터형): 인수의 설명
            인수의 이름 (:obj:`인수의 데이터형`, optional): 인수의 설명

        Returns:
           리턴 값의 데이터형: 리턴 값의 설명(예 : True 라면 성공, False이라면 실패.)

        Raises:
            예외명: 예외의 설명 (예 : 인수가 지정되지 않은 경우에 발생 )

        Yields:
           리턴값의 데이터형: 리턴값에 대한 설명

        Examples:

            함수의 사용법 기재

            >>> print_test ("test", "message")
               test message

        Note:
            주의항목 등을 기재

        """
	pass

 

8. Python Coding Convention

다른 사람이 내 코드를 쉽게 이해하도록 코드를 정리되고 간결히 만드는 규칙

ex.

  • 들여쓰기는 공백 4칸을 권장합니다.
  • 한 줄은 최대 79자까지.
  • 소문자 L, 대문자 O, 대문자 I는 변수명으로 사용하지 마세요.
  • 클래스 명은 카멜케이스(CamelCase)로 작성합니다.
  • 함수명은 소문자로 구성하되 필요하면 밑줄로 나눕니다.

flake8 모듈로 체크하여 바꾸거나, black 모듈로 수정할 수 있다

* 줄이 너무 길면 \를 통해 내릴수 있다

month = 'a' + 'b' + \
    'c' + 'd'

 

9. 값이 하나인 튜플 생성

t = (1, ) # 값이 하나인 Tuple은 반드시 "," 를 붙여야 함

 

10. namedtuple

이름으로 접근이 가능한 튜플

from collections import namedtuple  # collections 모듈에서 namedtuple 불러옴

human = namedtuple('Human', ['height', 'weight'])  # 네임드 튜플 클래스 만듬

h = human(180, 75)  # 네임드튜플 객체 생성
print(h[0], h[1])  # 일반 튜플과 같은 접근법
print(h.height, h.weight)  # 이름으로 접근하는 방법

 

11. set / frozenset

set 연산자

s  = set() # 빈 set 생성
'''
| : 합집합, & : 교집합, - : 차집합, ^ : 대칭 차집합,
.add(): 원소추가, .discard(): 원소삭제,
|= : 다른 집합의 원소 전부 추가, &= : 다른 집합과 공통으로 있는 원소만 남기기
-= : 다른 집합이 갖는 원소 모두 삭제, ^= : 공통으로 갖지 않는 것들은 추가하고 나머지는 삭제
'''

frozenset 는 immutable set이다.

 

12. counter

from collections import Counter
# 산술 연산자 활용가능
counter1 = Counter(["A", "A", "B"])
counter2 = Counter(["A", "B", "B"])
counter1 + counter2
 
>>> Counter({'A': 3, 'B': 3})
#뺄셈의 결과로 0이나 음수가 나온 경우에는 최종 카운터 객체에서 제외

 

13. join

colors = ['red', 'blue', 'green', 'yellow']
result = ''.join(colors)

>>> result
'redbluegreenyellow'

result = '-'.join(colors) # 연결 시 "-"으로 연결
>>> result
'red-blue-green-yellow'

 

13. 일급객체 함수

* 일급 객체:

  • 변수나 데이터에 할당 할 수 있어야 한다.
  • 객체의 인자로 넘길 수 있어야 한다.
  • 객체의 리턴값으로 리턴 할 수 있어야 한다

 

파이썬에서는 특이하게도 함수도 일급객체(first-class citizen)이다.

  • 변수나 데이터에 할당 할 수 있어야 한다.
def square_numbers(x) :
  return x * x

f1 = square_numbers # f1이라는 '변수'에 함수를 할당
f1(5) # f1이라고 이름 붙여진 square_numbers가 실행
  • 객체의 인자로 넘길 수 있어야 한다.
a = [1.2, 2.5, 3.7, 4.6]
a = list(map(int, a)) # 맵 함수에 인자로 int 함수 전달
  • 객체의 리턴값으로 리턴 할 수 있어야 한다
def outer(m):
    def inner(n):
        return m*n
    return inner # 함수를 return 값으로 반환

f1 = outer(7)
f1(2)
>>> 14

 

14. map, filter, reduce

  • map(function, iterable):  두번째 인자로 들어온 iterable 자료형을 첫번째 인자로 들어온 함수에 하나씩 적용
# 리스트의 값을 정수 타입으로 변환
result1 = list(map(int, [1.1, 2.2, 3.3, 4.4, 5.5]))
  • filter(funtion, iterable): 두번째 인자로 들어온 iterable 자료형을 첫번째 인자로 들어온 boolean형 반환 함수에 하나씩 적용하여 True 값만 반환
# users에서 u["sex"] != "M"가 True 인 경우만 print
for woman in filter(lambda u: u["sex"] != "M", users):
	print(woman)
  • reduce(function, iterable [, 초기값]): 두번째 인자로 들어온 iterable 자료형을 첫번째 인자로 들어온 집계함수에 넣어서 데이터 누적
# 초기값 0에서부터 cur["age"] 누적합 구하기
from functools import reduce
reduce(lambda acc, cur: acc + cur["age"], users, 0)

 

15. comprehension

파이썬 공식문서에서는 map, filter 함수보다 comprehension 문법을 권장한다.

 

  • list comprehension
result = [i for i in range(10)] # 기본 list comprehension
result = [i+j for i in word_1 for j in word_2] #  i가 상위 for문 j가 하위 for 문 역할
result = [i+j for i in case_1 for j in case_2 if not(i==j)] # 조건문 추가
result = [[0 for col in range(4)] for row in range(3)] # 2차원 리스트 컴프리헨션 (shape = (3,4))

# i==0 이면 x.lower(), 0이 아니면 x.title() 적용
l = [x.lower() if i==0 else x.title()  for i, x in enumerate(tmp_list)]

#elif 처럼 사용 v == 1 : yes, v == 2 : no, else: idle
['yes' if v == 1 else 'no' if v == 2 else 'idle' for v in l]
  • dict comprehension
old={'A':10,'B':10,'C':20,'D':10}
new={k:v for k,v in old.items() if v!=20} # dict comprehension
  • set comprehension
s1 = {x for x in range(1,11)} # set comprehension
  • tuple comprehension
num = (x for x in range(10)) # tuple comprehension

 

16. iterator, generator

https://nvie.com/posts/iterators-vs-generators/

  • iterator
a_tuple = (1, 2, 3)
b_iterator = iter(a_tuple) #Tuple -> iterable -> iterator 반환
 
print(b_iterator.__next__())
print(b_iterator.__next__())
print(b_iterator.__next__())
#print(b_iterator.__next__()) # 다 돌았으면 예외발생: StopIteration
from itertools import count, cycle, repeat
count(10) # 10 11 12 13 ...
cycle('abc') # a b c a b c a ...
repeat(10, 3) # 10 10 10
repeat(10) # 10 10 10 ...

 

Class에 __iter__() 메소드가 있어야 iterable 객체이다.

 

  • genrator

iterator 객체의 한 종류로 next 함수를 호출하면 그 다음 yield문을 만날 때까지 실행을 이어간다.

>>> def test_generator():
...     yield 1
...     yield 2
...     yield 3
... 
>>> gen = test_generator()
>>> type(gen)
<class 'generator'>
>>> next(gen)
1
>>> next(gen)
2
>>> next(gen)
3
>>> next(gen)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
# yield from iterable, for문 대신에 iterable한 객체를 yield 할 수 있다

>>> def three_generator():
...     a = [1, 2, 3]
...     yield from a
... 
>>> gen = three_generator()
>>> list(gen)
[1, 2, 3]
  • genrator의 장점

- lazy evaluation하기 때문에 수행시간이 긴 연산을 필요한 순간까지 늦출 수 있다

- 반환할 값들을 미리 저장해 두지 않기 때문에 메모리 공간 차지가 적다.

 

# generator를 list()로 씌우면 망가진다

a = range(0,10) # genrator
print(list(a))
for i in a: # for문에 안들어가짐
	pass

 

 

 

17.가변인자(*args, **kwargs)

* 별표는 asterisk라고 한다.

# *args(위치 가변 인자)
def f(x, *args):
	pass
   
f(1,2,3,4,5)
	# x -> 1
    # args -> (2,3,4,5)
    
    
# **kwargs(키워드 가변 인자)
def f(x, y, **kwargs):
	pass
f(2, 3, flag=True, mode='fast', header='debug')
    # x -> 2
    # y -> 3
    # kwargs -> { 'flag': True, 'mode': 'fast', 'header': 'debug' }

 

18. Class

- 파이썬에서는 class도 객체이다.

- __init__(self): 클래스 변수의 초기화

- 상속

class Korea(Country): # Korea class의 Country 상속
	# self는 korea 클래스, super는 Country class
    def __init__(self, name, num):
        super().__init__(name)
        self.num - num

- 메소드 오버라이딩: 부모 클래스의 메소드를 자식 클래스에서 재정의

- isinstance (객체, 클래스): 객체가 클래스에 속하는지 알려주는 함수, 상속받은 객체도 상속한 객체에 속한다

- 파이썬의 모든 클래스는 object 클래스를 직접 또는 간접 상속한다

 

- 스페셜 메소드

  • __init__ : 객체 생성시 자동으로 호출되는 메소드
  • __len__: len 함수가 호출되었을 때 호출되는 메소드
  • __iter__: iter 함수가 호출되었을 때 호출되는 메소드, iterable 객체가 될 수 있다
  • __str__: str 함수가 호출되었을 때 호출되는 메소드, print에 쓰임
  • __next__: next 함수가 호출되었을 때 호출되는 메소드, iterator 객체가 될 수 있다

   * iterator 객체이자 iterable 객체

class Coll2:
    def __init__(self,d):
        self.ds = d
    def __next__(self):
        if len(self.ds) <= self.cc:
            raise StopIteration
        self.cc+=1
        return self.ds[self.cc - 1]
    def __iter__(self):
        self.cc = 0
        print('__iter__호출됨')
        return self # 자기 자신을 반환함으로서 iter이 호출될때마다 self.cc를 0으로 초기화한다
  • 연산자 오버로딩 : __add__, __sub__
  • __call__ : 인스턴스가 함수로 호출되었을때, 호출되는 메소드
  • __dict__ : 클래스 객체의 속성 정보를 담고 있는 딕셔너리, 인스턴스마다 하나씩 가지고있다
  • __slots__: __dict__과 달리 동적 사전을 사용하는 것이 아니라 정적 메모리를 사용하여 객체의 속성을 담아 액세스가 빠르고 메모리 효율적이다. 다만 새로운 속성을 추가할 수 없다.

-private method/ protected method

class Order:

# protected
# 암묵적 규칙에 의해 본 클래스와 하위클래스에서만 호출해야하는 변수
  def _add(x,y):
  	pass

# private
# 외부와 하위 클래스에서 호출불가능
  def __sub(x,y):
  	pass

 

- private variable/ protected variables

class Order:
  def __init__(self):
  
  	# protected
    self._coffee = 'Americano' # 암묵적 규칙에 의해 본 클래스와 하위클래스에서만 호출해야하는 함수
    
    # private
    self.__price = 3000 # private
	# 외부와 하위 클래스 Order.price로 변수 참조 불가능
    # 변수명이 _Order__price로 바뀐다

- class 변수: class의 인스턴스가 얼마나 많이 존재하는지에 상관없이, 하나의 사본이 존재하는 클래스에 정의된 변수

 class Account:
        num_accounts = 0 # 클래스 변수
        def __init__(self, name):
                self.name = name # 인스턴스 변수

- static 메소드: 객체가 없는 상태에서도 호출과 실행가능한 메소드

class Calc:
	# static 메소드
    @staticmethod
    def add(a, b):
        print(a + b)

- class 메소드:  인자로 class 객체를 받는다. 상속하는 과정에서 static 메소드보다 유용하다.

class Person:
    count = 0    # 클래스 속성
 
    def __init__(self):
        Person.count += 1    # 인스턴스가 만들어질 때
                             # 클래스 속성 count에 1을 더함
 
    @classmethod
    def print_count(cls):
        print('{0}명 생성되었습니다.'.format(cls.count))    # cls로 클래스 속성에 접근

19. 클로저

def outer_func(): 
    message = 'Hi' 

    def inner_func(): 
        print(message)  

    return inner_func # 함수를 return

my_func = outer_func() # my_func은 함수

my_func() 
#  my_func이 실행될때 message라는 변수는 inner_func안의 변수가 아니라 
# outer_func의 로컬변수이지만 잘 실행이 된다 -> 클로저 때문
>>> Hi

Hi라는 값은 my_func.__closure__[0].cell_contents 안에 저장되어있다

-> 클로저는 기존의 만들어진 함수나 모듈등을 수정하지 않고도 wrapper 함수를 이용하여 커스터마이징 할 수 있게 도와준다

 

def outer_func(tag):  
    tag = tag  

    def inner_func(txt):  
        text = txt  
        print('<{0}>{1}<{0}>'.format(tag, text)) 

    return inner_func  

# 'h1'과 'p'가 클로저로 저장된다
h1_func = outer_func('h1')  
p_func = outer_func('p')  

h1_func('h1 태그의 안입니다.')  
p_func('p 태그의 안입니다.')  

# wrapping이 잘 수행된다
>>> <h1>h1 태그의 안입니다.<h1>
>>> <p>p 태그의 안입니다.<p>

 

20. 데코레이터

데코레이터는 클로저를 사용하여 함수를 내부함수의 인자로 전달하여 수정하지 않고도 유연하게 함수에 특정 동작을 추가하거나 작동방식을 바꿀 수 있다.

- 함수형 데코레이터

def decorator_function(original_function): # original_function을 closure로 전달
    def wrapper_function():
    	# 함수 데코레이팅
        print('{} 함수가 호출되기전 입니다.'.format(original_function.__name__)) 
        return original_function()

    return wrapper_function

# 실제 함수
def display_1():
    print('display_1 함수가 실행됐습니다.')


display_1 = decorator_function(display_1)  # 1

display_1()

>>> display_1 함수가 호출되기전 입니다.
>>> display_1 함수가 실행됐습니다.


# 이렇게도 사용가능 # 1 생략
@decorator_function
def display_1():
    print('display_1 함수가 실행됐습니다.')

display_1()

 

21. 프로퍼티

객체가 갖는 값에 직접 접근하는 것은 위험하므로 내부 데이터를 보호하기 위해서 메소드를 통해 접근하는 것이 안전하다.

주로 getter와 setter 메소드를 작성하여 데이터를 받아오거나 수정한다.

 # getter와 setter을 사용하면 매번 메서드를 사용하여야 해 코드가 길어지고
 # 인터페이스가 변경됨에 다라 하위 호환성도 깨지게 된다.
person.set_age(person.get_age() + 1)

이때 프로퍼티를 사용하면 안정성을 유지하고 코드를 간결히 할 수 있다.

age = property(get_age, set_age) # 프로퍼티 설정
person.age = person.age +1

property 데코레이터를 사용하면 좀 더 간결하게 표현할 수 있다

class Person:
    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, age):
        if age < 0:
            raise ValueError("Invalid age")
        self._age = age
        
   # 따로 property에 입력해 줄 필요없이 데코레이션으로 getter와 setter 설정
   # 같은 이름을 사용할 것이기때문에 getter와 setter 함수의 이름 동일하게 지정

>>> person = Person("John", "Doe", 20)
>>> person.age
20
>>> person.age = -1
ValueError: Invalid age
>>> person.age = person.age + 1
>>> person.age
21

property 함수나 @property 데코레이터를 사용했을 때 가장 큰 이점은 외부에 티 내지 않고 내부적으로 클래스의 필드 접근 방법을 바꿀 수 있다는 것이다.

22. __name__ & __main__

def main():
    print ("Main Function")

if __name__ == "__main__":
	main()

코드가 시작한 파일이면  __name__ = __main__이고, 그렇지 않으면 __name__ = 파일명. py이다.

 

23. 객체의 비교와 복사

- is와 ==의 차이

  • is 는 변수의 객체가 같을 때 True를 리턴
  • ==은 변수의 값이 같을 때 True를 리턴

- 깊은 복사: mutable 객체를 얕은 복사한다는 것은 같은 객체를 참조한다는 뜻이므로 객체의 값이 바뀌면 복사한 것도 영향을 받을 수 있다

# 깊은 복사
import copy
B = copy.deepcopy(A)

 

24.  pprint

예쁘게 출력 가능

from pprint import pprint
pprint(users)
>>> {'body': 'quia et suscipit\n'
         'suscipit recusandae consequuntur expedita et cum\n'
         'reprehenderit molestiae ut ut quas totam\n'
         'nostrum rerum est autem sunt rem eveniet architecto',
 'id': 1,
 'title': 'sunt aut facere repellat provident occaecati excepturi optio '
          'reprehenderit',
 'userId': 1}

 

25.  mypy

정적 타입 검사 도구 -> type hints로 적은 타입과 다른 타입 오류를 찾아낼 수 있다 + 런타임 오류

  • 설치 : pip install mypy
  • 실행 : mypy 파일명.py

https://www.daleseo.com/python-mypy/

 

파이썬 타입 체크 - Mypy

Engineering Blog by Dale Seo

www.daleseo.com

 

26.  모듈 & 패키지

module은 py파일을 의미한다

- 모듈 호출하기

#1 
import fah_converter as fah # 모듈을 별칭으로 호출
print(fah.covert_c_to_f(41.6))

#2
from fah_converter import covert_c_to_f # 모듈에서 특정 함수/클래스만 호출
print(covert_c_to_f(41.6))

#3
from fah_converter import * # 모듈의 전체 함수/클래스 호출
print(covert_c_to_f(41.6))

package는 다양한 모듈들의 합을 의미하고 폴더로 연결되어있다

 - 폴더별로 있는  __init__.py라는 초기화 스크립트를 하위 폴더/모듈의 이름으로 구성해준다

 - 다른 폴더의 모듈을 부를때는 절대/상대 참조로 호출한다

 

27.  예외 처리(Exception Handling)

-예외 종류: https://kwongas.tistory.com/entry/Python-32-%ED%8C%8C%EC%9D%B4%EC%8D%AC-exception-%EC%A2%85%EB%A5%98

 

#Python - 32. 파이썬 exception 종류

이번 시간에는 프로그래밍의 꽃! exception(예외)에 대해 공부했습니다. 파이썬의 예외들을 알아볼까요? 파이썬 공식 문서를 참조했습니다. https://docs.python.org/ko/3/library/exceptions.html 내장 예외 —..

kwongas.tistory.com

# try ~ except
try:
	예외 발생 가능 코드
except <Exception Type>:
	예외 발생시 대응하는 코드
    
# try ~ except ~ else
try:
	예외 발생 가능 코드
except <Exception Type>:
	예외 발생시 동작하는 코드
else:
	예외가 발생하지 않을 때 동작하는 코드
    
# try ~ except ~ finally
try:
	예외 발생 가능 코드
except <Exception Type>:
	예외 발생시 동작하는 코드
finally:
	예외 발생 여부와 상관없이 실행됨
    
# raise
raise <Exception Type>(예외정보) # 강제로 예외 발생

# assert
assert 예외조건 '메세지'
# ex)
def get_binary_nmubmer(decimal_number):
	# decimal_number의 값이 정수형이 아니면 assert에 위배되므로 예외 발생
	assert isinstance(decimal_number, int)
	return bin(decimal_number)

 

28.  File Handling

- 파일 다루기

# open/close

f = open("<파일이름>","접근 모드")
# r: 읽기모드, w: 쓰기모드, a: 추가모드
f.close()

# with
with open("<파일이름>", "접근 모드") as my_file:
# 알아서 닫아준다

f.read(): 파일의 내용 전체를 문자열로 리턴

f.readlines(): 파일의 모든 줄을 읽어서 각각의 줄을 요소로 갖는 리스트 리턴

f.readline(): 파일의 첫번째 줄 읽어서 리턴

f.write(): 파일에 쓰기

 

-디렉토리 다루기

import os
os.mkdir("a") # 디렉토리 만들기

# log 디렉토리가 없으면 디렉토리 만들기
if not os.path.isdir("log"):
os.mkdir("log")

## import pathlib 모듈을 사용하여 path를 객체로 다룬다.

29.  pickle

객체 영속화 => 데이터, object 등 실행중 정보를 저장하여 불러와서 사용한다

import pickle
# 파일을 바이너리로 쓰고 읽어야한다
f = open("list.pickle", "wb")
test = [1, 2, 3, 4, 5]
pickle.dump(test, f) # pickle 저장
f.close()
f = open("list.pickle", "rb")
test_pickle = pickle.load(f) # pickle 로드
print(test_pickle)
f.close()

30. 파이썬 로깅 logging  / configparser / argparser -> ??

31. 파이썬 Max int value, Max float value

파이썬 정수형은 최대값을 가지지 않는다

python 정수값은 비트 수에 제한되지 않으며 사용 가능한 메모리의 한계까지 확장할 수 있다.

# 정수 최대값
import sys

sys.maxsize # 시스템에서 제공하는 정수의 최대값
# int64 = 9223372036854775808

float('inf') # 실수 최대값
10000000 < float('inf') # true, 어떤 수와 비교해도 크다
float('inf') < float('inf') # false
# OverflowError: Python int too large to convert to C ssize_t 오류
# sys.maxsize 이상의 숫자를 쓰면 발생할 수 있다
# 더 큰 정밀도로 숫자를 가져 오려면 장면 뒤에서 
#제한된 C 정수를 사용하는 int 유형을 전달하지 말아야 한다

32. unpacking & zip

파이썬에서 행렬 바꾸기

arr = [[1,2],[3,4],[5,6]]
print(list(zip(*arr)))
>>> [(1, 3, 5), (2, 4, 6)]

33. python scope & global/nonlocal

Python scope

1-1 Local scope

def local_scope():
  local_var = 1
  print(local_var)

print(local_var) # local_Var는 함수 내에서만 호출 가능하므로 호출이 불가하다

1-2 Enclosing scope

def enclosing_scope():
  enclosing_var = 2
  def inner_func():
    inner_var = 3
    # enclosing_var += 1 #error
    
    #nonlocal enclosing_var # 비전역 변수로 선언 == enclosing에 선언된 변수에요
    #enclosing_var += 1 # 가능
    
    print(enclosing_var * inner_var) # 6이 나온다
 	
enclosing_scope()

# closure 때문에 nonlocal 없이 enclosing_var가 참조될 수는 있지만 변경은 불가능하다

1-3 Global scope

global_Var = 10

def outer_func():
  outer_var = global_var + 3
  print(outer_var) # 13이 출력된다
  def inner_func():
    inner_var = global_var * 10
    print(inner_var) # 100이 출력된다

print(global_var) # 10이 출력된다

# 똑같이 하위 scope에서 참조는 가능하나 변경을 위해서는 global이 필요하다

1-4 Built-in scope

python 설치 파일 안에 바로 내장 되어 있는 어떤 python 파일을 작성하든지 간에 항상 포함되는 가장 광범위한 scope라고 보면 된다.

별다른 선언없이 실행되는 len(), input(), print() 와 같은 python 내장 함수등이 해당 범위에 해당된다.

 

1-5. Shadowing

Local scope -> Enclosing scope -> Global Scope -> Built-in Scope

python은 선언된 변수나 함수의 정의를 찾을 때 선언된 지점을 기준으로 가장 가까운 범위서 부터 찾게 되고 가장 가까운 범위에 있는 정의를 가장 우선시한다.

 

34. getattr, setattr, hasattr,delattr, dir

- getattr

getattr(object, attribute_name [, default])

object 안에 찾고자하는 attribute의 값을 출력한다.(만약 없을 경우 default가 출력된다)

class Employee:
  emp_comp = "Amazon"
  emp_age = 30
  default_age = 50

  def defaultMethod(self):
    print("This is a default method")

e = Employee()
print(getattr(e, 'emp_age'))            
# e 에 emp_age 라는 attribute가 있는지? 있다. 30 출력

print(getattr(e, 'emp_age', 45))          
# e 에 emp_age 라는 attribute가 있는지? 있다. 30 출력, 45 [default] 무시

print(getattr(e, 'emp_age_other', 45))       
# e 에 emp_age_other 라는 attribute가 있는지? 없다. 45 [default] 출력

print(getattr(e, 'emp_age_other', e.default_age))  
# e 에 emp_age_other 라는 attribute가 있는지? 없다. e.default_age [default] 출력 
# e.default_age의 값이 return

- setattr

setattr(object, attribute_name, value)

object에 새로운 attribute를 추가하고 값은 value를 준다

class Employee:
  emp_comp = "Amazon"
  emp_age = 30
  default_age = 50

  def defaultMethod(self):
    print("This is a default method")
    
e = Employee()

print(getattr(e, 'emp_age'))            
# e 에 emp_age 라는 attribute가 있는지? 있다. 30 출력

setattr(e, 'emp_age', 100)            
# setattr를 통해 emp_age를 100으로 변경 

print(getattr(e, 'emp_age', 45))          
# e 에 emp_age 라는 attribute가 있는지? 있다. 100 출력, 45 [default] 무시

setattr(e, 'emp_sex', "man")            
# setattr를 통해 emp_sex 생성 및 man 입력

print(getattr(e, 'emp_sex', 'woman'))      
# e 에 emp_sex 라는 attribute가 있는지? 있다. man 출력, woman 무시

- hasattr()

hasattr(object, attribute_name)

object에 attribute_name이 있는지 확인하고 boolean 값을 출력한다

class Employee:
  emp_comp = "Amazon"
  emp_age = 30
  default_age = 50

  def defaultMethod(self):
    print("This is a default method")
    
e = Employee()
e1 = Employee()

print(hasattr(e, 'emp_address'))      
# e 에 emp_address가 있는지? 없다. False

setattr(e, 'emp_address', 'Korea')    
# e 에 emp_address 생성 및 Korea 입력 
# setattr()는 class에 변수를 추가하는게 아니라 인스턴스에 추가

print(hasattr(e, 'emp_address'))      
# e 에 emp_address가 있는지? 있다. True

print(hasattr(e1, 'emp_address'))     
# e1 에 emp_address가 있는지? 없다. False

-delattr()

delattr(object, attribute_name)

object 내부의 attribute_name과 같은 attribute를 삭제한다

class Employee:
  emp_comp = "Amazon"
  emp_age = 30
  default_age = 50

  def defaultMethod(self):
    print("This is a default method")
    
e = Employee()
e1 = Employee()

print(hasattr(e, 'emp_comp'))      # e 에 emp_address가 있는지? 있다. True
print(hasattr(e1, 'emp_comp'))      # e 에 emp_address가 있는지? 있다. True
delattr(Employee, 'emp_comp')    # Employee에서 emp_comp 삭제
print(hasattr(e, 'emp_comp'))      # e 에 emp_address가 있는지? 없다. False
print(hasattr(e1, 'emp_comp'))      # e 에 emp_address가 있는지? 없다. False

print(hasattr(e, 'emp_age'))      # e 에 emp_age가 있는지? 있다. True
print(hasattr(e1, 'emp_age'))      # e 에 emp_age가 있는지? 있다. True
del Employee.emp_age          # Employee에서 emp_age 삭제/delattr(Employee, 'emp_age')와 동일
print(hasattr(e, 'emp_age'))      # e 에 emp_age가 있는지? 없다. False
print(hasattr(e1, 'emp_age'))      # e 에 emp_age가 있는지? 없다. False

- dir() 해당 object의 전체 attribute를 확인할 수 있다

class Employee:
  emp_comp = "Amazon"
  emp_age = 30
  default_age = 50

  def defaultMethod(self):
    print("This is a default method")

e = Employee()
dir(e)

>>>
['__class__',  # 매직 메서드들
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__le__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 'defaultMethod', # 메서드도 들어감
 'default_age', # 변수들 들어감
 'emp_age',
 'emp_comp']

35. class의 magic method

__으로 시작해서 __으로 끝나는 메소드로 특별하나 기능을 제공한다

 

* __new__

객체를 생성할 때 가장 먼저 실행되는 메소드

*__init__

생성자라고 부르며, __new__메소드로 객체가 생성되고 나면 호출된다

*__del__

객체가 소멸될 때 호출된다

*__str__, __repr__

객체의 문자열 표현을 위해 사용된다

https://recordnb.tistory.com/47

 

[Python] 내장 함수 __str__, __repr__

Python 3.9 파이썬에는 내장 함수가 구현되어 있습니다. 내장 함수란 자주 사용되는 기능들을 사전에 구현해 놓은 것입니다. 여러 내장 함수들이 있고 그중 __str__과 __repr__에 대해 알아보려 합니다.

recordnb.tistory.com

* __class__

객체의 데이터 타입을 가지고 있다

a = 1
print(a.__class__) # <class 'int'>

def do():
    pass
print(do.__class__) # <class 'function'>

class Thing():
    pass
print(Thing.__class__) # <class 'type'>

thing = Thing()
print(thing.__class__) # <class '__main__.Thing'>
print(thing.__class__.__name__) # Thing

 

* __dict__ : 클래스 객체의 속성 정보를 담고 있는 딕셔너리, 인스턴스마다 하나씩 가지고있다

class Test:
	def __init__(self, name):
		self.name = name
		self.test_dict = {'a':1, 'b':2}
		self.test_list = ['1','2','3']
	
# Test 객체 생성		
test_object = Test("minimi")

# __dict__ 메소드를 이용해보면 type이 dict인 것을 확인 할 수 있다.
print(type(test_object.__dict__)) # <class 'dict'>

# print 해보면, 객체에 선언한 변수들이 key,value로 들어간 것을 확인할 수 있다.
print(test_object.__dict__)  # {'name': 'minimi', 'test_dict': {'a': 1, 'b': 2}, 'test_list': ['1', '2', '3']}

# dict 형태이기 때문에 key 값으로 조회시 바로 value를얻을 수 있다.
print(test_object.__dict__['name']) # minimi

# 번외 : dictionary의 key, value를 얻을 수 있는 items() 로 dict로 재변경
print(test_object.__dict__.items()) # dict_items([('name', 'minimi'), ('test_dict', {'a': 1, 'b': 2}), ('test_list', ['1', '2', '3'])])
print(type(test_object.__dict__.items())) # <class 'dict_items'>
object_dict = dict(x for x in test_object.__dict__.items()) # {'name': 'minimi', 'test_dict': {'a': 1, 'b': 2}, 'test_list': ['1', '2', '3']}
print(type(object_dict)) # <class 'dict'>
출처: https://minimilab.tistory.com/58 [MINIMI LAB:티스토리]

* __slots__: __dict__과 달리 동적 사전을 사용하는 것이 아니라 정적 메모리를 사용하여 객체의 속성을 담아 액세스가 빠르고 메모리 효율적이다. 다만 새로운 속성을 추가할 수 없다.

class Bar :
​​​​
​​​​__slots__ = ['x', 'y'] # __slots__를 선언하면, __dict__가 사라진다
​​​​
​​​​def __init__(self, x, y) :
​​​​​​​​self.x = x
​​​​​​​​self.y = y

bar = Bar(1, 2) 
bar.z = 10 # AttributeError: 'Bar' object has no attribute 'z'
# __dict__가 없어서 새로운 객체 생성 x

*__dir__: dir()이 실행될때 호출된다

 

◆ dir() : 현재 프로그램 scope 내 사용하고 있는 변수(객체) 즉, namespace 명단을 제공

◆ dir(객체명) : 해당 "객체명"의 attribute(객체 내 포함된 변수 또는 메소드를 의미) 명단을 제공. 객체명으로는 변수, 함수, 모듈, 패키지, 데이터 타입 등이 가능

 

*__doc__:

document 출력

 

*__eq__,__ge__,__gt__,__le__,__lt__,__ne__

비교 연산 할때 사용된다

 

*super().__init__() == super(custom module 이름, self).__init__() 

custom model의 부모 클래스인 nn.module을 __init__함으로서 아래 코드를 실행시킬 수 있다

    def __init__(self) -> None:
        """
        Initializes internal Module state, shared by both nn.Module and ScriptModule.
        """
        
        torch._C._log_api_usage_once("python.nn_module")

        self.training = True
        self._parameters: Dict[str, Optional[Parameter]] = OrderedDict()
        self._buffers: Dict[str, Optional[Tensor]] = OrderedDict()
        self._non_persistent_buffers_set: Set[str] = set()
        self._backward_hooks: Dict[int, Callable] = OrderedDict()
        self._is_full_backward_hook = None
        self._forward_hooks: Dict[int, Callable] = OrderedDict()
        self._forward_pre_hooks: Dict[int, Callable] = OrderedDict()
        self._state_dict_hooks: Dict[int, Callable] = OrderedDict()
        self._load_state_dict_pre_hooks: Dict[int, Callable] = OrderedDict()
        self._load_state_dict_post_hooks: Dict[int, Callable] = OrderedDict()
        self._modules: Dict[str, Optional['Module']] = OrderedDict()

 

* __dict__

 클래스 객체의 속성 정보를 담고 있는 딕셔너리, 인스턴스마다 하나씩 가지고있다

class Test:
	def __init__(self, name):
		self.name = name
		self.test_dict = {'a':1, 'b':2}
		self.test_list = ['1','2','3']
	
# Test 객체 생성		
test_object = Test("minimi")

# __dict__ 메소드를 이용해보면 type이 dict인 것을 확인 할 수 있다.
print(type(test_object.__dict__)) # <class 'dict'>

# print 해보면, 객체에 선언한 변수들이 key,value로 들어간 것을 확인할 수 있다.
print(test_object.__dict__) 
# {'name': 'minimi', 'test_dict': {'a': 1, 'b': 2}, 'test_list': ['1', '2', '3']}

 

* __getattr__, __getattribute__, __setattr__

 

__getattr__:  인스턴스 속성에 접근 시 가장 마지막에 호출

어떤 속성 (attribute: 변수나 매소드 등)에 접근할 때, 그 속성을 코드에서 끝까지 찾아본 뒤, 없으면 맨 마지막에 호출된다

 

__getattribute__: 인스턴스 속성에 접근 시 가장 처음에 호출

어떤 속성(attribute: 변수나 매소드 등)에 접근할때 그 속성을 코드에서 찾기 전에 가장 처음 호출된다

 

class A:    
	def __getattr__(self, name):        
        a.ace = 'ace value'
    	return ('hahaha-'+name)
        
a = A()   

print(a.ace) # ace value
print(a.ace2) # hahaha-ace2 # ace2는 객체에 없는 속성이므로 __getattr__ 호출
print(a.__dict__) # {‘ace’: ‘ace value’}
class A:
    def __getattr__(self, name):
        return (‘hahaha-’+name)
    def __getattribute__(self,name):
        return (‘jajaja-’+name)

a = A()
a.ace = ‘ace value’

print(a.ace) # jajaja-ace
print(a.ace2) # jajaja-ace2
print(a.__dict__) # jajaja-__dict__

# 모든 속성에 대한 접근을 __getattribute__가 가로채갔다

__setattribute__: 인스턴스 속성에 할당할 때 호출된다

>>> # this example uses __setattr__ to dynamically change attribute value to uppercase
>>> class Frob:
...     def __setattr__(self, name, value):
...         self.__dict__[name] = value.upper()
...
>>> f = Frob()
>>> f.bamf = "bamf"
>>> f.bamf
'BAMF'

 

무한재귀발생: 

class MyTest(object):
    def __init__(self, x):
        self.x = x

    def __setattr__(self, name, value):
        if name=="device":
            print "device test"
        else:
            setattr(self, name, value)

test = MyTest(1)
# self.x에 1을 대입한다
# 속성에 대입이 일어났으므로 __setattr__가 실행된다
# setattr(self, name, value) name에 value를 대입한다
# 속성에 대입이 일어났으므로 __setattr__가 실행된다
# setattr(self, name, value) name에 value를 대입한다
# ... 무한반복

무한재귀 해결법 - 1:

class MyTest(object):

    def __init__(self, x):
        self.x = x

    def __setattr__(self, name, value):
        if name=="device":
            print "device test"
        else:
            super().__setattr__(name, value) #부모클래스에서 __setattr__호출하면 재귀가 안된다

무한재귀 해결법 - 2:

class SomeClass(object):

    def __setattr__(self, name, value):
        self.__dict__[name] = value # __dict__에서 바꾼다

    def __init__(self, attr1, attr2):
        self.attr1 = attr1
        self.attr2 = attr2


sc = SomeClass(attr1=1, attr2=2)

sc.attr1 = 3

36. NotImplementedError와 NotImplemented

- NotImplementedError

상위 클래스를 설계할 때, 하위 클래스에서 반드시 오버라이드하여 상세하게 구현해야하느 메소드를 명시하고자 한다면, 해당 메소드의 내용으로 raise NotImplementedError만 넣어놓는다.

class BaseWheel:
    def roll(self):
        raise NotImplementedError("roll 메소드를 구현하여야 합니다.")

class FastWheel(BaseWheel):
    def roll(self):
        print("빠르게 굴러간다~!")

someWheel = BaseWheel() 
someWheel.roll() # NotImplementedError: roll 메소드를 구현하여야 합니다.

someWheel = FastWheel()
someWheel.roll() # 빠르게 굴러간다~!

- NotImplemented

어떤 클래스의 연산자, 특히 중위 연산자에서 지원하지 않은 연산이라고 알리기 위해 NotImplemented를 return한다

NotImplented는 None이나 True/False 같이 키워드이자 값이다.

수치 연산에서 굳이 에러를 반환하지 않고 특정한 값을 반환하는 이유는 파이썬 인턴프리터가 다른 가능한 연산을 찾아볼 기회를 주어 설계를 유연히 하기 위해서이다

class Minute:
    def __init__(self, value):
        self.value = value

    def __radd__(self, other):
        return Time(other.hour, other.minute + self.value, other.second)


t = Time(12, 23, 00)
print("초기 상태", t)

t += 22 # + int는 TypeError가 나지않아서 잘 반환된다
print("22초 추가", t)

# + Minute객체는 TypeError가 나서 NotImplemented가 반환되었으므로
# 파이썬에서 다른 연산자 __radd__를 찾아 수행한다
m = Minute(15)
t += m
print("15분 추가", t)

 

37.functools.partial

기존의 함수와 구현은 동일하고 인자만 미리 정해준 또 다른 함수를 생성한다

from functools import partial

def power(base, exponent):
    return base ** exponent
    
square = partial(power, exponent=2) 

#square은 
#def square(arm):
#    return arm ** 2
# 과 같다