일급 함수 : 함수나 메서드를 일급 객체(값, 주소) 취급
고차 함수 : 함수를 아규먼트로 받거나 return값으로 반환하는 함수
donghu = print
donghu('Hello World') # Hello World
class Cat:
def sound(self):
print('냐옹')
licat = Cat()
licat_sound = licat.sound
licat_sound() # licat.sound()와 같다.
l = [10, 20, 30]
la = l.append
la(40)
print(l) # [10, 20, 30, 40]
def add(x, y):
return x + y
def sub(x, y):
return x - y
funcs = [add, sub]
print(funcs[0](2, 3)) # 5
Class Operator:
def add(x, y):
return x + y
op = Operator()
logical_op = {'add': op.add}
logical_op['add'](2, 3) # 5
함수를 인자로
def Cat(p)
p('야옹')
Cat(print) # 야옹
def square(x):
return x ** 2
def width_circle(r, s):
return s(r) * 3.14
print(width_circle(10, square)) # 314.0
함수를 결과로 반환
def create_adder(x):
def adder(y):
return x + y
return adder
add_5 = create_adder(5)
print(add_5(10)) # 15
def create_exponent(x):
def exponent(y):
return y ** x
return exponent
exponent_2 = create_exponent(2) # exponent
exponent_3 = create_exponent(3) # exponent
print(exponent_2(10)) # 출력: 100
# print(exponent(10)) => return y ** 2(이 숫자는 상수취급되어 변경시킬 수 없게 됨.)
print(exponent_3(10)) # 출력: 1000
# print(exponent(10)) => return y ** 3
함수 안의 변수는 항상 휘발되나?
def f():
l = [10, 20, 30]
print(id(l))
return l
sample = f()
id(sample) # 주소가 같다. 참조가 되어있으면 휘발되지 않음
import sys
def ff():
l = [20, 30, 40]
return l
sample_ = ff()
sys.getrefcount(sample_) # win, mac, linux 출력 값이 다름
# 중요한 포인트는 getrefcount의 작동 원리가 아니라
# 함수가 종료되어도 참조하는 변수가 있다면 값이 사라지지 않는다는 것
# getrefcount가 0이 되면 휘발됨
클로저
함수 내의 함수가 바깥쪽 변수를 참조하여 보존하는 것.
외부에서 접근 할 수 없게 데이터를 은닉하거나 캡슐화를 구현 할 수 있음.
# 클로저 아닌 경우
# 보통 클로저는 outer_function에 은닉할 값을 매개변수로 값을 넘겨줌
def outer_function():
def inner_function():
return 100+100
return inner_function
# 클로저인 경우
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
inner = outer_function(100)
inner(200) # inner 입장에서 100을 변경할 수 있는 방법이 없음.
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
counter_a = make_counter()
print(counter_a()) # 1 # count에 접근 할 수 있는 방법이 없음.
print(counter_a()) # 2
데코레이터
함수 또는 메서드를 꾸며주는 함수
Django에서는 다음과 같이 사용
def login(arg):
pass
@login
def 게시판읽기():
pass
데코레이터는 고차 함수.
함수를 인자로 받아서 새로운 함수 반환
def simple_decorator(function):
def wrapper():
print("Before the function call")
function()
print("After the function call")
return wrapper
@simple_decorator
def hello():
print("Hello, World!")
hello() # 이렇게만 하면 simple_decorator에 hello를 아규먼트로 넣어주고 실행
# 데코레이터가 없는 상태에서는 simple_decorator(hello)() 와 같음
# 데코레이터가 없는 경우
def simple_decorator(function):
def wrapper():
print("Before the function call")
function()
print("After the function call")
return wrapper
def hello():
print("Hello, World!")
simple_decorator(hello)()
# simple_decorator(hello) => wrapper
# simple_decorator(hello)() => wrapper()
# step 1
def data_Preprocessing(function):
def wrapper():
pass
return wrapper
@data_Preprocessing
def mean(data):
return sum(data)/len(data)
mean([1, 2, '3', 4, '5']) # TypeError 발생
# step 2
def data_Preprocessing(function):
def wrapper(data):
print(data)
return wrapper
@data_Preprocessing
def mean(data):
return sum(data)/len(data)
mean([1, 2, '3', 4, '5']) # 데이터만 출력하고 함수는 None을 반환
# step 3
def data_Preprocessing(function):
def wrapper(data):
return function(list(map(int, data)))
return wrapper
@data_Preprocessing
def mean(data):
return sum(data)/len(data)
mean([1, 2, '3', 4, '5']) # 출력: 3.0 (정상 작동) # mean을 실행하는게 아님
# data_preprocessing(mean) => wrapper
# data_preprocessing(mean)([1, 2, '3', 4, '5']) => wrapper([1, 2, '3', 4, '5'])
인자가 어디에 들어가는지 확인
def wrapper(a, b, c):
print(a, b, c)
print(function([a, b, c]))
return wrapper
@data_Preprocessing
def mean(data):
return sum(data)/len(data) # data랑 얘는 상관이 없음. wrapper에 들어가기 때문
mean(10, 20, 30) # data인자가 하나고, 10, 20, 30인자가 3개인데 오류가 없는 이유: 10, 20, 30이 wrapper에 들어감
동작 상세
def outer(function):
def wrapper():
function()()
return 'hello'
return wrapper
@outer
def a():
def b():
print('hello b')
return b
print(a())
# a()가 호출되면 outer(a)로 들어감. return wrapper에서 wrapper()호출,
# function()에서 a()호출, return b 이므로 a()() = b() 호출, print('hello b')하고,
# print(a()) 이므로 wrapper()의 리턴인 'hello' print
이 밑에서 부터는 나중에 필요할 때 다시 공부..
중첩 데코레이터
def add_exclamation(function):
def wrapper(text):
print(f'add_exclamation 데코레이터 시작')
result = function(text) + "!"
print(f'add_exclamation 데코레이터 종료')
return result
return wrapper
def add_question_mark(function):
def wrapper(text):
print(f'add_question_mark 데코레이터 시작')
result = function(text) + "?"
print(f'add_question_mark 데코레이터 종료')
return result
return wrapper
def add_dot(function):
def wrapper(text):
print(f'add_dot 데코레이터 시작')
result = function(text) + "."
print(f'add_dot 데코레이터 종료')
return result
return wrapper
@add_dot
@add_question_mark
@add_exclamation
def greet(message):
print('함수실행!')
return message
result = greet('Hello')
print(result)
# add_dot 데코레이터 시작
# add_question_mark 데코레이터 시작
# add_exclamation 데코레이터 시작
# 함수실행!
# add_exclamation 데코레이터 종료
# add_question_mark 데코레이터 종료
# add_dot 데코레이터 종료
# Hello!?.
정적 데코레이터
데코레이터를 감싸는 함수를 더 만들어서 아규먼트를 받는 방법
def add(n):
def decorator(function): # 여기서부터의 기능은 같음
def new_function(a, b):
print(f'plus 함수가 {n}만큼 증가시키는 데코레이터가 시작됩니다.')
result = function(a, b)
print(result)
print(f'plus 함수가 {n}만큼 증가시키는 데코레이터가 종료됩니다.')
return result + n
return new_function
return decorator
@add(1000)
def plus(a, b):
print('plus 함수가 호출되었습니다.')
return a + b
result = plus(10, 20)
print(f'result : {result}')
# plus 함수가 1000만큼 증가시키는 데코레이터가 시작됩니다.
# plus 함수가 호출되었습니다.
# 30
# plus 함수가 1000만큼 증가시키는 데코레이터가 종료됩니다.
# result : 1030
'Python' 카테고리의 다른 글
Python(18) f-string 문법 (0) | 2023.09.21 |
---|---|
Python(17) args, kwargs, 이터레이터와 제너레이터 (1) | 2023.09.20 |
Python(15) 예외 처리와 오류 관리 (0) | 2023.09.19 |
Python(14) 모듈 (0) | 2023.09.19 |
Python(13) 클래스 심화 (1) | 2023.09.19 |