찾다
백엔드 개발파이썬 튜토리얼개발 중에 자주 직면하는 Python의 함정과 예방 조치

최근 Python을 사용하는 과정에서 변수 객체 datetime.datetime.now()를 함수의 기본 매개변수로 사용하는 경우, 모듈 순환 종속성 등 몇 가지 함정에 직면했습니다.

향후 문의 및 추가를 위해 여기에 기록해 주세요.

변경 가능한 객체를 기본 매개변수로 사용하지 마세요

함수를 사용할 때 기본 매개변수가 포함되는 경우가 많습니다. Python에서 변경 가능한 객체를 기본 매개변수로 사용하면 예기치 않은 결과가 발생할 수 있습니다.

아래 예를 보세요.

def append_item(a = 1, b = []):
    b.append(a)
    print b
     
append_item(a=1)
append_item(a=3)
append_item(a=5)

결과는 다음과 같습니다.

[1]
[1, 3]
[1, 3, 5]

결과에서 볼 수 있듯이 나중에append_item 함수를 두 번 호출하면 , 함수 매개변수 b는 []로 초기화되지 않지만 이전 함수 호출의 값을 유지합니다.

이러한 결과가 나오는 이유는 Python에서는 함수 정의 시 함수 매개변수의 기본값이 한 번만 초기화되기 때문입니다.

Python의 이 기능을 증명하는 예를 살펴보겠습니다.

class Test(object):  
    def __init__(self):  
        print("Init Test")  
           
def arg_init(a, b = Test()):  
    print(a)  
arg_init(1)  
arg_init(3)  
arg_init(5)

결과는 다음과 같습니다.

Init Test
1
3
5

이 예의 결과에서 볼 수 있듯이 , Test 클래스만 한 번 인스턴스화됩니다. 즉, 기본 매개변수는 함수 호출 횟수와 관련이 없으며 함수가 정의될 ​​때 한 번만 초기화됩니다.

가변 기본 매개변수의 올바른 사용

가변 기본 매개변수의 경우 다음 패턴을 사용하여 위와 같은 예상치 못한 결과를 방지할 수 있습니다.

def append_item(a = 1, b = None):
    if b is None:
        b = []
    b.append(a)
    print b
     
append_item(a=1)
append_item(a=3)
append_item(a=5)

결과는 다음과 같습니다.

[1]
[3]
[5]

Python의 범위

Python의 범위 확인 순서는 Local, Enclosing, Global, 내장입니다. 즉, Python 인터프리터가 변수를 이 순서로 구문 분석합니다.


간단한 예를 살펴보세요.

global_var = 0
def outer_func():
    outer_var = 1
     
    def inner_func():
        inner_var = 2
         
        print "global_var is :", global_var
        print "outer_var is :", outer_var
        print "inner_var is :", inner_var
         
    inner_func()
     
outer_func()


결과는 다음과 같습니다.

global_var is : 0
outer_var is : 1
inner_var is : 2

Python에서 범위에 관해 주의할 점 중 하나는 범위의 변수에 값을 할당할 때 Python이 해당 변수를 현재 범위의 지역 변수로 간주한다는 것입니다.


이 역시 비교적 이해하기 쉽습니다. 다음 코드의 경우 var_func는 num 변수에 값을 할당하므로 여기서 num은 var_func 범위의 로컬 변수입니다.

num = 0
def var_func():
    num = 1
    print "num is :", num
     
var_func()

문제 1

그런데, 변수를 아래와 같이 사용하면 문제가 발생합니다.

num = 0
def var_func():
    print "num is :", num
    num = 1
     
var_func()

결과는 다음과 같습니다.

UnboundLocalError: local variable 'num' referenced before assignment

이 오류가 발생하는 이유는 var_func의 num 변수에 값을 할당했기 때문에 Python 인터프리터는 num이 var_func 범위의 지역 변수라고 생각하지만 코드를 실행하여 인쇄하면 "num is :", num 문을 실행할 때 num은 여전히 ​​정의되지 않습니다.


질문 2

위 오류는 비교적 명백하며, 다음과 같이 좀 더 미묘한 오류 형태도 있습니다.

li = [1, 2, 3]
def foo():
    li.append(4)
    print li
foo()
def bar():
    li +=[5]
    print li
bar()

코드 결과는 다음과 같습니다.

[1, 2, 3, 4]
UnboundLocalError: local variable 'li' referenced before assignment

foo 함수에서는 Python의 범위 구문 분석 순서에 따라 이 함수에서는 전역 li 변수가 사용되지만 bar 함수에서는 li 변수가 할당됩니다. 따라서 li는 bar 범위에서 변수로 처리됩니다.


bar 함수의 이 문제에는 전역 키워드를 사용할 수 있습니다.

li = [1, 2, 3]
def foo():
    li.append(4)
    print li
     
foo()
def bar():
    global li
    li +=[5]
    print li
     
bar()

클래스 속성은 숨겨져 있습니다

