728x90
- 숫자로 이뤄진 list를 정렬하되, 정렬한 리스트의 앞쪽에는 우선 순위를 부여한 몇몇 숫자를 기준으로 위치시킨다고 가정하자.
def sort_priority(values, group):
def helper(x):
if x in group:
return (0, x)
return (1, x)
values.sort(key=helper)
numbers = [8, 3, 1, 2, 5, 4, 7, 6]
group = {2, 3, 5, 7}
sort_priority(numbers, group)
print(numbers) # [2, 3, 5, 7, 1, 4, 6, 8]
영역과 관련 함수 주요 개념
- 파이썬 클로저 를 지원
- 클로저란 자신이 정의된 영역 밖의 변수를 참조하는 함수다.
- 파이썬에서 함수가 일급 시민 (first-class citizen) 객체임:
- 변수에 대입하거나, 다른 함수에 인자로 전달할 수 있으며, 식이나 if 문에서 함수를 비교하거나 함수에서 반환하는 것 등이 가능하다는 것을 의미한다.
- 파이썬에서는 시퀀스 (튜플 포함)를 비교하는 구체적인 규칙이 있음.
- 우선 순위가 높은 원소가 발견했음을 표시하는 플래그를 설정했다고 가정해보자
def sort_priority2(numbers, group):
found = False
def helper(x):
if x in group
found = True
return (0, x)
return (1, x)
numbers.sort(key=helper)
return found
found = sort_priority2(numbers, group)
print('발견:', found) # 발견: False
print(numbers) # [2, 3, 5, 7, 1, 4, 6, 8]
- 위 결과는
False로 반환 된다. - 이유는 식 안에서 변수를 참조할 때 파이썬 인터프리터는 참조를 해결하기 위해 다음 순서로 영역을 뒤진다.
- 현재 함수의 영역
- 현재 함수를 둘러싼 영역
- 현재 코드가 들어 있는 모듈의 영역 (
global) - 내장 영역 (
lenstr등 기본 함수가 들어 있는 영역)
- 이러한 이유로 식이 참조하는 이름에 해당하는 변수가 4가지 영역에 없으면
NameError가 발생한다.
foo = does_not_exist * 5 # does_not_exist가 없다면 에러날 것이다.
변수에 값을 대입하는 것은 다른 방식으로 작동한다.
- 변수가 현재 영역에 이미 정의돼 있다면 그 변수의 값만 새로운 값으로 바뀐다.
- 하지만 변수가 현재 영역에 정의돼 있지 않다면 파이썬은 변수 대입을 변수 정의로 취급한다.
- 이러한 이유로 helper 함수 내부의
found는 변수가 정의된 것으로 취급되는 것이고, 기존 변수에 값을 바꾼 것이 아니게 된다. - 이러한 현상을 영역 지정 버그라고 한다.
- 이러한 이유로 helper 함수 내부의
nonlocal로 정의가 아닌 기존 변수를 찾을 수 있다.
nonlocal은 안티패턴 유발하는 코드이므로 사용을 권장하진 않는다.
def sort_priority2(numbers, group):
found = False
def helper(x):
nonlocal found # 추가함
if x in group:
found = True
return (0, x)
return (1, x)
numbers.sort(key=helper)
return found
이를 클래스로 선언하여 극복해보자
class Sorter:
def __init__(self, group):
self.group = group
self.found = False
def __call__(self, x):
if x in self.group:
self.found = True
return (0, x)
return (1, x)
sorter = Sorter(group)
numbers.sort(key=sorter)
assert sorter.found is True728x90
'Programming Language > Python' 카테고리의 다른 글
| BETTER WAY 30 - 리스트를 반환하기보다는 제너레이터를 사용하라 (0) | 2024.12.02 |
|---|---|
| BETTER WAY 26 - functools.wrap 사용해 함수 데코레이터를 정의하라 (0) | 2024.11.26 |
| BETTER WAY 15 - 딕셔너리 삽입 순서에 의존할 떄는 조심하라 (2) | 2024.11.11 |
| BETTER WAY 14 - 복잡한 기준을 사용해 정렬할 때는 key 파라미터를 사용하라 (0) | 2024.10.14 |
| BETTER WAY 13 - 슬라이싱보다는 나머지를 모두 잡아내는 언패킹을 사용하라 (1) | 2024.10.10 |