본문 바로가기

Phython

함수 / * ,** / 함수 설명 보기 / 예외처리 (else, as, from, with)

pythond의 function은 first class function

'first class function' ?

  : 객체 지향에서 object(값)를 의미함. 

q. 다음중 파이썬의 함수는?

  (1) x (2) x()  (3) x(t)  

a. 1번. 

x
<function __main__.x()>

x는 함수의 이름. 

def x(t):
    return t

괄호(call)는 선택사항 -> callable : 괄호를 붙일 수 있니?

callable(x)
True

괄호를 붙여서 argument로 쓴다는 것은 함수로서 사용하는 것이 아니라 return값을 활용한다는 의미. 

 

parameter : t 를 사용할 때 (2)가지 용법  

  - 함수를 사용할 땐, 파라미터의 개수와 argument의 개수를 맞춰야 한다. 

(1) positional 방식 (위치기반)

x(3)
3

  1. /  앞으로는 반드시 포지셔널 방식을 사용한다. 

def z(a, / , b):
    return a+b
z(a=3,b=4)
 
TypeError Traceback (most recent call last) Cell In[28], line 1
----> 1 z(a=3,b=4) TypeError: z() got some positional-only arguments passed as keyword arguments: 'a'
 

 

(2) keyword 방식  

x(t=3)
3

키워드 방식의 장점

  1. 순서와 상관없이 사용할 수 있다. 

def zz(a,b):
    return a+2*b
 
zz(b=3, a=5)
11

  2. * 다음은 무조건 키워드 방식으로 사용해야 한다. 

def z(a, * , b):
    return a+b
z(3)
 
-TypeError Traceback (most recent call last) Cell In[25], line 1
----> 1 z(3) TypeError: z() missing 1 required keyword-only argument: 'b'

 

 

 

python 에는 function overloading을 지원하지 않는다. 

 

만약, function overloading을 지원한다면

def x(a):
    print(a)
 
def x(a,b):
    print(a,b)

위 두 식을 다른 함수로 본다. 즉, signiture가 다르면 다른 함수라고 인식한다.

 

하지만, 차이썬에서는 이를 지원하지 않기 때문에 함수의 이름이 똑같으면 같은 함수로 인식하고, 다시 정의한다. 

대신 default technic을 지원한다. 

 

'default technic' 이란?

def x(a,b=3,c=4):
    print(a,b,c)
x(4)
4 3 4

: 함수 정의할 때 디폴트를 정의해놓으면, 파라미터와 argument 개수를 맞출  필요가 없다. 

 

만약 여기서 c의 값을 1로 바꾸고 싶다면?

x(4,3,1)   #포지셔널 방식 
4 3 1

포지셔널 방식은 모든 값을 다 적어주어야 하는 반면,

x(4, c=1)  #키워드 방식
4 3 1

keyword 방식으로 쉽게 바꿀 수 있다.

 

디폴트값을 한번이라도 사용하면 계속 사용해야 한다.

 

마찬가지로, 키워드 방식을 한 번이라도 사용하면 계속 사용해야 한다. 

 

 


함수에서 * 의 사용

(1) 가변 positional 

def k(*a):  # 가변 포지셔널
    return a
k()
()
k(1,2,3)
(1, 2, 3)

(2) 가변 kwyword 

def j(**a):
    return a
 j()
  
 {}
 j(a=1)
 {'a': 1}

matplotlib을 사용해서 함수 사용 연습하기 

pip install matplotlib
import matplotlib.pyplot as plt

수행 후, 

plt.hist([1,1,2,2,3,1,2,1,1,3,3],color='skyblue')

plt.bar([1,2,3],[1,2,3], color='pink')

 

색을 바꿀 수 있는 이유 ==> ** 때문!

 

def xx(a, **kw):
    return a
def xx(a, **kw):
    # if 'color' in kw:
    #     color = color
    # else:
    #     color = None
    print(kw)
    return a
xx(4, color='red')
 
{'color': 'red'}

또는 

def xx(a, **kw):
    # if 'color' in kw:
    #     color = color
    # else:
    #     color = None
    # print(kw)
    return a, kw['color']
xx(4, color='red')
 
(4, 'red')

=> * 이 **보다 항상 먼저 온다. 

 


 

unpacking  *

def x(*a):
    return a
 
b = [1,2,3,4]
 
x(b)
([1, 2, 3, 4],)    #b가 한 번에 들어감
 
x(*b)
(1, 2, 3, 4)        # b가 하나씩 unpacking되어 들어감. 

 

unpacking **

def x(*a):
    return a
def y(**a):
    return a
 
bb = {'a':1, 'b':2}
y(**bb)
{'a': 1, 'b': 2}
x(*bb)
('a', 'b')       # key만 뽑아낼 수 있다. 

unpacking  -->  병합 과정에서 키가 중복될 경우, 두 번째 딕셔너리(j)의 값으로 덮어씌워집니다.

k = {'a':1, 'b':2}
j = {'b':1, 'c':2}
{*k, *j}
{'a', 'b', 'c'}
{**k, **j}
{'a': 1, 'b': 1, 'c': 2}    

 