파이썬에는 클래스 속성과 인스턴스 속성이 있습니다. 클래스 속성은 클래스 자체에 속하며 모든 클래스 인스턴스에서 공유됩니다.

클래스 속성은 클래스 이름을 통해 액세스 및 수정이 가능하며, 클래스 인스턴스를 통해서도 액세스 및 수정이 가능합니다. 그러나 인스턴스가 클래스와 동일한 이름의 속성을 정의하면 클래스 속성이 숨겨집니다.


다음 예를 보세요.

class Student(object):
    books = ["Python", "JavaScript", "CSS"]
    def __init__(self, name, age):
        self.name = name
        self.age = age
    pass
     
wilber = Student("Wilber", 27)
print "%s is %d years old" %(wilber.name, wilber.age)
print Student.books
print wilber.books
wilber.books = ["HTML", "AngularJS"]
print Student.books
print wilber.books
del wilber.books
print Student.books
print wilber.books

코드의 결과는 다음과 같습니다. 처음에는 Wilber 인스턴스에서 책에 직접 액세스할 수 있습니다. 하지만 Wilber 인스턴스가 정의된 경우 books라는 인스턴스 속성을 삭제한 후 Wilber 인스턴스의 books 속성은 Wilber 인스턴스의 books 속성인 wilber.books를 삭제한 후 클래스의 books 속성을 "숨깁니다". 다시 클래스의 books 속성에 해당합니다.

Wilber is 27 years old
['Python', 'JavaScript', 'CSS']
['Python', 'JavaScript', 'CSS']
['Python', 'JavaScript', 'CSS']
['HTML', 'AngularJS']
['Python', 'JavaScript', 'CSS']
['Python', 'JavaScript', 'CSS']

파이썬 값에서 상속을 사용할 때는 클래스 속성이 숨겨지는 것도 주의해야 합니다. 클래스의 경우 클래스의 __dict__ 속성을 통해 모든 클래스 속성을 볼 수 있습니다.


当通过类名来访问一个类属性的时候,会首先查找类的__dict__属性,如果没有找到类属性,就会继续查找父类。但是,如果子类定义了跟父类同名的类属性后,子类的类属性就会隐藏父类的类属性。


看一个例子:

class A(object):
    count = 1
     
class B(A):
    pass    
     
class C(A):
    pass        
     
print A.count, B.count, C.count      
B.count = 2
print A.count, B.count, C.count      
A.count = 3
print A.count, B.count, C.count     
print B.__dict__
print C.__dict__

结果如下,当类B定义了count这个类属性之后,就会隐藏父类的count属性:

1 1 1
1 2 1
3 2 3
{'count': 2, '__module__': '__main__', '__doc__': None}
{'__module__': '__main__', '__doc__': None}

tuple是“可变的”

在Python中,tuple是不可变对象,但是这里的不可变指的是tuple这个容器总的元素不可变(确切的说是元素的id),但是元素的值是可以改变的。

tpl = (1, 2, 3, [4, 5, 6])
print id(tpl)
print id(tpl[3])
tpl[3].extend([7, 8])
print tpl
print id(tpl)
print id(tpl[3])

代码结果如下,对于tpl对象,它的每个元素都是不可变的,但是tpl[3]是一个list对象。也就是说,对于这个tpl对象,id(tpl[3])是不可变的,但是tpl[3]确是可变的。

36764576
38639896
(1, 2, 3, [4, 5, 6, 7, 8])
36764576
38639896

Python的深浅拷贝

在对Python对象进行赋值的操作中,一定要注意对象的深浅拷贝,一不小心就可能踩坑了。


当使用下面的操作的时候,会产生浅拷贝的效果:


使用切片[:]操作

使用工厂函数(如list/dir/set)

使用copy模块中的copy()函数

使用copy模块里面的浅拷贝函数copy():

import copy
will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.copy(will)
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]

使用copy模块里面的深拷贝函数deepcopy():

import copy
will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.deepcopy(will)
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]

模块循环依赖

在Python中使用import导入模块的时候,有的时候会产生模块循环依赖,例如下面的例子,module_x模块和module_y模块相互依赖,运行module_y.py的时候就会产生错误。

# module_x.py
import module_y
     
def inc_count():
    module_y.count += 1
    print module_y.count
     
     
# module_y.py
import module_x
count = 10
def run():
    module_x.inc_count()
     
run()

       

其实,在编码的过程中就应当避免循环依赖的情况,或者代码重构的过程中消除循环依赖。


当然,上面的问题也是可以解决的,常用的解决办法就是把引用关系搞清楚,让某个模块在真正需要的时候再导入(一般放到函数里面)。


对于上面的例子,就可以把module_x.py修改为如下形式,在函数内部导入module_y:

# module_x.py
def inc_count():
    import module_y
    module_y.count += 1

   


