개발/Python

[파이썬] 블록 범위

MinorMan 2022. 10. 11. 03:52
반응형

<질문>

다른 언어로 코딩할 때 다음과 같은 블록 범위를 만드는 경우가 있습니다.

statement
...
statement
{
    statement
    ...
    statement
}
statement
...
statement

(많은 것 중) 한 가지 목적은 코드 가독성을 향상시키는 것입니다. 특정 명령문이 논리 단위를 형성하거나 특정 지역 변수가 해당 블록에서만 사용된다는 것을 보여주기 위함입니다.

Python에서 동일한 작업을 수행하는 관용적 방법이 있습니까?


<답변1>

아니요, 블록 범위 생성에 대한 언어 지원은 없습니다.

다음 구문은 범위를 생성합니다.

  • 기준 치수
  • 수업
  • 함수(람다 포함)
  • 생성기 표현
  • 내포(dict, set, list(Python 3.x에서))

<답변2>

Python의 관용적 방법은 함수를 짧게 유지하는 것입니다. 이것이 필요하다고 생각되면 코드를 리팩토링하십시오! :)

Python은 각 모듈, 클래스, 함수, 생성기 표현식, 사전 이해, 집합 이해에 대한 새 범위를 만들고 Python 3.x에서도 각 목록 이해에 대해 새 범위를 만듭니다. 이 외에도 함수 내부에는 중첩 범위가 없습니다.


<답변3>

함수 내에서 함수를 선언한 다음 즉시 호출하여 Python에서 C++ 블록 범위와 유사한 작업을 수행할 수 있습니다. 예를 들어:

def my_func():
    shared_variable = calculate_thing()

    def do_first_thing():
        ... = shared_variable
    do_first_thing()

    def do_second_thing():
        foo(shared_variable)
        ...
    do_second_thing()

왜 이것을 하고 싶은지 확신이 서지 않는다면this video 확신할 수 있습니다.

기본 원칙은 절대적으로 필요한 것보다 더 넓은 범위에 '쓰레기'(추가 유형/함수)를 도입하지 않고 가능한 한 엄격하게 모든 범위를 지정하는 것입니다.do_first_thing() 예를 들어 메서드를 호출하는 함수 외부에서 범위를 지정해서는 안 됩니다.


<답변4>

차단 범위가 없다는 데 동의합니다. 하지만 Python 3의 한 곳에서는같다 블록 범위가 있는 것처럼.

이 모양을 준 무슨 일이?

이것은 Python 2에서 제대로 작동했지만 Python 3에서 변수 누출을 방지하기 위해 이 트릭을 수행했으며 이 변경으로 인해 블록 범위가 있는 것처럼 보입니다.

설명하겠습니다.

범위의 개념에 따라 같은 범위 안에 같은 이름의 변수를 도입할 때 그 값을 수정해야 합니다.

다음은 Python 2에서 발생하는 일입니다.

>>> x = 'OLD'
>>> sample = [x for x in 'NEW']
>>> x
'W'

하지만 Python 3에서는 같은 이름의 변수가 도입되어도 덮어쓰지 않고, 리스트 컴프리헨션이 왠지 샌드박스처럼 동작해서 그 안에 새로운 범위를 생성하는 것 같다.

>>> x = 'OLD'
>>> sample = [x for x in 'NEW']
>>> x
'OLD'

그리고 이 답변은 답변자에게 반합니다.ThomasH's statement 범위를 생성하는 유일한 수단은 함수, 클래스 또는 모듈입니다. 이것은 새로운 범위를 생성하는 또 다른 장소처럼 보이기 때문입니다.


<답변5>

가장 쉬운 인터페이스와 코드에 도입할 추가 이름이 가장 적은 솔루션을 찾았습니다.

from scoping import scoping
a = 2
with scoping():
    assert(2 == a)
    a = 3
    b = 4
    scoping.keep('b')
    assert(3 == a)
assert(2 == a)
assert(4 == b)

https://pypi.org/project/scoping/


<답변6>

완전성을 위해: 당신 다음을 사용하여 지역 변수의 범위를 종료합니다.. 또한보십시오Python에서 del은 언제 유용합니까?. 그러나 그것은 확실히 관용적이지 않습니다.

statement
statement

# Begin block
a = ...
b = ...
statement
statement
del a, b
# End block

statement

<답변7>

모듈(및 패키지)은 프로그램을 별도의 네임스페이스로 나누는 훌륭한 Python 방식이며, 이는 이 질문의 암시적 목표인 것 같습니다. 사실 저는 파이썬의 기초를 배우면서 블록 스코프 기능이 없어서 답답했습니다. 그러나 일단 Python 모듈을 이해하고 나면 블록 범위 없이 이전 목표를 더 우아하게 실현할 수 있습니다.

