초보자가 Python 언어를 처음 배우기 시작하면 이런저런 실수를 하게 됩니다. 이제 막 Python을 배우기 시작한 친구들에게 관심을 주고자 여기에 몇 가지 요약을 만들었습니다.
문법 오류
문법 오류는 아마도 Python을 배울 때 저지르는 가장 흔한 실수일 것입니다.
>>> while True print "hi~" File "<stdin>", line 1 while True print "hi~" ^ SyntaxError: invalid syntax
거기 화살표는 오류가 처음 발견된 곳을 가리킵니다. 여기서는 화요일 이후에 콜론
이 누락되었기 때문에 if, elif, else, for, while 끝에 추가하는 것을 잊었습니다. , class, def 문: ("SyntaxError: 잘못된 구문" 발생) 이 오류는 다음과 유사한 코드에서 발생합니다:
if spam == 42 print('Hello!')
== 대신 = 사용("SyntaxError: 잘못된 구문" 발생) =는 할당 연산자이고 ==는 동등 비교 연산입니다. 다음 코드에서 오류가 발생합니다.
if spam = 42: print('Hello!')
들여쓰기를 잘못 사용했습니다. ("IndentationError: 예기치 않은 들여쓰기", "IndentationError: unindent가 외부 들여쓰기 수준과 일치하지 않습니다" 및 "IndentationError: 들여쓰기된 블록이 필요함"이 발생함) 들여쓰기 증가는 다음으로 끝나는 문 후에만 사용되며 복원되어야 함을 기억하십시오. 이후에는 이전 들여쓰기 형식으로 변경됩니다. 이 오류는 다음 코드에서 발생합니다.
print('Hello!') print('Howdy!')
또는
if spam == 42: print('Hello!') print('Howdy!')
또는
if spam == 42: print('Hello!')
for 루프 문에서 len()을 호출하는 것을 잊어버렸습니다("TypeError: '목록' 개체는 정수로 해석될 수 없습니다.") 일반적으로 목록이나 문자열의 요소를 인덱스별로 반복하려고 하는데, 이를 위해서는 range() 함수를 호출해야 합니다. 목록 대신 len 값을 반환하는 것을 기억하세요. 다음 코드에서 오류가 발생합니다.
spam = ['cat', 'dog', 'mouse'] for i in range(spam): print(spam[i])
문자열 값을 수정하려고 합니다("TypeError: 'str' 개체가 항목 할당을 지원하지 않습니다." 발생). string은 다음과 같습니다. an available 다음 코드에서 오류가 발생합니다:
spam = 'I have a pet cat.' spam[13] = 'r' print(spam)
그리고 실제로 이 작업을 수행하려는 경우:
spam = 'I have a pet cat.' spam = spam[:13] + 'r' + spam[14:] print(spam)
비에 연결해 보십시오. - 문자열 값 대 문자열("TypeError: 'int' 객체를 암시적으로 str로 변환할 수 없습니다." 발생) 실제로 수행하려는 경우
numEggs = 12 print('I have ' + numEggs + ' eggs.')
와 같은 코드에서 오류가 발생합니다. 이:
numEggs = 12 print('I have ' + str(numEggs) + ' eggs.')
또는:
numEggs = 12 print('I have %s eggs.' % (numEggs))
문자열의 시작과 끝에 따옴표를 추가하는 것을 잊었습니다("SyntaxError: EOL while scanning string literal"이 발생함). 다음 코드:
print(Hello!') 或者: print('Hello!)
또는:
myName = 'Al' print('My name is ' + myName + . How are you?')
변수 또는 함수 이름의 철자가 잘못되었습니다("NameError: 이름 'fooba'가 정의되지 않았습니다."). 이 오류는 다음 코드에서 발생합니다. :
foobar = 'Al' print('My name is ' + fooba)
또는
spam = ruond(4.2)
또는
spam = Round(4.2)
메서드 이름의 철자가 잘못되었습니다(결과적으로 "AttributeError: 'str' 개체에 'lowerr' 속성이 없습니다.") 이 오류는 다음 코드에서 발생합니다:
spam = 'THIS IS IN LOWERCASE.' spam = spam.lowerr()
Exception
문과 표현식 구문이 정확하더라도 실행 중에 오류가 발생할 수 있는데, 이를 예외라고 합니다. 예외가 항상 치명적인 것은 아닙니다. 잠시 후에 예외를 처리하는 방법을 배우게 됩니다. 많은 예외 루틴은 이를 처리하지 않고 대신 오류 메시지를 반환합니다. 예:
>>> 10 * (1/0) Traceback (most recent call last): File "<stdin>", line 1, in <module>ZeroDivisionError: integer division or modulo by zero >>> 4 + git*3 Traceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name 'git' is not defined >>> '2' + 1 Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: cannot concatenate 'str' and 'int' objects >>>
错误消息的最后一行就是异常消息,冒号前是异常的类型。上面的 ZeroDivisionError, NameError, TypeError, 都是系统内置的异常。
处理异常
可以自己编写程序来处理异常,比如下面这个例子,它会返回异常,直到用户输入有效数据为止。
>>> while True: ... try: ... x = int(raw_input("Please enter a number: ")) ... break... except ValueError: ... print "Oops! That was no valid number. Try again..."... Please enter a number: x Oops! That was no valid number. Try again... Please enter a number: 32x Oops! That was no valid number. Try again... Please enter a number: 038
使用 try 和 except ExceptionName 来处理异常
如果没有异常产生,except 段会被跳过
如果某处有异常产生,后面的语句会被跳过,如果产生的异常类型和except后的类型一致,except后的语句会被执行
如果发生异常,但和except后的类型不一致,异常会传递到try语句外面,如果没有相应处理,那么就会打印出像上 一个例子那样的信息。
一个try语句可能有多个except与之对应,分别处理不同类型的异常,最多只有一种处理会被执行。一个except可以包含多 个类型名,比如:
... except (RuntimeError, TypeError, NameError): ... pass
注意上面的三种异常类型,必须用括号把它们括起来,因为在现代python中, except ValueError, e 的意思是 except ValueError as e:(后面会讲这是什么意思)
最后一个except一般不指定名字,用于处理其余情况
import systry: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except IOError as e: print "I/O error({0}): {1}".format(e.errno, e.strerror) except ValueError: print "Could not convert data to an integer." except: print "Unexpected error:", sys.exc_info()[0] raise
try..except 语句还可以选择使用else,例如
for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close()
需要注意,一旦使用else,每个except后都要有else,这种方式用于需要指定某一异常不出现时执行什么操作。
except子句可以在异常名后指定参数,这些参数被存储在异常实例产生时的 instance.arg
>>> try: ... raise Exception('spam', 'eggs') ... except Exception as inst: ... print type(inst) ... print inst.args ... print inst ... x, y = inst.args ... print 'x =', x ... print 'y =', y ... <type 'exceptions.Exception'> ('spam', 'eggs') ('spam', 'eggs') x = spam y = eggs
异常处理不仅仅处理直接在try中出现的异常,还可以处理在try中调用函数的异常
>>> def mdiv(): ... x = 1/0 ... >>> try: ... mdiv() ... except ZeroDivisionError as detail: ... print 'Handling run-time error:', detail ... Handling run-time error: integer division or modulo by zero
用户自定义异常
程序可以通过创建一个异常类来命令一个新的异常,这个异常类需要通过直接或者间接的方式由 Exception 类派生。
>>> class MyError(Exception): ... def __init__(self, value): ... self.value = value ... def __str__(self): ... return repr(self.value) ... >>> try: ... raise MyError(1+5) ... except MyError as e: ... print 'My exception occurred, value:', e.value ... My exception occurred, value: 6 >>> raise MyError('oops!') Traceback (most recent call last): File "<stdin>", line 1, in <module> __main__.MyError: 'oops!'
在上面的例子中,__ init __ (), 覆盖了默认的 init 函数,新的行为创建了 value 属性, 替换了原有的 创建args属性的行为。
其它类可以做的事情,通过定义Exception类都可以完成。但是Exception类总是被设计地非常简单, 它们提供一些属性,这样错误处理时就可能方便地提取出这些属性。 当设计一个模块处理多种异常时,常常先定义一个基本的类,其它类在此基础上处理一些特殊情况。
class Error(Exception): """Base class for exceptions in this module.""" pass class InputError(Error): """Exception raised for errors in the input. Attributes: expr -- input expression in which the error occurred msg -- explanation of the error """ def __init__(self, expr, msg): self.expr = expr self.msg = msg class TransitionError(Error): """Raised when an operation attempts a state transition that's not allowed. Attributes: prev -- state at beginning of transition next -- attempted new state msg -- explanation of why the specific transition is not allowed """ def __init__(self, prev, next, msg): self.prev = prev self.next = next self.msg = msg
在定义局部变量前在函数中使用局部变量
(此时有与局部变量同名的全局变量存在)(导致“UnboundLocalError: local variable 'foobar' referenced before assignment”) 在函数中使用局部变来那个而同时又存在同名全局变量时是很复杂的,使用规则是:如果在函数中定义了任何东西,如果它只是在函数中使用那它就是局部的,反之就是全局变量。 这意味着你不能在定义它之前把它当全局变量在函数中使用。 该错误发生在如下代码中:
someVar = 42 def myFunction(): print(someVar) someVar = 100 myFunction()
尝试使用 range()创建整数列表
(导致“TypeError: 'range' object does not support item assignment”) 有时你想要得到一个有序的整数列表,所以 range() 看上去是生成此列表的不错方式。然而,你需要记住 range() 返回的是 “range object”,而不是实际的 list 值。 该错误发生在如下代码中:
spam = range(10) spam[4] = -1
也许这才是你想做:
spam = list(range(10)) spam[4] = -1
(注意:在 Python 2 中 spam = range(10) 是能行的,因为在 Python 2 中 range() 返回的是list值,但是在 Python 3 中就会产生以上错误)
错在 ++ 或者 -- 自增自减操作符。
(导致“SyntaxError: invalid syntax”) 如果你习惯于例如 C++ , Java , PHP 等其他的语言,也许你会想要尝试使用 ++ 或者 -- 自增自减一个变量。在Python中是没有这样的操作符的。 该错误发生在如下代码中:
spam = 1 spam++
也许这才是你想做的:
spam = 1 spam += 1
忘记为方法的第一个参数添加self参数
(导致“TypeError: myMethod() takes no arguments (1 given)”) 该错误发生在如下代码中:
class Foo(): def myMethod(): print('Hello!') a = Foo() a.myMethod()