성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
파이썬 어레이에 어떤 데이터 유형을 저장할 수 있습니까?파이썬 어레이에 어떤 데이터 유형을 저장할 수 있습니까?Apr 27, 2025 am 12:11 AM

PythonlistsCanstoreAnyDatAtype, ArrayModuLearRaysStoreOneType 및 NUMPYARRAYSAREFORNUMERICALPUTATION.1) LISTSAREVERSATILEBUTLESSMEMORY-EFFICENT.2) ARRAYMODUERRAYRAYRAYSARRYSARESARESARESARESARESARESAREDOREDORY-UNFICEDONOUNEOUSDATA.3) NumpyArraysUraysOrcepperperperperperperperperperperperperperperperferperferperferferpercient

파이썬 어레이에 잘못된 데이터 유형의 값을 저장하려고하면 어떻게됩니까?파이썬 어레이에 잘못된 데이터 유형의 값을 저장하려고하면 어떻게됩니까?Apr 27, 2025 am 12:10 AM

whenyouattempttoreavalueofthewrongdatatypeinapythonaphonarray, thisiSdueTotheArrayModule의 stricttyPeenforcement, theAllElementStobeofthesAmetypecified bythetypecode.forperformancersassion, arraysaremoreficats the thraysaremoreficats thetheperfication the thraysaremorefications는

Python Standard Library의 일부는 무엇입니까? 목록 또는 배열은 무엇입니까?Python Standard Library의 일부는 무엇입니까? 목록 또는 배열은 무엇입니까?Apr 27, 2025 am 12:03 AM

Pythonlistsarepartoftsandardlardlibrary, whileraysarenot.listsarebuilt-in, 다재다능하고, 수집 할 수있는 반면, arraysarreprovidedByTearRaymoduledlesscommonlyusedDuetolimitedFunctionality.

스크립트가 잘못된 파이썬 버전으로 실행되는지 확인해야합니까?스크립트가 잘못된 파이썬 버전으로 실행되는지 확인해야합니까?Apr 27, 2025 am 12:01 AM

thescriptIsrunningwithHongpyThonversionDueCorRectDefaultTerpretersEttings.tofixThis : 1) checktheDefaultPyThonVersionUsingPyThon-VersionorPyThon3- version.2) usvirtual-ErondmentsBythePython.9-Mvenvmyenv, 활성화, 및 파괴

파이썬 어레이에서 수행 할 수있는 일반적인 작업은 무엇입니까?파이썬 어레이에서 수행 할 수있는 일반적인 작업은 무엇입니까?Apr 26, 2025 am 12:22 AM

PythonArraysSupportVariousOperations : 1) SlicingExtractsSubsets, 2) 추가/확장 어드먼트, 3) 삽입 값 삽입 ATSpecificPositions, 4) retingdeletesElements, 5) 분류/ReversingChangesOrder 및 6) ListsompectionScreateNewListSbasedOnsistin

어떤 유형의 응용 프로그램에서 Numpy Array가 일반적으로 사용됩니까?어떤 유형의 응용 프로그램에서 Numpy Array가 일반적으로 사용됩니까?Apr 26, 2025 am 12:13 AM

NumpyArraysareSentialplosplicationSefficationSefficientNumericalcomputationsanddatamanipulation. Theyarcrucialindatascience, MachineLearning, Physics, Engineering 및 Financeduetotheiribility에 대한 handlarge-scaledataefficivally. forexample, Infinancialanyaly

파이썬의 목록 위의 배열을 언제 사용 하시겠습니까?파이썬의 목록 위의 배열을 언제 사용 하시겠습니까?Apr 26, 2025 am 12:12 AM

UseanArray.ArrayOveralistInpyThonWhendealingwithhomogeneousData, Performance-CriticalCode, OrinterFacingwithCcode.1) HomogeneousData : ArraysSaveMemorywithtypepletement.2) Performance-CriticalCode : arraysofferbetterporcomanceFornumericalOperations.3) Interf

모든 목록 작업은 배열에 의해 지원됩니까? 왜 또는 왜 그렇지 않습니까?모든 목록 작업은 배열에 의해 지원됩니까? 왜 또는 왜 그렇지 않습니까?Apr 26, 2025 am 12:05 AM

아니요, NOTALLLISTOPERATIONARESUPPORTEDBYARRARES, andVICEVERSA.1) ArraySDONOTSUPPORTDYNAMICOPERATIONSLIKEPENDORINSERTWITHUTRESIGING, WHITHIMPACTSPERFORMANCE.2) ListSDONOTEECONSTANTTIMECOMPLEXITEFORDITITICCESSLIKEARRAYSDO.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

mPDF

mPDF

mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

VSCode Windows 64비트 다운로드

VSCode Windows 64비트 다운로드

Microsoft에서 출시한 강력한 무료 IDE 편집기

Atom Editor Mac 버전 다운로드

Atom Editor Mac 버전 다운로드

가장 인기 있는 오픈 소스 편집기

안전한 시험 브라우저

안전한 시험 브라우저

안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.