[ *의 사용법 정리]   Ascii 에서 *은 42 (은하수를 여행하는 히치하이커를 위한 안내서)

1. 숫자와 sequence 곱하기 연산

2 ** 연승

3. a, *b = 1,2,3

4. def  x(a, *, b)

5. def  x(*b)

6. def  x(*bb)

7. from import * 

8. x(*b)     #unpacking

9. x(**b)    #unpacking


설명란에서 대괄호 [ ] 는 옵션임을 의미한다. 고로, 옵션을 제외한 값이 우선된다. 


 TYPE HINT 를 줄 수 있지만, 강제성은 없다. 

# type hint를 줄 수 있다. a는 int를 주고 b는 float을 넣도록 가이드 해주세요.
# 하지만 강제성은 없다.
def x(a:int, b:float)  -> int:
    return a

강제성은 없지만, 값 입력시 힌트가 위에 뜸.

설명 보는 방법 1

x.__annotations__
 
{'a': int, 'b': float, 'return': int}

설명 보는 방법 2

def x(a:int, b:float)  -> int:
    '''설명 쓰는 란'''
    return a
x.__doc__
'설명 쓰는 란'

예외 처리

"허락보다 용서가 쉽다" EAFP

 

즉, 매번 오류가 날지 안 날지 체크하지 말고 오류가 나면 그때 처리해라. 

                                                 (import this 로 파이썬의 철학 확인 가능함)

[예외 처리 관련 keyword] -  keyword.kwlist 에서 학인

assert

else

exception

finally

from

lazy

try

 

[특징]

- 예외(에러)가 발생하면 중단된다. 

 

[예외처리 사용 상황]

- 중단을 시켜야 하는 경우 

- 중단 없이 실행될 필요가 있을 때


"중단을 시켜야 하는 경우"

1. assert

a = 1일때, 

assert a==2

을 실행하면 

AssertionError Traceback (most recent call last) Cell In[84], line 1

----> 1 assert a==2 AssertionError:

위와 같은 에러가 난다. 

 

assert a==2, '설명'

AssertionError Traceback (most recent call last) Cell In[85], line 1

----> 1 assert a==2, '설명' AssertionError: 설명

 

설명도 붙일 수 있다. 

2. raise

if a!=1:
    print('a')
else:
    raise ZeroDivisionError

ZeroDivisionError Traceback (most recent call last) Cell In[92], line 4 2 print('a') 3 else:

----> 4 raise ZeroDivisionError ZeroDivisionError:

에러명을 내가 정의할 수 있다. 

 

모든 에러 확인

import builtins
dir(builtins)
[i for i in dir(builtins) if 'Error' in i]

에러의 부모를 확인하는 방법 -> .__base__ 로 확인 가능. 

AssertionError.__base__

Exception


"중단 없이 실행 시켜야 하는 경우"

1. try - except

try 에서 에러가 발생하면 except문으로 넘어간다.

try에서 에러가 발생하지 않으면, else로 넘어감. 


# else 3가지

as
from
try

반복이 끝나고 나면 else값이 찍힘
else가 안 찍히는 2가지 경우
1. for문이 제대로 수행되지 않은 경우
2. break
#control flow
- 조건
- 반복
-예외처리

:else
try:     # try에서 에러가 나지 않으면 
    1/3
except:
    print('a')
else:         #else를 처리한다. 
    print('b')
finally:
    print('c')     #굳이 finally 안쓰고 그냥 print('c')해도 나옴.

b c

 

에러 값이 가장 가까운 것에 해당되는 값을 반환한다.
 
try:
    1/0
# except ZeroDivisionError:
#     print('a')
# except ArithmeticError:
#     print('bb')
except Exception as e:   # as 용법 3가지 -> import as  / with as / open as (바다코끼리 연산자)
    print(e, type(e))
except ZeroDivisionError:
    print('k')
else:
    print('b')
finally:
    print('c')
 

division by zero <class 'ZeroDivisionError'>

c


as 용법 3가지 (alias)

1. import as

2. with as

3. open as  -> 바다코끼리 연산자 walrus


from 용법 3가지 

1. import from

2. raise from

3. yiled from


메모리를 계속 할당하면 안되니까, 항상 닫아줘야 한다.

 

with 

with plt.xkcd():
    plt.plot([1,2,3,4])

특정 조건으로 수행하고 싶을 때 사용

 

@ 다음은 수행되는 순서에 집중해서 보자

class A:
    def __enter__(self):
        print('enter')
    def __exit__(self,a,b,c):
        print('exit')
a = A()
with a:
    print('with')

enter

with

exit

-> 첫 번째 def 실행 후, 본문 (with 문) 수행하고, 다시 두 번째 def 문 수행한다. 

 

 

with를 사용하는 전제조건 

-> dir()에서 __exit__가 있어야 함. 

 

 

[ source 보는 법 ]     #c는 소스 못 봄

d = plt.xkcd
import inspect
print(inspect.getsource(plt.xkcd))
print(inspect.getsource(plt.xkcd().__exit__))

 

 

'Phython' 카테고리의 다른 글

DBMS / ORM 시작  (2) 2023.09.05
파이썬의 naming, expression  (0) 2023.09.04