동기를 부여하고 사람들을 올바른 방향으로 안내하기 위해 Python의 범위 지정 구성에 대한 명시적인 예를 제공하는 것이 유용하다고 생각합니다. 먼저 Python 클래스를 사용하여 블록 범위를 구현하려는 시도가 실패했는지 설명합니다. 다음으로 Python 모듈을 사용하여 더 유용한 것을 달성한 방법을 설명합니다. 마지막으로 데이터 로드 및 필터링에 패키지를 실제로 적용하는 방법을 간략하게 설명합니다.

잠시 동안 나는 클래스 선언 안에 코드를 집어넣어 블록 범위를 달성했다고 생각했습니다.

x = 5
class BlockScopeAttempt:
    x = 10
    print(x) # Output: 10
print(x) # Output: 5

불행히도 이것은 함수가 정의될 때 분해됩니다:

x = 5 
class BlockScopeAttempt: 
    x = 10
    print(x) # Output: 10
    def printx2(): 
        print(x) 
    printx2() # Output: 5!!!

클래스 내에 정의된 함수는 전역 범위를 사용하기 때문입니다. 이 문제를 해결하는 가장 쉬운(유일한 것은 아니지만) 방법은 클래스를 명시적으로 지정하는 것입니다.

x = 5 
class BlockScopeAttempt: 
    x = 10
    print(x) # Output: 10
    def printx2(): 
        print(BlockScopeAttempt.x)  # Added class name
    printx2() # Output: 10

클래스에 포함되어 있는지 여부에 따라 함수를 다르게 작성해야 하기 때문에 이것은 그렇게 우아하지 않습니다.

모듈은 정적 클래스와 매우 유사하지만 내 경험에 따르면 모듈이 훨씬 깨끗합니다. 모듈과 동일한 작업을 수행하기 위해 다음과 같은 파일을 만듭니다.my_module.py 현재 작업 디렉토리에 다음 내용이 포함되어 있습니다.

x = 10
print(x) # (A)

def printx():
    print(x) # (B)

def alter_x():
    global x
    x = 8

def do_nothing():
    # Here x is local to the function.
    x = 9

그런 다음 내 기본 파일이나 대화형(예: Jupyter) 세션에서

x = 5
from my_module import printx, do_nothing, alter_x  # Output: 10 from (A)
printx()  # Output: 10 from (B)
do_nothing()
printx()  # Output: 10
alter_x()
printx()  # Output: 8
print(x) # Output: 5
from my_module import x  # Copies current value from module
print(x) # Output: 8
x = 7
printx()  # Output: 8
import my_module
my_module.x = 6
printx()  # Output: 6

설명에 따르면 각 Python 파일은 고유한 전역 네임스페이스가 있는 모듈을 정의합니다. 그만큼import my_module 명령을 사용하면 이 네임스페이스의 변수에 액세스할 수 있습니다.. 통사론. 정적 클래스와 같은 모듈을 생각합니다.

대화식 세션에서 모듈로 작업하는 경우 처음에 이 두 줄을 실행할 수 있습니다.

%load_ext autoreload
%autoreload 2

해당 파일이 수정되면 모듈이 자동으로 다시 로드됩니다.

패키지라는 개념은 모듈 개념을 약간 확장한 것입니다. 패키지는 다음을 포함하는 디렉토리입니다(비어 있을 수 있음).__init__.py 가져올 때 실행되는 파일입니다. 이 디렉토리 내의 모듈/패키지는 다음을 사용하여 액세스할 수 있습니다.. 통사론.

데이터 분석을 위해 대용량 데이터 파일을 읽은 다음 다양한 필터를 대화식으로 적용해야 하는 경우가 많습니다. 파일을 읽는 데 몇 분이 걸리므로 한 번만 수행하고 싶습니다. 학교에서 객체 지향 프로그래밍에 대해 배운 것을 기반으로 클래스의 메서드로 필터링 및 로드를 위한 코드를 작성해야 한다고 믿었습니다. 이 접근 방식의 주요 단점은 필터를 재정의하면 클래스 정의가 변경되므로 데이터를 포함하여 전체 클래스를 다시 로드해야 한다는 것입니다.

요즘에는 Python으로 다음이라는 패키지를 정의합니다.my_data 이름이 지정된 하위 모듈이 포함된load 그리고filter. 내면에filter.py 상대 가져오기를 수행할 수 있습니다.

from .load import raw_data

내가 수정하면filter.py, 그 다음에autoreload 변경 사항을 감지합니다. 다시로드되지 않습니다load.py, 그래서 내 데이터를 다시 로드할 필요가 없습니다. 이렇게 하면 Jupyter 노트북에서 필터링 코드의 프로토타입을 만들고 함수로 래핑한 다음 노트북에서 직접 잘라 붙여넣을 수 있습니다.filter.py. 이 사실을 알아낸 것은 내 워크플로에 혁명을 일으켰고 회의론자에서 "파이썬의 선(Zen of Python)"을 믿는 사람으로 전환했습니다.

반응형