Closures
내부 기능이 폐쇄 역할을 할 수 있습니다. 다른 함수에 의해 동적으로 생성되는 함수로, 함수 외부에서 생성된 변수의 값을 변경하고 기억할 수 있습니다.
다음 예제는 이전 기사() 예제를 기반으로 합니다. 우리는 상상력이 없기 때문에 새로운 기사2()라고 부르고, 내부() 기능을 내부2()라고 하는 폐쇄 기능으로 바꾸자. 차이점은 다음과 같습니다.
• inner2는 외부말 매개변수를 인수로 얻는 대신 직접 사용합니다.
• nights2px는 내부 2 함수 이름을 호출하는 대신 반환합니다.
>>> def knights2(saying):
def inner2():
return "We are the knights who say: '%s'" % saying
return inner2
내부2() 함수는 전달된 말의 가치를 알고 기억합니다. line return inner2는 inner2 함수의 이 특수 복사본을 반환합니다(하지만 호출하지는 않음). 이것은 폐쇄입니다. 어디서 왔는지 기억하는 동적으로 만들어진 함수입니다.
다른 인수를 사용하여 기사 2()를 두 번 호출합니다.
>>> a = knights2('Duck')
>>> b = knights2('Hasenpfeffer')
좋아, 그럼 A와 B는 뭐야?
>>> type(a) <class 'function'> >>> type(b) <class 'function'>
기능이지만 폐쇄이기도 합니다.
>>> a
<function knights2.<locals>.inner2 at 0x10193e158>
>>> b
<function knights2.<locals>.inner2 at 0x10193e1e0>
우리가 그들을 부른다면, 그들은 그들이 기사2에 의해 창조되었을 때 사용되었던 속담을 기억한다:
>>> a()
"We are the knights who say: 'Duck'"
>>> b()
"We are the knights who say: 'Hasenpfeffer'"
Anonymous Functions: the lambda() Function
Python에서 람다 함수는 단일 문장으로 표현되는 익명 함수입니다. 일반적인 작은 기능 대신 사용할 수 있습니다.
이를 설명하기 위해 먼저 정규 함수를 사용하는 예를 만들어 보겠습니다. 먼저 edit_story() 함수를 정의하겠습니다. 그 주장은 다음과 같다.
• 단어—단어 목록
• func—단어의 각 단어에 적용하는 기능
>>> def edit_story(words, func): ... for word in words:
... print(func(word))
이제 단어 목록과 각 단어에 적용할 기능이 필요합니다. 여기 제 고양이가 계단 하나를 놓쳤을 때 내는 (가정적인) 소리 목록이 있습니다.
>>> stairs = ['thud', 'meow', 'thud', 'hiss']
그리고 함수의 경우, 각 단어를 대문자로 쓰고 느낌표를 붙입니다.
고양이 타블로이드 신문 헤드라인에 적합:
>>> def enliven(word): # give that prose more punch ... return word.capitalize() + '!'
재료 혼합:
>>> edit_story(stairs, enliven)
Thud!
Meow!
Thud!
Hiss!
드디어 람다에 도착했군. 활성화() 기능이 너무 짧아서 대체할 수 있었습니다.
람다와 함께:
>>>
>>> edit_story(stairs, lambda word: word.capitalize() + '!') Thud!
Meow!
Thud!
Hiss!
>>>
람다는 하나의 주장을 받아들입니다. 여기서 우리는 그것을 단어라고 부릅니다. 대장과 끝 괄호 사이의 모든 것이 함수의 정의입니다.
종종 람다를 사용하는 것보다 활력()과 같은 실제 기능을 사용하는 것이 훨씬 더 명확합니다. 람다는 그렇지 않으면 많은 작은 함수들을 정의해야 할 경우에 가장 유용합니다. 그리고 그것들을 모두 기억해야 합니다. 특히 그래픽 사용자 인터페이스에서 람다를 사용하여 콜백 함수를 정의할 수 있습니다. 예는 부록 A를 참조하십시오.
Generators
생성기는 Python 시퀀스 생성 개체입니다. 이 기능을 사용하면 전체 시퀀스를 한 번에 만들고 메모리에 저장하지 않고도 잠재적으로 큰 시퀀스를 반복할 수 있습니다. 생성기는 반복측정기의 데이터 원본인 경우가 많습니다. 이전 코드 예제에서는 이미 범위()라는 이름을 사용하여 일련의 정수를 생성했습니다. Python 2에서 range()는 목록을 반환하여 메모리에 맞도록 제한합니다. Python 2에는 생성기 xrange()도 있으며, 이는 Python 3에서 일반 범위()가 되었다. 이 예제에서는 1에서 100까지의 모든 정수를 추가합니다.
>>> sum(range(1, 101))
5050
생성기를 통해 반복할 때마다 마지막으로 호출된 시간을 추적하고 다음 값을 반환합니다. 이는 이전 통화에 대한 메모리가 없고 항상 동일한 상태의 첫 회선에서 시작되는 일반 함수와는 다릅니다.
잠재적으로 큰 시퀀스를 만들고 코드가 너무 커서 제너레이터를 이해할 수 없는 경우 제너레이터 함수를 작성합니다. 정상 함수이지만 반환이 아닌 항복문으로 값을 반환합니다. 고유한 범위 버전()을 작성해 보겠습니다.
>>> def my_range(first=0, last=10, step=1):
number = first while number < last:
yield number number += step
정상적인 기능입니다.
>>> my_range
<function my_range at 0x10193e268>
생성기 개체를 반환합니다.
>>> ranger = my_range(1, 5)
>>> ranger
<generator object my_range at 0x101a0a168>
이 생성기 개체에 대해 반복할 수 있습니다.
>>> for x in ranger: ... print(x) ...
1
2 3 4
Decorators
경우에 따라 소스 코드를 변경하지 않고 기존 함수를 수정하려고 할 수 있습니다. 일반적인 예는 전달된 인수를 확인하기 위해 디버깅 문을 추가하는 것입니다.
데코레이터는 한 함수를 입력으로 사용하고 다른 함수를 반환하는 함수입니다. Python 트릭 백을 자세히 살펴보고 다음을 사용합니다.
• *병력 및 **왜성
• 내부 기능
• 인수로서의 함수
document_it() 함수는 다음 작업을 수행할 장식자를 정의합니다.
• 함수의 이름과 인수 값을 인쇄합니다.
• 인수를 사용하여 함수 실행
• 결과 인쇄
• 수정된 기능을 사용할 수 있도록 반환
코드는 다음과 같습니다.
- >>> def document_it(func):
document_it()에 전달하는 함수는 document_it()가 추가하는 추가 문을 포함하는 새 함수를 제공합니다. 데코레이터는 실제로 func에서 코드를 실행할 필요가 없지만 document_it()는 func를 호출하여 func뿐만 아니라 모든 추가 결과를 얻을 수 있도록 합니다.
그래서 이걸 어떻게 사용하죠? 장식자를 수동으로 적용할 수 있습니다
- >>> def add_ints(a, b):
- ... returna+b ...
>>> add_ints(3, 5)
8
>>> cooler_add_ints = document_it(add_ints) # manual decorator assignment >>> cooler_add_ints(3, 5)
Running function: add_ints
Positional arguments: (3, 5) - Keyword arguments: {}
- Result: 8
- 8
- 위의 수동 데코레이터 할당 대신, 꾸미려는 함수 앞에 @decorator_name을 추가하십시오.
>>> @document_it
... def add_ints(a, b):
... returna+b
...
>>> add_ints(3, 5)
Start function add_ints Positional arguments: (3, 5) Keyword arguments: {} Result: 8
8
기능별로 둘 이상의 데코레이터를 둘 수 있습니다. 결과를 제곱하는 square_it()라는 다른 장식가를 작성해 보겠습니다.
...
...
...
...
...
def new_function(*args, **kwargs): result = func(*args, **kwargs) return result * result
return new_function
함수에 가장 근접하게 사용된 데코레이터(decorator, 정의 바로 위)가 먼저 실행된 다음 그 위에 있는 데코레이터가 실행됩니다. 두 순서 모두 동일한 최종 결과를 제공하지만 중간 단계가 어떻게 변하는지 확인할 수 있습니다.
>>> @document_it
... @square_it
... def add_ints(a, b):
... returna+b
...
>>> add_ints(3, 5)
Running function: new_function Positional arguments: (3, 5) Keyword arguments: {}
Result: 64
64
데코레이터 순서를 반대로 해 보겠습니다.
>>> @square_it
... @document_it
... def add_ints(a, b): ... returna+b
...
>>> add_ints(3, 5) Running function: add_ints
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8
64
Namespaces and Scope
이름은 어디에 쓰이느냐에 따라 다른 것을 가리킬 수 있다. Python 프로그램에는 특정 이름이 고유하고 다른 네임스페이스의 동일한 이름과 관련이 없는 섹션 등 다양한 네임스페이스가 있습니다.
각 함수는 고유한 네임스페이스를 정의합니다. 주 프로그램에서 x라는 변수를 정의하고 함수에서 x라는 다른 변수를 정의하면 다른 변수를 나타냅니다. 그러나 벽을 뚫을 수 있습니다. 필요한 경우 다양한 방법으로 다른 네임스페이스의 이름에 액세스할 수 있습니다.
프로그램의 주요 부분은 글로벌 네임스페이스를 정의하므로 해당 네임스페이스의 변수는 글로벌 변수입니다.
함수 내에서 전역 변수의 값을 가져올 수 있습니다.
>>> animal = 'fruitbat'
>>> def print_global():
... print('inside print_global:', animal) ...
>>> print('at the top level:', animal)
at the top level: fruitbat
>>> print_global()
inside print_global: fruitbat
그러나 전역 변수의 값을 가져와 함수 내에서 변경하려고 하면 다음 오류가 발생합니다.
>>> def change_and_print_global():
- ... print('inside change_and_print_global:', animal)
- ... animal = 'wombat'
- ... print('after the change:', animal) ...
>>> change_and_print_global()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in change_and_report_it
UnboundLocalError: local variable 'animal' referenced before assignment
이 변수를 변경하면 이름이 동물인 다른 변수도 변경되지만 이 변수는 함수 내부에 있습니다.
- >>> def change_local():
>>> change_local()
inside change_local: wombat 4330406160
>>> animal
'fruitbat'
>>> id(animal)
4330390832
이게 어찌된 일이냐? 첫 번째 줄은 동물이라는 글로벌 변수에 '과일배트' 문자열을 할당했습니다. change_local() 함수에도 animal이라는 변수가 있지만, 이 변수는 로컬 네임스페이스에 있습니다.
여기서는 Python 함수 ID()를 사용하여 각 객체에 대한 고유한 값을 인쇄하고 change_local() 내부의 변수 동물이 프로그램의 메인 레벨에서 동물과 같지 않음을 증명했습니다.
함수 내의 로컬 변수가 아닌 전역 변수에 액세스하려면 글로벌 키워드를 사용해야 합니다(이것이 올 것임을 알고 있었음: expiritive is been implicit):
>>> animal = 'fruitbat'
>>> def change_and_print_global():
- ... global animal
- ... animal = 'wombat'
- ... print('inside change_and_print_global:', animal) ...
>>> animal
'fruitbat'
>>> change_and_print_global()
inside change_and_print_global: wombat
>>> animal
'wombat'
함수 내에서 전역이라고 말하지 않으면 Python은 로컬 네임스페이스를 사용하며 변수는 로컬입니다. 기능이 완료되면 사라집니다.
Python은 네임스페이스의 내용에 액세스할 수 있는 두 가지 기능을 제공합니다. • locals()는 로컬 네임스페이스의 콘텐츠 사전을 반환합니다.
• globalsyspace는 글로벌 네임스페이스의 내용에 대한 사전을 반환합니다. 그리고 여기서 사용되고 있습니다.
- >>> animal = 'fruitbat' >>> def change_local():
>>> print('globals:', globals()) # reformatted a little for presentation globals: {'animal': 'fruitbat',
'__doc__': None,
'change_local': <function change_it at 0x1006c0170>,
'__package__': None,
'__name__': '__main__',
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__builtins__': <module 'builtins'>}
>>> animal
'fruitbat'
change_local() 내의 로컬 네임스페이스에는 로컬 변수 동물만 포함되어 있습니다. 글로벌 네임스페이스에는 별도의 글로벌 변수 동물과 여러 가지가 포함되어 있습니다.
Uses of _ and __ in Names
두 개의 밑줄(__)로 시작하고 끝나는 이름은 Python 내에서 사용할 수 있도록 예약되어 있으므로 자신의 변수와 함께 사용하면 안 됩니다. 이 이름 지정 패턴은 응용 프로그램 개발자가 자체 변수에 대해 선택할 가능성이 낮기 때문에 선택되었습니다.
예를 들어, 함수의 이름은 시스템 변수 함수 ._name__에 있으며 문서화 문자열은 함수입니다.__doc__:
>>> def amazing():
- ... '''This is the amazing function.
- ... Want to see it again?'''
- ... print('This function is named:', amazing.__name__)
- ... print('And its docstring is:', amazing.__doc__) ...
>>> amazing()
This function is named: amazing
And its docstring is: This is the amazing function.
Want to see it again?
앞서 글로벌 인쇄물에서 보셨듯이, 메인 프로그램에는 특별 프로그램이 할당되어 있습니다.
이름 __main_.
- Handle Errors with try and except
- 일부 언어에서는 오류가 특수 함수 반환 값으로 표시됩니다. Python은 관련 오류가 발생할 때 실행되는 코드: 예외를 사용합니다.
위치를 벗어난 목록이나 튜플 또는 존재하지 않는 키를 가진 사전 액세스와 같은 일부 항목이 이미 있습니다. 경우에 따라 실패할 수 있는 코드를 실행하는 경우 잠재적인 오류를 차단하기 위해 적절한 예외 처리기도 필요합니다. - 예외가 발생할 수 있는 모든 위치에 예외 처리를 추가하여 사용자에게 상황을 알리는 것이 좋습니다. 문제를 해결하지 못할 수도 있지만 최소한 상황을 확인하고 프로그램을 정상적으로 종료할 수는 있습니다. 일부 기능에서 예외가 발생했지만 해당 기능에서 잡히지 않으면 일부 호출 기능에서 일치하는 핸들러에 잡힐 때까지 거품이 발생합니다. 사용자 고유의 예외 처리기를 제공하지 않는 경우 Python은 오류 메시지와 오류가 발생한 위치에 대한 일부 정보를 인쇄한 후 프로그램을 종료합니다.
- >>> short_list = [1, 2, 3]
- >>> position = 5
- >>> short_list[position]
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module> IndexError: list index out of range
코드를 운에 맡기지 말고 코드를 래핑해 보십시오. 오류 처리 기능은 예외입니다.
>>> short_list = [1, 2, 3] >>> position = 5
>>> try:
... short_list[position] ... except:
... print('Need a position between 0 and', len(short_list)-1, ' but got', ... position)
...
Need a position between 0 and 2 but got 5
시도 블록 내부의 코드가 실행됩니다. 오류가 발생하면 예외가 발생하고 예외 블록 내부의 코드가 실행됩니다. 오류가 없으면 예외 블록을 건너뜁니다.
여기서처럼 인수가 없는 경우를 제외하고 평면을 지정하는 것은 모든 예외 유형에 대한 캐치올입니다. 둘 이상의 예외 유형이 발생할 수 있는 경우 각 예외 처리기를 별도로 제공하는 것이 가장 좋습니다. 이렇게 하도록 강요하는 사람은 없습니다. 모든 예외를 포착하는 것 외에는 베어(Bare)를 사용할 수 있지만 이러한 예외에 대한 처리가 일반적일 수 있습니다(일부 인쇄 오류가 발생했습니다). 원하는 수의 특정 예외 처리기를 사용할 수 있습니다.
때로는 유형을 벗어난 예외 세부 정보를 원할 수 있습니다. 다음 형식을 사용하는 경우 변수 이름에 전체 예외 개체가 표시됩니다.
except exceptiontype as name
다음 예제에서는 시퀀스에 잘못된 위치를 제공할 때 IndexError가 발생하는 예외 유형이기 때문에 먼저 IndexError를 찾습니다. IndexError 예외는 변수에 저장하고 다른 예외는 변수에 저장합니다. 이 예에서는 다른 항목에 저장된 모든 내용을 인쇄하여 해당 개체에 있는 내용을 보여 줍니다.
>>> short_list = [1, 2, 3] >>> while True:
...
...
...
... try:
value = input('Position [q to quit]? ') if value == 'q':
break
...
...
...
...
...
...
...
Position [q to quit]? 1
2
Position [q to quit]? 0
1
Position [q to quit]? 2
3
Position [q to quit]? 3
Bad index: 3
Position [q to quit]? 2
3
Position [q to quit]? two
Something else broke: invalid literal for int() with base 10: 'two' Position [q to quit]? q
위치 3을 입력하면 예상대로 인덱스 오류가 발생했습니다. 두 개를 입력하면 두 번째에 처리한 int() 함수가 코드만 제외하고 모두 잡힙니다.
Make Your Own Exceptions
이전 섹션에서는 처리 예외에 대해 설명했지만, 모든 예외(예: IndexError)는 Python 또는 표준 라이브러리에 미리 정의되어 있습니다. 원하는 용도로 사용할 수 있습니다. 또한 프로그램에서 발생할 수 있는 특수한 상황을 처리하기 위해 고유한 예외 유형을 정의할 수도 있습니다.
예외는 수업이다. 예외 클래스의 하위 항목입니다. 대문자라는 예외를 만들자.문자열에 대문자가 있을 경우 예외로 올리고 대문자로 표시합니다.
>>> class UppercaseException(Exception): ... pass
>>> words = ['eeenie', 'meenie', 'miny', 'MO'] >>> for word in words:
... if word.isupper():
... raise UppercaseException(word) ...
Traceback (most recent call last): File "<stdin>", line 3, in <module>
__main__.UppercaseException: MO
대문자에 대한 동작도 정의하지 않았습니다.예외(방금 통과를 사용함)를 통해 상위 클래스인 예외(Exception)가 예외가 발생했을 때 인쇄할 내용을 파악할 수 있습니다.
예외 개체 자체에 액세스하여 인쇄할 수 있습니다.
>>> try:
... raise OopsException('panic') ... except OopsException as exc: ... print(exc)
...
panic
Things to Do
4.1 guess_me 변수에 값 7을 할당합니다. 그런 다음 guess_me가 7보다 작으면 'too low', 7보다 크면 'too high', 7보다 크면 'just right' 문자열을 인쇄하는 조건부 테스트(if, elif)를 작성합니다.
4.2 변수 guess_me에 값 7을, 변수 시작에 값 1을 할당합니다. guess_me와 시작을 비교하는 시간 루프를 작성합니다. 시작이 내 짐작보다 작으면 너무 낮게 인쇄합니다. 시작이 guess_me이면 '찾았다!'를 인쇄하고 루프를 종료합니다. 시작할 경우
루프가 더 크죠
4.3 4.4 사용
4.5 반품 시 a 사용
4.6 사용
4.9 범위(10)에서 홀수를 반환하는 get_odds라는 생성기 함수를 정의합니다. 반환된 세 번째 값을 찾아 인쇄하려면 for 루프를 사용하십시오.
than guess_me, 'oops'를 인쇄하고 루프를 종료합니다. 끝에서 시작 증분
루프에서 목록 값을 인쇄합니다 [3, 2, 1, 0].
(10) 범위의 짝수 목록을 작성하기 위해 이해 목록을 작성합니다.
사전 정사각형을 만들기 위한 사전 이해. 범위(10) 키를 사용하고 각 키의 정사각형을 값으로 사용합니다.
범위(10)의 홀수에서 홀수 집합을 생성하도록 이해를 설정합니다. 발생기 이해는 문자열 'Got'을 반환하고, 값은 값을 반환합니다.
범위(10). for 루프를 사용하여 이 과정을 반복합니다.
4.8 목록을 반환하는 good라는 함수를 정의합니다 ['해리', '론', '헤르미온느'.
4.7 숫자 사용
4.10 함수를 호출할 때 '시작'을 인쇄하고 종료할 때 '끝'을 인쇄하는 테스트라는 데코레이터를 정의합니다.
4.11 OopsException이라는 예외를 정의합니다. 무슨 일이 일어나는지 보려면 이 예외를 제기하십시오. 그런 다음 이 예외를 잡기 위한 코드를 작성하고 'Caught a oops'를 인쇄합니다.
4.12 zipcope을 사용하여 제목 = [습관의 창조물', [크루웰 페이트] 및 플롯 = [수녀가 괴물로 변한다', [유령 실 가게] 목록과 짝을 이루는 영화라는 사전을 만듭니다.