5장 파이썬 날개 달기¶
5-1 클래스¶
클래스는 왜 필요한가?¶
result = 0
def add(num):
global result
result += num
return result
print(add(3))
print(add(4))
3 7
result1 = 0
result2 = 0
#계산기1
def add1(num):
global result1
result1 += num
return result1
#계산기2
def add2(num):
global result2
result2 += num
return result2
print(add1(3))
print(add1(4))
print(add2(3))
print(add2(7))
3 7 3 10
#클래스 사용
class Calculator:
def __init__(self):
self.result = 0
def add(self, num):
self.result += num
return self.result
#빼기 기능 추가
def sub(self, num):
self.result -= num
return self.result
cal1 = Calculator()
cal2 = Calculator()
print(cal1.add(3))
print(cal1.add(4))
print(cal2.add(3))
print(cal2.add(7))
3 7 3 10
클래스와 객체¶
class Cookie:
pass
a=Cookie()
b=Cookie()
사칙연산 클래스 만들기¶
클래스 구조 만들기¶
class FourCal:
pass
a = FourCal()
type(a) # a는 FourCal클래스의 객체
__main__.FourCal
객체에 숫자 지정할 수 있게 만들기¶
class FourCal:
def setdata(self, first, second): # 1. 메서드의 매개변수
self.first = first
self.second = second #2.매서드의 수행문(first, second)
1. setdata 메서드의 매개변수¶
a = FourCal()
# 메서드의 첫 번째 매개변수 self에는 setdata메서드를 호출한 객체 a가 자동으로 전달되기 때문에 first,second만 넣어주면 된다.
a.setdata(4,2)
메서드의 또 다른 호출 방법¶
# '클래스 이름.메서드' : 객체 a를 첫 번째 매개변수 self에 꼭 전달
a = FourCal()
FourCal.setdata(a,4,2)
# '객체.메서드' : self를 반드시 생략해서 호출
a = FourCal()
a.setdata(4,2)
2. setdata 메서드의 수행문¶
def setdata(self, first, second):
self.first = first
self.second = second #메서드의 수행문 (first, second)
a.setdata(4,2)호출하면
first, second에는 각각 값 4와 2가 전달되어
setdata 메서드의 수행문은 다음과 같이 해석
self.first = 4
self.second = 2
self는 전달된 객체 a이므로 다시 다음과 같이 해석
a.first = 4
a.second = 2
- a.first = 4 문장 수행 -> a 객체에 객체변수 first 생성 -> 값 4 저장
- a.second = 2 문장 수행 -> a 객체에 객체변수 second 생성 -> 값 2 저장
a = FourCal()
a.setdata(4,2)
print(a.first)
4
print(a.second)
2
#a,b 객체 만들기
a = FourCal()
b = FourCal()
#a객체의 객체변수 first 생성
a.setdata(4,2)
print(a.first)
4
#b객체의 객체변수 first 생성
b.setdata(3,7)
print(b.first)
3
# a 객체의 first 값은 b 객체의 first값에 영향받지 않고 원래 값 유지
print(a.first)
4
- 클래스로 만든 객체의 객체변수는 다른 객체의 객체변수와 상관없이 독립적인 값 유지!!
# 지금까지 완성된 FourCal 클래스
class FourCal:
def setdata(self, first, second):
self.first = first
self.second = second
더하기 기능 만들기¶
class FourCal:
def setdata(self, first, second):
self.first = first
self.second = second
def add(self):
result = self.first + self.second
return result
a = FourCal()
a.setdata(4,2)
# add 메서드 호출
print(a.add())
6
- add 메서드 자세히 살펴보기
def add(self):
result = self.first + self.second
return result
# add 메서드의 매개변수는 self, 반환 값은 result
# 반환 값인 result를 계산하는 부분
result = self.first + self.second
# a.add()와 같이 a 객체에 의해 add 메서드가 수행되면 add메서드의 self에는 객체 a가 자동입력되므로 위 내용은 다음과 같이 해석
result = a.first + a.second
# 위 내용은 a.add() 메서드 호출 전 a.setdata(4,2)가 먼저 호출되어
# a.first = 4, a.second = 2라고 미리 설정되었기에 다음과 같이 해석
result = 4 + 2
print(a.add())
6
곱하기, 빼기 ,나누기 기능 만들기¶
class FourCal:
def setdata(self, first, second):
self.first = first
self.second = second
def add(self):
result = self.first + self.second
return result
def mul(self):
result = self.first * self.second
return result
def sub(self):
result = self.first - self.second
return result
def div(self):
result = self.first / self.second
return result
a = FourCal()
b = FourCal()
a.setdata(4,2)
b.setdata(3,8)
a.add()
6
a.mul()
8
a.sub()
2
a.div()
2.0
b.add()
11
b.mul()
24
b.sub()
-5
b.div()
0.375
생성자(Constructor)¶
a = FourCal()
a.add() # FourCal 클래스의 인스턴스 a에 setdata 메서드를 수행하지 않고 add 메서드를 수행하면 오류 발생
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) Cell In[67], line 1 ----> 1 a.add() # FourCal 클래스의 인스턴스 a에 setdata 메서드를 수행하지 않고 add 메서드를 수행하면 오류 발생 Cell In[51], line 6, in FourCal.add(self) 5 def add(self): ----> 6 result = self.first + self.second 7 return result AttributeError: 'FourCal' object has no attribute 'first'
- 이렇게 객체에 초깃값을 설정해야 할 필요가 있을 때 : setdata 메서드 호출보다는 '생성자 구현'이 안전!!
- 생성자(Constructor) : 객체가 생성될 때 자동으로 호출되는 메서드
- 파이썬 메서드 이름으로 init을 사용하면 이 메서드는 생성자가 된다.
#FourCal 클래스에 생성자 추가
class FourCal:
def __init__(self, first, second):
self.first = first
self.second = second
def setdata(self, first, second):
self.first = first
self.second = second
def add(self):
result = self.first + self.second
return result
def mul(self):
result = self.first * self.second
return result
def sub(self):
result = self.first - self.second
return result
def div(self):
result = self.first / self.second
return result
# 새롭게 추가된 생성자 __init__ 메서드만 따로 떼어 내서 살펴보기
def __init__(self, first, second):
self.first = first
self.second = second
- init 메서드는 setdata 메서드와 이름만 다르고 모든 게 동일.
- 단 메서드 이름을 init으로 했기 때문에 생성자로 인식되어 객체가 생성되는 시점에 자동으로 호출되는 차이
# 생성자 first와 second에 해당하는 값이 전달되지 않아 오류 발생
a = FourCal()
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[76], line 2 1 # 생성자 first와 second에 해당하는 값이 전달되지 않아 오류 발생 ----> 2 a = FourCal() TypeError: FourCal.__init__() missing 2 required positional arguments: 'first' and 'second'
a = FourCal(4,2)
a = FourCal(4,2)
print(a.first)
4
print(a.second)
2
a = FourCal(4,2)
a.add()
6
a.div()
2.0
클래스의 상속¶
- class 클래스 이름(상속할 클래스 이름)
class MoreFourCal(FourCal):
pass
a = MoreFourCal(4,2)
a.add()
6
a = MoreFourCal(4,2)
- MoreFourCal 클래스는 FourCal 클래스를 상속했으므로 FourCal 클래스의 모든 기능 사용 가능
a.add()
6
a.mul()
8
a.sub()
2
a.div()
2.0
class MoreFourCal(FourCal):
def pow(self):
result = self.first ** self.second
return result
a = MoreFourCal(4,2)
a.pow()
16
메서드 오버라이딩(Overriding, 덮어쓰기)¶
- 부모 클래스(상속한 클래스)에 있는 메서드를 동일한 이름으로 다시 만드는 것
a = FourCal(4,0)
a.div() #4를 0으로 나누려고 해서 오류 발생
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) Cell In[100], line 1 ----> 1 a.div() Cell In[73], line 19, in FourCal.div(self) 18 def div(self): ---> 19 result = self.first / self.second 20 return result ZeroDivisionError: division by zero
class SafeFourCal(FourCal):
def div(self):
if self.second == 0: # 나누는 값이 0인 경우 숫자 0을 돌려주도록 수정
return 0
else:
return self.first/ self.second
a = SafeFourCal(4,0)
a.div()
0
#### 상속과 변수 (super())
https://supermemi.tistory.com/178
Cell In[1], line 2 https://supermemi.tistory.com/178 ^ SyntaxError: invalid syntax
상속 super()¶
#예시
class Nintendo:
def __init__(self,name, character):
self.country='Japan'
self.game_name=name
self.character=character
class New(Nintendo):
def __init__(self,name,character,genre,income):
super().__init__(name,character)
self.ceo='Shigeru Miyamoto'
self.genre=genre
self.income=income
p1 = New("simono", "warm", "mystery", 100)
print(p1.country, p1.game_name, p1.ceo, p1.income)
Japan simono Shigeru Miyamoto 100
클래스 변수¶
- 클래스이름.클래스변수
class Family:
lastname = "김" # 클래스 변수
print(Family.lastname)
김
a = Family()
b = Family()
print(a.lastname)
김
print(b.lastname)
김
- 클래스 변수 값을 변경하면 클래스로 만든 객체의 lastname 값도 모두 변경된다 = 클래스 변수는 클래스로 만든 모든 객체에 공유된다
Family.lastname = "박" #Family.lastname 수정하면?
print(a.lastname)
박
print(b.lastname)
박
클래스 변수와 객체 변수¶
- a.lastname을 변경하면?
a.lastname = "최"
print(a.lastname)
최
- 이렇게 하면 Family클래스의 lastname이 바뀌는 것이 아니라 a 객체에 lastname이라는 객체변수가 새롭게 생성
- 즉, 객체변수는 클래스 변수와 동일한 이름으로 생성 가능
- 이제부터 a.lastname은 Family클래스의 lastname이 아닌 객체 a의 객체변수 lastname을 가리킴
- a.lastname의 객체변수를 생성하더라도 Family 클래스의 lastname과는 상관이 없다
print(Family.lastname)
박
print(b.lastname)
박
- Family 클래스의 lastname 값은 변하지 않았다
5-2 모듈¶
- 함수나 변수 또는 클래스를 모아 놓은 파일
- 다른 파이썬 프로그램에서 불러와 사용할 수 있게끔 만든 파이썬 파일
모듈 만들기¶
#mod1.py
def add(a,b):
return a+b
def sub(a,b):
return a-b
파이썬 확장자 .py로 만든 파이썬 파일은 모두 모듈이다.
모듈 불러오기¶
- 모듈 실행 방법
C:\Users\user>cd doit # mod1.py 저장한 디렉터리로 이동
C:\Users\user\doit>dir # C:\Users\user\doit 디렉터리에 파일이 있는지 확인
2023-03-21 오후 06:50 58 mod1.py
C:\Users\user\doit>python # 대화형 인터프리터 실행
반드시 mod1.py를 저장한 C:\Users\user\doit 디렉터리로 이동한 다음 예제 진행.
그래야만 대화형 인터프리터에서 mod1.py를 읽을 수 있다.
>>> import mod1
>>> print(mod1.add(3,4))
7
>>> print(mod1.sub(4,2))
2
mod1.py를 불러오기 위해 import mod1이라고 입력.
실수로 import mod1.py로 입력하지 않도록 주의!!
- import : 이미 만들어 놓은 파이썬 모듈을 사용할 수 있게 해주는 명령어
- mod1.py 파일에 있는 add 함수를 사용하기 위해서는 위 예와 같이 mod1.add처럼 모듈 이름 뒤에 '.'(도트 연산자)를 붙이고 함수 이름을 쓰면 된다.
- import 사용방법
import 모듈 이름
여기서 모듈 이름은 mod1.py에서 .py 확장자를 제거한 mod1만을 가리킴
- mod1.add, mod1.sub 처럼 쓰지 않고 add,sub 처럼 모듈 이름 없이 함수 이름만 쓰고 싶은 경우
from 모듈 이름 import 모듈 함수
위 형식을 사용하면 모듈 이름을 붙이지 않고 바로 해당 모듈의 함수를 쓸 수 있다.
>>> from mod1 import add
>>> add(3,4)
7
위와 같이 하면 add 함수만 사용 가능
add 함수와 sub 함수 둘 다 사용하고 싶다면?
- 2가지 방법
from mod1 import add, sub
from mod1 import *
ifname == "main__": 의 의미¶
mod1.py 파일을 다음과 같이 변경하자.
#mod1.py
def add(a,b):
return a+b
def sub(a,b):
return a-b
# ----- 추가 -----
print(add(1,4))
print(sub(4,2))
- 실행 결과
C:\Users\user\doit>python mod1.py
5
2
- mod1.py 파일의 add와 sub 함수를 사용하기 위해 mod1 모듈을 import할 때 문제 생김
C:\Users\user\doit>python
Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec 6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import mod1
5
2
import mod1을 수행하는 순간 mod1.py가 실행되어 결괏값 출력.
우리는 단지 add와 sub 함수만 사용하려고 했는데 말이다.
이런 문제를 방지하려면 mod1.py 파일을 다음처럼 변경
#mod1.py
def add(a,b):
return a+b
def sub(a,b):
return a-b
# 바뀐 코드
if __name__ == "__main__":
print(add(1,4))
print(sub(4,2))
if __name__ == "__main__"
을 사용하면
- C:\Users\user\doit>python mod1.py처럼 직접 이 파일을 실행할 경우 :
if __name__ == "__main__"
이 참이 되어 if 다음 문장 수행 - 대화형 인터프리터나 다른 파일에서 이 모듈을 불러서 사용할 경우 :
if __name__ == "__main__"
이 거짓이 되어 if 다음 문장 수행 X
- 위와 같이 수정 후 다시 실행
>>> import mod1
>>>
아무 결괏값도 출력되지 않는다.
__name__
변수란?¶
파이썬의 __name__
변수는 파이썬이 내부적으로 사용하는 특별한 변수 이름
- C:\Users\user\doit>python mod1.py처럼 직접 이 파일을 실행할 경우 : mod1.py의
__name__
변수에는__main__
값이 저장 - 파이썬 셸이나 다른 파이썬 모듈에서 mod1을 import할 경우 : mod1.py의
__name__
변수에는 mod1.py의 모듈 이름 값 mod1이 저장
클래스나 변수 등을 포함한 모듈¶
- 지금까지 살펴본 모듈은 함수만 포함했지만 클래스나 변수 등을 포함할 수도 있다.
# mod2.py
PI = 3.141592
class Math:
def solv(self, r):
return PI * (r**2)
def add(a,b):
return a+b
- 클래스 : 원의 넓이를 계산하는 Math 클래스
- 함수 : 두 값을 더하는 add 함수
- 변수 : 원주율 값에 해당되는 PI 변수
- mod2.PI처럼 입력해서 mod2.py 파일에 있는 PI 변수 값 사용 가능
C:\Users\user\doit>python
Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec 6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import mod2
>>> print(mod2.PI)
3.141592
- mode2.py에 있는 Math 클래스 사용하기
>>> a =mod2.Math()
>>> print(a.solv(2))
12.566368
모듈 안에 클래스를 사용하려면 '.'(도트 연산자)로 클래스 이름 앞에 모듈 이름 먼저 입력
- mode2.py에 있는 add 함수 사용하기
>>> print(mod2.add(mod2.PI, 4.4))
7.5415920000000005
다른 파일에서 모듈 불러오기¶
지금까지는 만들어 놓은 모듈 파일을 사용하기 위해 대화형 인터프리터만 사용
이번에는 다른 파이썬 파일에서 이전에 만들어 놓은 모듈을 불러와서 사용
- mod2.py 파일을 다른 파이썬 파일에서 불러와 사용하기
# modtest.py
import mod2
result = mod2.add(3,4)
print(result)
C:\Users\user\doit>python modtest.py
7
결과 정상적으로 출력
모듈을 불러오는 또 다른 방법¶
우리는 지금껏 명령 프롬프트 창을 열고 모듈이 있는 디렉터리로 이동 후 모듈을 사용할 수 있었다.
이번에는 모듈을 저장한 디렉터리로 이동하지 않고 모듈을 불러와 사용하는 방법에 대해 알아보자.
5-3 패키지¶
- 다음에 정리
5-4 예외 처리¶
오류는 어떨 때 발생?¶
- 디렉터리 안에 없는 파일을 열려고 시도
f = open("나없는파일", 'r')
--------------------------------------------------------------------------- FileNotFoundError Traceback (most recent call last) Cell In[4], line 1 ----> 1 f = open("나없는파일", 'r') File ~\AppData\Local\Programs\Python\Python310\lib\site-packages\IPython\core\interactiveshell.py:282, in _modified_open(file, *args, **kwargs) 275 if file in {0, 1, 2}: 276 raise ValueError( 277 f"IPython won't let you open fd={file} by default " 278 "as it is likely to crash IPython. If you know what you are doing, " 279 "you can use builtins' open." 280 ) --> 282 return io_open(file, *args, **kwargs) FileNotFoundError: [Errno 2] No such file or directory: '나없는파일'
FileNotFoundError 오류 발생
- 0으로 다른 숫자를 나누는 경우
4/0
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) Cell In[6], line 1 ----> 1 4/0 ZeroDivisionError: division by zero
4를 0으로 나누려니까 ZeroDivisionError 오류 발생
a = [1,2,3]
a[4]
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) Cell In[9], line 1 ----> 1 a[4] IndexError: list index out of range
IndexError 오류 발생
오류 예외 처리 기법¶
try, except문¶
- 기본 구조
try:
...
except [발생 오류[as 오류 메시지 변수]]:
...
- try 블록 수행 중 오류 발생 : except 블록 수행
- try 블록 수행 중 오류 발생X : except 블록 수행되지 X
- except 구문
except [발생 오류 [as 오류 메시지 변수]]:
[]
기호 : 괄호 안의 내용을 생략할 수 있다는 관례 표기법
except 구문을 사용하는 3가지 방법¶
1. try, except만 쓰는 방법¶
오류 종류에 상관없이 오류 발생하면 except 블록 수행
try:
...
except:
...
2. 발생 오류만 포함한 except문¶
오류 발생 시 except문에 미리 정해 놓은 오류 이름과 일치할 때만 except 블록 수행
try:
...
except 발생 오류:
...
3. 발생 오류와 오류 메시지 변수까지 포함한 except문¶
두 번째 경우에서 오류 메시지의 내용까지 알고 싶을 때 사용
try:
...
except 발생 오류 as 오류 메시지 변수:
...
try:
4/0
except ZeroDivisionError as e:
print(e)
division by zero
위처럼 4를 0으로 나누려고 하면 ZeroDivisionError가 발생해 except 블록이 실행되고 변수 e에 담기는 오류 메시지를 출력(division by zero)
- 나코딩
try:
a = [1,2,3]
a[4]
except IndexError as e:
print(e)
list index out of range
try ... finally¶
- finally절은 try문 수행 도중 예외 발생 여부에 상관없이 항상 수행
- 보통 finally절은 사용한 리소스를 close해야 할 때 많이 사용
f = open('foo.txt', 'w')
try:
#무언가 수행
finally:
f.close()
Cell In[15], line 4 finally: ^ IndentationError: expected an indented block after 'try' statement on line 2
foo.txt 파일을 쓰기 모드로 연 후 try문을 수행 후 예외 발생 여부와 상관없이 finally절에서 f.close()로 열린 파일 닫기 가능
여러 개의 오류 처리하기¶
- 구문
try:
...
except 발생 오류 1:
...
except 발생 오류 2:
...
try:
a = [1,2]
print(a[3])
4/0
except ZeroDivisionError:
print("0으로 나눌 수 없습니다.")
except IndexError:
print("인덱싱할 수 없습니다.")
인덱싱할 수 없습니다.
인덱싱 오류가 먼저 발생했으므로 4/0으로 발생되는 ZeroDivisionError 오류는 발생되지 않았다.
- 오류 메시지도 가져오기
try:
a = [1,2]
print(a[3])
4/0
except ZeroDivisionError as e:
print(e)
except IndexError as e:
print(e)
list index out of range
- ZeroDivisionError와 IndexError 함께 처리
try:
a = [1,2]
print(a[3])
4/0
except (ZeroDivisionError, IndexError) as e:
print(e)
list index out of range
2개 이상의 오류를 동시에 처리하기 위해서는 위와 같이 괄호를 사용해 함께 묶어 처리
오류 회피하기¶
try:
f = open("나없는파일", 'r')
except FileNotFoundError: # 파일이 없더라도 오류를 발생시키지 않고 통과
pass
오류 일부러 발생시키기(raise)¶
- raise 명령어를 사용해 오류를 강제로 발생시킬 수 있다.
- Bird 클래스를 상속받는 자식 클래스는 반드시 fly라는 함수를 구현하도록 만들고 싶은 경우(강제로 그렇게 하고 싶은 경우)
class Bird:
def fly(self):
raise NotImplementedError
- 자식 클래스가 fly 함수를 구현하지 않은 상태로 fly 함수 호출한 경우
class Eagle(Bird): #Eagle 클래스는 Bird 클래스를 상속 받음
pass
eagle = Eagle()
eagle.fly()
--------------------------------------------------------------------------- NotImplementedError Traceback (most recent call last) Cell In[7], line 5 2 pass 4 eagle = Eagle() ----> 5 eagle.fly() Cell In[6], line 3, in Bird.fly(self) 2 def fly(self): ----> 3 raise NotImplementedError NotImplementedError:
Eagle클래스는 Bird클래스를 상속받는다. 그런데 Eagle클래스에서 fly함수를 구현하지 않았기 때문에 Bird 클래스의 fly 함수가 호출된다.
그리고 raise문에 의해 NotImplemented Error 발생
- NotImplementedError가 발생되지 않도록 다음과 같이 Eagle클래스에 fly 함수 반드시 구현
class Eagle(Bird):
def fly(self):
print("very fast")
eagle = Eagle()
eagle.fly()
very fast
예외 만들기¶
- 프로그램 수행 도중 특수한 경우에만 예외 처리를 하기 위해 종종 예외를 만들어서 사용
- 파이썬 내장 클래스인 Exception 클래스를 상속하여 예외를 만들 수 있다
class MyError(Exception):
pass
- 별명 출력해주는 함수 작성
def say_nick(nick):
if nick == '바보':
raise MyError()
print(nick)
say_nick("천사")
천사
say_nick("바보") # MyError 발생
--------------------------------------------------------------------------- MyError Traceback (most recent call last) Cell In[12], line 1 ----> 1 say_nick("바보") Cell In[10], line 3, in say_nick(nick) 1 def say_nick(nick): 2 if nick == '바보': ----> 3 raise MyError() 4 print(nick) MyError:
- 예외 처리 기법을 사용해 MyError 발생을 예외 처리
try:
say_nick("천사")
say_nick("바보")
except MyError:
print("허용되지 않는 별명입니다.")
천사 허용되지 않는 별명입니다.
- 오류 메시지 사용한 예외 처리
try:
say_nick("천사")
say_nick("바보")
except MyError as e:
print(e)
천사
하지만 프로그램을 실행해 보면 print(e)로 오류 메시지가 출력되지 않음.
오류 메시지 출력 시 오류 메시지가 보이게 하려면 오류 클래스에 다음과 같은 str 메서드 구현
str 메서드 : print(e)처럼 오류 메시지를 print문으로 출력할 경우 호출되는 메서드
class MyError(Exception):
def __str__(self):
return "허용되지 않는 별명입니다."
try:
say_nick("천사")
say_nick("바보")
except MyError as e:
print(e)
천사 허용되지 않는 별명입니다.
# total(1,'2'3,4,5,'6')은 13이 출력되도록 total()를 만드시오.
def total(*args):
result = 0
for arg in args:
try:
result += arg
except:
print(f"{arg}는 int가 아닙니다.")
return result
total(1,'2',3,4,5,'6')
2는 int가 아닙니다. 6는 int가 아닙니다.
13
"허용되지 않는 별명입니다." 라는 오류메시지 출력
5-5 내장 함수¶
abs(x)¶
- 어떤 숫자를 입력받았을 때, 그 숫자의 절댓값을 돌려주는 함수
abs(3)
3
abs(-3)
3
abs(-1.2)
1.2
all(x)¶
- 반복 가능한(iterable) 자료형 x를 입력 인수로 받으며 이 x가 모두 참이면 True, 거짓이 하날도 있으면 False를 돌려줌
all([1,2,3])
True
all([1,2,3,0])
False
any(x)¶
- x 중 하나라도 참이 있으면 True를 돌려주고, x가 모두 거짓일 때에만 False를 돌려줌. all(x)의 반대
any([1,2,3,0])
True
any([0,""])
False
chr(i)¶
- 아스키(ASCII) 코드 값을 입력받아 그 코드에 해당하는 문자를 출력하는 함수
chr(97)
'a'
chr(48)
'0'
dir¶
- 객체가 자체적으로 가지고 있는 변수나 함수를 보여줌
- 다음 예는 리스트와 딕셔너리 객체 관련 함수(메서드)를 보여주는 예
dir([1,2,3])
['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
dir({'1':'a'})
['__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__ior__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__ror__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
divmod(a,b)¶
- 2개의 숫자를 입력으로 받으며, a를 b로 나눈 몫과 나머지를 튜플 형태로 돌려줌
divmod(7,3)
(2, 1)
7//3
2
7%3
1
enumerate¶
- '열거하다'라는 뜻. 이 함수는 순서가 있는 자료형(리스트, 튜플, 문자열)을 입력으로 받아 인덱스 값을 포함하는 enumerate 객체를 돌려줌.
- for문과 함께 자주 사용
for i, name in enumerate(['body', 'foo', 'bar']):
print(i, name)
0 body 1 foo 2 bar
위 예제와 같이 enumerate을 for문과 함께 사용하면 자료형의 현재 순서(index)와 그 값을 쉽게 알 수 있다.
for문처럼 반복되는 구간에서 객체가 현재 어느 위치에 있는지 알려 주는 인덱스 값이 필요할 때 enumberate 함수를 사용하면 매우 유용함
eval(expression)¶
- 실행 가능한 문자열(1+2, 'hi'+'a' 같은 것)을 입력으로 받아 문자열을 실행한 결괏값을 돌려주는 함수
eval('1+2')
3
eval("'hi' + 'a'")
'hia'
eval('divmod(4,3)')
(1, 1)
filter¶
- 첫 번째 인수 : 함수 이름
- 두 번째 인수 : 그 함수에 차례로 들어가 반복 가능한 자료형
#filter함수 없이
def positive(l):
result = []
for i in l:
if i > 0:
result.append(i)
return result
print(positive([1,-3,2,0,-5,6]))
[1, 2, 6]
#filter 함수 사용
def positive(x):
return x > 0
print(list(filter(positive, [1,-3,2,0,-5,6])))
[1, 2, 6]
list(filter(lambda x: x>0, [1,-3,2,0,-5,6]))
[1, 2, 6]
hex(x)¶
- 정수 값을 입력받아 16진수(hexadecimal)로 변환하여 돌려주는 함수
hex(234)
'0xea'
hex(3)
'0x3'
id(object)¶
- 객체를 입력받아 객체의 고유 주소 값(레퍼런스)을 돌려주는 함수
a=3
id(3)
2093048332592
b=a
id(b)
2093048332592
- 3, a, b가 모두 같은 객체를 가리킴
id(4) # 다른 고유 주소값
2093048332624
input([prompt])¶
- 사용자 입력을 받는 함수
a = input()
a
'hi'
b = input("Enter: ")
b
'hi'
int(x)¶
- 문자열 형태의 숫자나 소수점이 있는 숫자 등을 정수 형태로 돌려주는 함수
int('3')
3
int(3.4)
3
int(x, radix)¶
- radix 진수로 표현된 문자열 x를 10진수로 변환하여 돌려줌
int('11',2) #2진수로 표현된 11의 10진수 값 구하기
3
int('1A', 16) #16진수로 표현된 1A의 10진수 값 구하기
26
isinstance(object, class)¶
- 첫 번째 인수: 인스턴스 , 두 번째 인수: 클래스 이름
- 입력으로 받은 인스턴스가 그 클래스의 인스턴스인지를 판다하여 참이면 True, 거짓이면 False를 돌려줌
class Person:
pass
a = Person()
isinstance(a, Person) #a가 Person클래스의 인스턴스인지 확인
True
b=3
isinstance(b, Person) #b가 Person클래스의 인스턴스인지 확인
False
len(s)¶
- 입력값 s의 길이(요소의 전체 개수)를 돌려주는 함수
len("python")
6
len([1,2,3])
3
len((1,'a'))
2
list(s)¶
- 반복 가능한 자료형 s를 입력받아 리스트로 만들어 돌려주는 함수
list("python")
['p', 'y', 't', 'h', 'o', 'n']
list((1,2,3))
[1, 2, 3]
- 리스트 함수에 리스트를 입력으로 주면 똑같은 리스트를 복사해 돌려줌
a = [1,2,3]
b = list(a)
b
[1, 2, 3]
map(f, iterable)¶
- 함수(f)와 반복 가능한(iterable) 자료형을 입력으로 받음
- map은 입력받은 자료형의 각 요소를 함수 f가 수행한 결과를 묶어서 돌려주는 함수
#map 사용 전
def two_times(numberList):
result = []
for number in numberList:
result.append(number*2)
return result
result = two_times([1,2,3,4])
print(result)
[2, 4, 6, 8]
#map 사용 후
def two_times(x): return x*2
list(map(two_times, [1,2,3,4]))
[2, 4, 6, 8]
list(map(lambda a:a*2, [1,2,3,4]))
[2, 4, 6, 8]
max(iterable)¶
- 인수로 반복 가능한 자료형을 입력받아 그 최댓값을 돌려주는 함수
max([1,2,3])
3
max("python")
'y'
min(iterable)¶
- max함수와 반대로, 인수로 반복 가능한 자료형을 입력받아 그 최솟값을 돌려주는 함수
min([1,2,3])
1
min("python")
'h'
oct(x)¶
- 정수 형태의 숫자를 8진수 문자열로 바꾸어 돌려주는 함수
oct(34)
'0o42'
oct(12345)
'0o30071'
open(filename, [mode])¶
- '파일 이름'과 '읽기 방법'을 입력받아 파일 객체를 돌려주는 함수
- 읽기 방법(mode)을 생략하면 기본값인 읽기 전용 모드(r)로 파일 객체를 만들어 돌려줌
f = open("binary_file", "rb") #rb는 '바이너리 읽기 모드'
--------------------------------------------------------------------------- FileNotFoundError Traceback (most recent call last) Cell In[53], line 1 ----> 1 f = open("binary_file", "rb") #rb는 '바이너리 읽기 모드' File ~\AppData\Local\Programs\Python\Python310\lib\site-packages\IPython\core\interactiveshell.py:282, in _modified_open(file, *args, **kwargs) 275 if file in {0, 1, 2}: 276 raise ValueError( 277 f"IPython won't let you open fd={file} by default " 278 "as it is likely to crash IPython. If you know what you are doing, " 279 "you can use builtins' open." 280 ) --> 282 return io_open(file, *args, **kwargs) FileNotFoundError: [Errno 2] No such file or directory: 'binary_file'
# fread와 fread2는 동일한 방법
fread = open("read_mode.txt", 'r')
fread2 = open("read_mode.txt")
fappend = open("append_mode.txt", 'a')
ord(c)¶
- 문자의 아스키 코드 값을 돌려주는 함수
ord('a')
97
ord('0')
48
pow¶
- pow(x,y)는 x의 y제곱한 결괏값을 돌려주는 함수
pow(2,4)
16
pow(3,3)
27
range([start,] stop [,step])¶
- for문과 함께 자주 사용
- 입력받은 숫자에 해당하는 범위 값을 반복 가능한 객체로 만들어 돌려줌
인수가 하나일 경우¶
list(range(5))
[0, 1, 2, 3, 4]
인수가 2개일 경우¶
list(range(5,10))
[5, 6, 7, 8, 9]
인수가 3개일 경우¶
list(range(1,10,2))
[1, 3, 5, 7, 9]
list(range(9,-10,-1))
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
round(number[,ndigits])¶
- 숫자를 입력받아 반올림해주는 함수
- round 함수의 두 번째 매개변수는 반올림하여 표시하고 싶은 소수점의 자릿수(ndigits)
round(4.6)
5
round(4.2)
4
round(5.678,2)
5.68
sorted(iterable)¶
- 입력값을 정렬한 후 그 결과를 리스트로 돌려주는 함수
sorted([3,1,2])
[1, 2, 3]
sorted(['a','c','b'])
['a', 'b', 'c']
sorted("zero")
['e', 'o', 'r', 'z']
sorted((3,2,1))
[1, 2, 3]
str(object)¶
- 문자열 형태로 객체를 변환하여 돌려주는 함수
str(3)
'3'
str('hi')
'hi'
str('hi'.upper())
'HI'
sum(iterable)¶
- 입력받은 리스트나 튜플의 모든 요소의 합을 돌려주는 함수
sum([1,2,3])
6
sum([4,5,6])
15
tuple¶
- 반복 가능한 자료형을 입력받아 튜플 형태로 바꾸어 돌려주는 함수
- 만약 튜플이 입력을 들어오면 그대로 돌려줌
tuple("abc")
('a', 'b', 'c')
tuple([1,2,3])
(1, 2, 3)
tuple((1,2,3))
(1, 2, 3)
type(object)¶
- 입력값의 자료형이 무엇인지 알려주는 함수
type("abc")
str
type([])
list
type(open("test", 'w'))
_io.TextIOWrapper
zip(*iterable)¶
- 동일한 개수로 이루어진 자료형을 묶어 주는 역할을 하는 함수
- *iterable : 반복 가능(iter-able)한 자료형 여러 개를 입력할 수 있다는 의미
list(zip([1,2,3], [4,5,6]))
[(1, 4), (2, 5), (3, 6)]
list(zip([1,2,3],[4,5,6],[7,8,9]))
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]
list(zip("abc", "def"))
[('a', 'd'), ('b', 'e'), ('c', 'f')]
5-6 라이브러리¶
sys¶
- 파이썬 인터프리터가 제공하는 변수와 함수를 직접 제어할 수 있게 해주는 모듈
명령 행에서 인수 전달 - sys.argv¶
>> python test.py abc pey guido
명령 프롬프트 창에서 위과 같이 test.py 뒤에 또 다른 값을 함께 넣어주면 sys.argv 리스트에 그 값 추가
- 예제
argv_test.py 파일은 C:/Users/user/Mymod 디렉터리에 저장했다고 가정
#argv_test.py
import sys
print(sys.argv)
명령 프롬프트 창에서 Mymod 디렉토리로 들어간 뒤 다음과 같이 실행
C:/Users/user/Mymod> python argv_test.py you need python
['argv_test.py', 'you', 'need', 'python']
python 명령어 뒤의 모든 것들이 공백을 기준으로 나뉘어서 sys.argv 리스트의 요소가 된다.
강제로 스크립트 종료 - sys.exit¶
>>> sys.exit()
자신이 만든 모듈 불러와 사용 - sys.path¶
- sys.path는 파이썬 모듈들이 저장되어 있는 위치를 나타냄
- 즉, 이 위치에 있는 파이썬 모듈은 경로에 상관없이 어디에서나 불러올 수 있다.
>>> import sys
>>> sys.path
['', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\python310.zip', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\DLLs', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\lib', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\win32', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\win32\\lib', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\Pythonwin']
위 예에서 ''는 현재 디렉터리를 말한다.
#path_append.py
import sys
sys.path.append("C:/Users/user/Mymod")
위와 같이 파이썬 프로그램 파일에서 sys.path.append를 사용해 경로 이름을 추가할 수 있다.
이렇게 하고 난 후에는 C:/Users/user/Mymod 디렉터리에 있는 파이썬 모듈을 불러와서 사용 가능
pickle¶
- 객체의 형태를 그대로 유지하면서 파일에 저장하고 불러올 수 있게 하는 모듈
- pickle 모듈의 dump 함수를 사용해 딕셔너리 객체인 data를 그대로 파일에 저장하는 방법
import pickle
f = open("test.txt", 'wb')
data = {1:'python', 2: 'you need'}
pickle.dump(data, f)
f.close()
- pickle.dump로 저장한 파일을 pickle.load를 사용해서 원래 있던 딕셔너리 객체(data) 상태 그대로 불러오기
import pickle
f = open("test.txt", 'rb')
data = pickle.load(f)
print(data)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100]
위 예에서는 딕셔너리 객체를 사용했지만 어떤 자료형이든 저장하고 불러오기 가능
# 추가
my_list = ["a", "b", "c"]
with open("data.pickle", "wb") as f:
pickle.dump(my_list, f)
import pickle
with open("data2.pickle", "wb") as fw:
pickle.dump(b, fw)
with open('data2.pickle', 'rb') as fr:
df = pickle.load(fr)
print(df)
OS¶
- OS모듈은 환경 변수나 디렉터리, 파일 등의 OS 자원을 제어할 수 있게 해주는 모듈
내 시스템의 환경 변수 값을 알고 싶을 때 - os.environ¶
- 시스템은 제각기 다른 환경 변수 값을 가지고 있는데, os.environ은 현재 시스템의 환경 변수 값을 보여줌.
import os
os.environ
environ{'ALLUSERSPROFILE': 'C:\\ProgramData', 'APPDATA': 'C:\\Users\\user\\AppData\\Roaming', 'COMMONPROGRAMFILES': 'C:\\Program Files\\Common Files', 'COMMONPROGRAMFILES(X86)': 'C:\\Program Files (x86)\\Common Files', 'COMMONPROGRAMW6432': 'C:\\Program Files\\Common Files', 'COMPUTERNAME': 'DESKTOP-2PGRMF4', 'COMSPEC': 'C:\\windows\\system32\\cmd.exe', 'DRIVERDATA': 'C:\\Windows\\System32\\Drivers\\DriverData', 'FPS_BROWSER_APP_PROFILE_STRING': 'Internet Explorer', 'FPS_BROWSER_USER_PROFILE_STRING': 'Default', 'HOMEDRIVE': 'C:', 'HOMEPATH': '\\Users\\user', 'JAVA_HOME': 'C:\\Program Files\\Amazon Corretto\\jdk11.0.18_10', 'LOCALAPPDATA': 'C:\\Users\\user\\AppData\\Local', 'LOGONSERVER': '\\\\DESKTOP-2PGRMF4', 'NUMBER_OF_PROCESSORS': '12', 'ONEDRIVE': 'C:\\Users\\user\\OneDrive', 'OS': 'Windows_NT', 'PATH': 'C:\\Program Files\\Amazon Corretto\\jdk11.0.18_10\\bin;C:\\windows\\system32;C:\\windows;C:\\windows\\System32\\Wbem;C:\\windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\windows\\System32\\OpenSSH\\;C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\Scripts\\;C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\;C:\\Users\\user\\AppData\\Local\\Microsoft\\WindowsApps;', 'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC', 'PROCESSOR_ARCHITECTURE': 'AMD64', 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 167 Stepping 1, GenuineIntel', 'PROCESSOR_LEVEL': '6', 'PROCESSOR_REVISION': 'a701', 'PROGRAMDATA': 'C:\\ProgramData', 'PROGRAMFILES': 'C:\\Program Files', 'PROGRAMFILES(X86)': 'C:\\Program Files (x86)', 'PROGRAMW6432': 'C:\\Program Files', 'PROMPT': '$P$G', 'PSMODULEPATH': 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\windows\\system32\\WindowsPowerShell\\v1.0\\Modules', 'PUBLIC': 'C:\\Users\\Public', 'SESSIONNAME': 'Console', 'SYSTEMDRIVE': 'C:', 'SYSTEMROOT': 'C:\\windows', 'TEMP': 'C:\\Users\\user\\AppData\\Local\\Temp', 'TMP': 'C:\\Users\\user\\AppData\\Local\\Temp', 'USERDOMAIN': 'DESKTOP-2PGRMF4', 'USERDOMAIN_ROAMINGPROFILE': 'DESKTOP-2PGRMF4', 'USERNAME': 'user', 'USERPROFILE': 'C:\\Users\\user', 'WINDIR': 'C:\\windows', 'ZES_ENABLE_SYSMAN': '1', 'PYDEVD_USE_FRAME_EVAL': 'NO', 'JPY_SESSION_NAME': 'C:\\Users\\user\\New\\0309review.ipynb', 'JPY_INTERRUPT_EVENT': '3216', 'IPY_INTERRUPT_EVENT': '3216', 'JPY_PARENT_PID': '3236', 'TERM': 'xterm-color', 'CLICOLOR': '1', 'FORCE_COLOR': '1', 'CLICOLOR_FORCE': '1', 'PAGER': 'cat', 'GIT_PAGER': 'cat', 'MPLBACKEND': 'module://matplotlib_inline.backend_inline'}
위 결괏값은 필자의 시스템 정보
os.environ은 환경 변수에 대한 정보를 딕셔너리 객체로 돌려줌
돌려받은 객체가 딕셔너리이기 때문에 다음과 같이 호출 가능
- 필자 시스템의 PATH 환경 변수 내용
os.environ['PATH']
'C:\\Program Files\\Amazon Corretto\\jdk11.0.18_10\\bin;C:\\windows\\system32;C:\\windows;C:\\windows\\System32\\Wbem;C:\\windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\windows\\System32\\OpenSSH\\;C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\Scripts\\;C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\;C:\\Users\\user\\AppData\\Local\\Microsoft\\WindowsApps;'
현재 디렉터리 위치 변경 - os.chdir¶
os.chdir("C:/WINDOWS")
현재 디렉터리 위치 돌려받기 - os.getcwd¶
os.getcwd()
'C:\\WINDOWS'
시스템 명령어 호출 - os.system¶
- 시스템 자체의 프로그램이나 기타 명령어를 파이썬에서 호출할 수도 있다.
- os.system("명령어")
- 현재 디렉터리에서 시스템 명령어 dir 실행하기
os.system("dir")
0
실행한 시스템 명령어의 결괏값 돌려받기 - os.popen¶
- os.popen은 시스템 명령어를 실행한 결괏값을 읽기 모드 형태의 파일 객체로 돌려줌
f = os.popen("dir")
- 읽어 들인 파일 객체의 내용 보기
print(f.read())
기타 유용한 os 관련 함수¶
함수 | 설명 |
---|---|
os.mkdir(디렉터리) | 디렉터리 생성 |
os.rmdir(디렉터리) | 디렉터리 삭제. 단 디렉터리가 비어있어야 삭제 가능 |
os.unlink(파일 이름) | 파일을 지운다 |
os.rename(src,dst) | src라는 이름의 파일을 dst라는 이름으로 바꾼다. |
shutil¶
- 파일을 복사해 주는 파이썬 모듈
src라는 이름의 파일을 dst로 복사하기
- dst가 디렉터리 이름일 경우 : src라는 파일 이름으로 dst 디렉터리에 복사
- 동일한 파일 이름이 있을 경우 : 덮어쓰기
import shutil
shutil.copy("src.txt", "dst.txt")
'dst.txt'
위 예를 실행하면 src.txt 파일과 동일한 내용의 파일이 dst.txt로 복사됨
glob¶
- 가끔 파일을 읽고 쓰는 기능이 있는 프로그램을 만들다 보면 특정 디렉터리에 있는 파일 이름 모두를 알아야 할 때가 있다.
- 이럴 때 사용하는 모듈이 바로 glob
디렉터리에 있는 파일들을 리스트로 만들기 - glob(pathname)¶
- glob 모듈은 디렉터리 안의 파일들을 읽어서 돌려준다. *, ? 등 메타 문자를 써서 원하는 파일만 읽어 들일 수도 있다.
- C:/Users/user/test 디렉터리에 있는 파일 중 이름이 sys로 시작하는 파일을 모두 찾아서 읽어들이기
import os
os.chdir("C:/Users/user/test")
import glob
glob.glob("sys*")
['sys1.py', 'sys2.py']
tempfile¶
- 파일을 임시로 만들어서 사용할 때 유용한 모듈
- tempfile.mkstemp() : 중복되지 않는 임시 파일의 이름을 무작위로 만들어서 돌려줌
import tempfile
filename = tempfile.mkstemp()
filename
(3, 'C:\\Users\\user\\AppData\\Local\\Temp\\tmpodg2iu2y')
tempfile.TemporaryFile()¶
- 임시 저장 공간으로 사용할 파일 객체를 돌려줌
- 이 파일은 기본적으로 바이너리 쓰기 모드(wb)를 가짐
- f.close()가 호출되면 이 파일 객체는 자동으로 사라짐
import tempfile
f = tempfile.TemporaryFile()
f.close() # 생성한 임시 파일 자동 삭제
time¶
- 시간과 관련된 time 모듈에는 함수가 굉장히 많다. 그 중 가장 유용한 몇 가지만 살펴보자
time.time¶
- UTC(Universal Time Coordinated 협정 세계 표준시)를 사용해 현재 시간을 실수 형태로 돌려주는 함수
- 1970년 1월 1일 0시 0분 0초를 기준으로 지난 시간을 초 단위로 돌려줌
import time
time.time()
1679559502.4437962
time.time()/60
time.time()/60/60
time.time()/60/60/24 #며칠
time.time()/60/60/24/30 #몇 달
time.time()/60/60/24/30/12 # 몇 년
53.981645794929086
time.localtime¶
- time.time()이 돌려준 실수 값을 사용해 연도, 월, 일, 시, 분, 초, ...의 형태로 바꾸어주는 함수
time.localtime(time.time())
time.struct_time(tm_year=2023, tm_mon=3, tm_mday=23, tm_hour=17, tm_min=18, tm_sec=25, tm_wday=3, tm_yday=82, tm_isdst=0)
t = time.localtime()
print(t.tm_year, "년", t.tm_mday, "일")
2023 년 23 일
time.asctime¶
- 위 time.localtime에 의해서 반환된 튜플 형태의 값을 인수로 받아서 날짜와 시간을 알아보기 쉬운 형태로 돌려주는 함수
time.asctime(time.localtime(time.time()))
'Thu Mar 23 17:18:30 2023'
time.ctime¶
- time.asctime(time.localtime(tim.time()))은 time.ctime()을 사용해 간편하게 표시 가능
- asctime과 다른 점은 ctime은 항상 현재 시간만을 돌려줌
time.ctime()
'Thu Mar 23 17:18:53 2023'
strftime과 strptime¶
- strftime : 날짜와 시간(datetime)을 문자열로 출력
- strptime : 날짜와 시간 형식의 문자열을 datetime으로 변환
time.strftime¶
time.strftime('출력할 형식 포맷 코드', time.localtime(time.time()))
- strftime 함수는 시간에 관계된 것을 세밀하게 표현하는 여러 포맷 코드를 제공
코드 | 설명 | 예 |
---|---|---|
%a | 요일 줄임말 | Mon |
%A | 요일 | Monday |
%b | 달 줄임말 | Jan |
%B | 달 | January |
%c | 날짜와 시간 출력 | Thu Mar 23 17:34:23 2023 |
%d | 날(day) | [01,31] |
%H | 시간(hour):24시간 출력 형태 | [00,23] |
%I | 시간(hour):12시간 출력 형태 | [01,12] |
%j | 1년 중 누적 날짜 | [001,366] |
%m | 달 | [01,12] |
%M | 분 | [01,59] |
%p | AM or PM | AM |
%S | 초 | [00,59] |
%U | 1년 중 누적 주 : 일요일을 시작으로 | [00,53] |
%w | 숫자로 된 요일 | [0(일요일),6] |
%W | 1년 중 누적 주-월요일을 시작으로 | [00,53] |
%x | 현재 설정된 지역에 기반한 날짜 출력 | 06/01/01(월/일/년) |
%X | 현재 설정된 지역에 기반한 시간 출력 | 17:22:21 |
%Y | 연도 출력 | 2001 |
%Z | 시간대 출력 | 대한민국 표준시 |
%% | 문자 | % |
%y | 세기 부분을 제외한 연도 출력 | 01 |
- time.strftime을 사용하는 예시
import time
time.strftime('%x', time.localtime(time.time()))
'03/23/23'
time.strftime('%c', time.localtime(time.time()))
'Thu Mar 23 17:34:23 2023'
import datetime
now = datetime.datetime.now()
date = now.strftime('%Y-%m-%d')
date
'2023-03-17'
time = now.strftime('%H:%M:%S')
time
'18:30:07'
datetime = now.strftime('%Y-%m-%d %H:%M:%S')
datetime
'2023-03-17 18:30:07'
time = now.strftime('')
time.strptime¶
- datetime.strptime(문자열, 형식)
import datetime
str_datetime = '2021-04-08 21:31:48'
currdate = datetime.datetime.strptime(str_datetime, "%Y-%m-%d %H:%M:%S")
print(type(currdate))
<class 'datetime.datetime'>
time.sleep¶
- 주로 루프 안에서 많이 사용
- 이 함수를 사용하면 일정한 시간 간격을 두고 루프 실행 가능
import time
for i in range(10):
print(i)
time.sleep(1)
0 1 2 3 4 5 6 7 8 9
위 예는 1초 간격으로 0부터 9까지의 숫자 출력
위 예에서 볼 수 있듯이 time.sleep함수의 인수는 실수 형태 사용 가능
즉, 1이면 1초, 0.5면 0.5초가 된다.
calendar¶
- 파이썬에서 달력을 볼 수 있게 해주는 모듈
calendar.calendar(연도)¶
- 그 해의 전체 달력을 볼 수 있음
import calendar
print(calendar.calendar(2023))
2023 January February March Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 1 2 3 4 5 1 2 3 4 5 2 3 4 5 6 7 8 6 7 8 9 10 11 12 6 7 8 9 10 11 12 9 10 11 12 13 14 15 13 14 15 16 17 18 19 13 14 15 16 17 18 19 16 17 18 19 20 21 22 20 21 22 23 24 25 26 20 21 22 23 24 25 26 23 24 25 26 27 28 29 27 28 27 28 29 30 31 30 31 April May June Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 2 1 2 3 4 5 6 7 1 2 3 4 3 4 5 6 7 8 9 8 9 10 11 12 13 14 5 6 7 8 9 10 11 10 11 12 13 14 15 16 15 16 17 18 19 20 21 12 13 14 15 16 17 18 17 18 19 20 21 22 23 22 23 24 25 26 27 28 19 20 21 22 23 24 25 24 25 26 27 28 29 30 29 30 31 26 27 28 29 30 July August September Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 2 1 2 3 4 5 6 1 2 3 3 4 5 6 7 8 9 7 8 9 10 11 12 13 4 5 6 7 8 9 10 10 11 12 13 14 15 16 14 15 16 17 18 19 20 11 12 13 14 15 16 17 17 18 19 20 21 22 23 21 22 23 24 25 26 27 18 19 20 21 22 23 24 24 25 26 27 28 29 30 28 29 30 31 25 26 27 28 29 30 31 October November December Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 1 2 3 4 5 1 2 3 2 3 4 5 6 7 8 6 7 8 9 10 11 12 4 5 6 7 8 9 10 9 10 11 12 13 14 15 13 14 15 16 17 18 19 11 12 13 14 15 16 17 16 17 18 19 20 21 22 20 21 22 23 24 25 26 18 19 20 21 22 23 24 23 24 25 26 27 28 29 27 28 29 30 25 26 27 28 29 30 31 30 31
calendar.prcal(연도)¶
- 위와 똑같은 결괏값 출력
calendar.prcal(2023)
2023 January February March Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 1 2 3 4 5 1 2 3 4 5 2 3 4 5 6 7 8 6 7 8 9 10 11 12 6 7 8 9 10 11 12 9 10 11 12 13 14 15 13 14 15 16 17 18 19 13 14 15 16 17 18 19 16 17 18 19 20 21 22 20 21 22 23 24 25 26 20 21 22 23 24 25 26 23 24 25 26 27 28 29 27 28 27 28 29 30 31 30 31 April May June Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 2 1 2 3 4 5 6 7 1 2 3 4 3 4 5 6 7 8 9 8 9 10 11 12 13 14 5 6 7 8 9 10 11 10 11 12 13 14 15 16 15 16 17 18 19 20 21 12 13 14 15 16 17 18 17 18 19 20 21 22 23 22 23 24 25 26 27 28 19 20 21 22 23 24 25 24 25 26 27 28 29 30 29 30 31 26 27 28 29 30 July August September Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 2 1 2 3 4 5 6 1 2 3 3 4 5 6 7 8 9 7 8 9 10 11 12 13 4 5 6 7 8 9 10 10 11 12 13 14 15 16 14 15 16 17 18 19 20 11 12 13 14 15 16 17 17 18 19 20 21 22 23 21 22 23 24 25 26 27 18 19 20 21 22 23 24 24 25 26 27 28 29 30 28 29 30 31 25 26 27 28 29 30 31 October November December Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 1 2 3 4 5 1 2 3 2 3 4 5 6 7 8 6 7 8 9 10 11 12 4 5 6 7 8 9 10 9 10 11 12 13 14 15 13 14 15 16 17 18 19 11 12 13 14 15 16 17 16 17 18 19 20 21 22 20 21 22 23 24 25 26 18 19 20 21 22 23 24 23 24 25 26 27 28 29 27 28 29 30 25 26 27 28 29 30 31 30 31
calendar.prmonth(월)¶
- 2023년 12월의 달력만 출력
calendar.prmonth(2023, 12)
December 2023 Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
calendar.weekday(연도, 월, 일)¶
- 그 날짜에 해당하는 요일 정보 출력
- 월요일: 0, 화요일: 1, 수요일: 2, 목요일: 3, 금요일: 4, 토요일: 5, 일요일: 6
calendar.weekday(2023,12,31)
6
calendar.monthrange(연도, 월)¶
- 입력받은 달의 1일이 무슨 요일인지와 그 달이 며칠가지 있는지를 튜플 형태로 돌려줌
calendar.monthrange(2023, 12)
(4, 31)
위 예는 2023년 12월 1일은 금요일이고, 이 달은 31일까지 있다는 것을 보여줌
날짜 관련 프로그래밍을 할 때 위 2가지 함수는 매우 유용하게 사용됨
random¶
- 난수(규칙이 없는 임의의 수)를 발생시키는 모듈
- random, randint
random.random()¶
- 0부터 1사이의 랜덤 실수 리턴
import random
random.random() # Random float x, 0.0 <= x < 1.0
0.24893784658835794
random.randint¶
- 2개 숫자 사이의 랜덤 정수 리턴(2번째 인자로 넘어온 정수도 범위에 포함)
- 1에서 10 사이의 정수 중 난수 값을 돌려줌
random.randint(1,10) # Integer from 1 to 10, endpoints included
4
- 1에서 55사이의 정수 중에서 난수 값을 돌려줌
random.randint(1,55)
20
- random 모듈을 사용한 함수 만들기
import random
def random_pop(data):
number = random.randint(0,len(data)-1)
return data.pop(number)
if __name__=="__main__":
data=[1,2,3,4,5]
while data:
print(random_pop(data))
2 3 5 1 4
위 random_pop 수는 리스트의 요소 중 무작위를 하나 선택해 꺼낸 후 그 값을 돌려줌.
꺼낸 요소는 pop 메서드에 의해 사라짐
random.shuffle¶
- 리스트의 항목을 무작위로 섞고 싶을 때 사용
import random
data = [1,2,3,4,5]
random.shuffle(data)
data
[2, 1, 5, 3, 4]
[1,2,3,4,5] 리스트가 shuffle 함수에 의해 섞여서 [2,1,5,3,4]로 변함
random.uniform()¶
- 2개의 숫자 사이의 랜덤 실수 리턴
random.uniform(1,10) # Random float x, 1.0 <= x < 10.0
2.520366318317702
choice, choices, sample¶
- random.choice: 랜덤으로 요소 하나 취득
- random.choices : 랜덤으로 요로 여러 개 취득. 중복 O
- random.sample: 랜덤으로 요소 여러 개 취득. 중복 X
random.choice()¶
- 랜덤하게 하나의 원소 선택
import random
l = [0,1,2,3,4]
print(random.choice(l))
2
random.choice('abcdefghi') # Choose a random element
'g'
- 튜플이나 문자열에서도 choice 함수를 사용해 문자를 랜덤하게 취득 가능
import random
print(random.choice(('xxx','yyy','zzz')))
print(random.choice('abcde'))
yyy d
- 주의점 : 공백 리스트나 튜플 또는 문자열에 choice 함수를 사용하면 에러 발생
import random
print(random.choice([]))
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) Cell In[62], line 2 1 import random ----> 2 print(random.choice([])) File ~\AppData\Local\Programs\Python\Python310\lib\random.py:378, in Random.choice(self, seq) 376 """Choose a random element from a non-empty sequence.""" 377 # raises IndexError if seq is empty --> 378 return seq[self._randbelow(len(seq))] IndexError: list index out of range
random.choices()¶
- 형식: choices(리스트, k =취득개수)
- choices 함수의 첫 번째 파라미터 : 대상이 되는 리스트
- choices 함수의 두 번재 파라미터 : 랜덤으로 취득하고 싶은 요소 개수 k
import random
l = [0,1,2,3,4]
print(random.choices(l, k=3))
[0, 1, 2]
choices 함수를 사용해 취득한 결과를 보면 추출 대상 리스트에는 중복된 값을 지정하지 않았지만 중복된 값이 표시되어 있음
sample 함수와 다르게 choices 함수는 한번 추출한 요소를 제외시키지 않음
그래서 추출 대상 리스트의 요소수보다 랜덤하게 취득하고 싶은 요소를 크게 지정해도 에러가 발생하지 않음
import random
l = [0,1,2,3,4]
print(random.choices(l,k=10))
[1, 0, 1, 4, 0, 2, 2, 3, 3, 1]
추출 대상 리스트에는 요소가 5개 있지만 랜덤으로 10개 추출 가능
k를 생략할 경우 기본값으로 1 지정
random.sample()¶
- 랜덤하게 여러 개의 원소 선택
- sample로 랜덤하게 취득한 값은 중복되지 않음
- 형식
sample(리스트, 취득 개수)
sample 함수의 첫번째 파라미터 : 추출 대상이 되는 리스트
sample 함수의 두번째 파라미터 : 랜덤으로 취득하고 싶은 요소 개수
random.sample([1,2,3,4,5],3) # Choose 3 elements
[4, 5, 3]
#반환한 데이터 타입 확인
a = random.sample([1,2,3,4,5],3)
type(a)
list
sample을 사용해 취득한 결과값은 리스트 형태로 반환
결과값이 없는 경우에도 리스트 형태로 반환
import random
print(random.sample([0,1,2,3,4],0))
[]
- 취득하고 싶은 요소 개수가 추출 대상 리스트 요소수보다 큰 경우 에러발생
import random
l = [0,1,2,3,4]
print(random.sample(l,10))
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[65], line 3 1 import random 2 l = [0,1,2,3,4] ----> 3 print(random.sample(l,10)) File ~\AppData\Local\Programs\Python\Python310\lib\random.py:482, in Random.sample(self, population, k, counts) 480 randbelow = self._randbelow 481 if not 0 <= k <= n: --> 482 raise ValueError("Sample larger than population or is negative") 483 result = [None] * k 484 setsize = 21 # size of a small set minus size of an empty list ValueError: Sample larger than population or is negative
- sample 함수에도 튜플이나 문자열 지정 가능
import random
print(random.sample(('xxx','yyy','zzz'),2))
print(random.sample('abcde', 2))
['zzz', 'xxx'] ['a', 'c']
random.randrange()¶
- range(start, stop, step) 함수로 만들어지는 정수 중 하나를 랜덤하게 리턴
random.randrange(0,101,2) # Even integer from 0 to 100
random.sample() : 중복없이
random.shuffle()
random.choices() : k개 복원추출(중복가능)
random.randint(10,15) : 정수 1개 임의출력,
10~15사이의 정수 1개 출력?
random.random.random() : 0초과 1미만의 실수 중 1개 임의 출력
random.uniform(10,15) : 10~15 사이의 실수 1개 출력?
webbrowser¶
- 자신의 시스템에서 사용하는 기본 웹 브라우저를 자동으로 실행하는 모듈
webbrowser.open¶
- 웹 브라우저가 이미 실행된 상태 : 입력 주소로 이동
- 웹 브라우저가 실행되지 않은 상태 : 새로 웹 브라우저 실행 후 해당 주소로 이동
- 다음 예제는 웹 브라우저를 자동으로 실행하고 해당 URL인 google.com으로 가게 함
import webbrowser
webbrowser.open("http://google.com")
True
webbrowser.open_new¶
- 이미 웹브라우저가 실행된 상태이더라도 새로운 창으로 해당 주소가 열리게 함
webbrowser.open_new("http://google.com")
True
스레드를 다루는 threading 모듈¶
- 프로세스 : 컴퓨터에서 동작하고 있는 프로그램
- 보통 1개의 프로세스는 한 가지 일만 하지만 스레드(Thread)를 사용하면 한 프로세스 안에서 2가지 또는 그 이상의 일을 동시에 수행 가능
import time
def long_task(): # 5초의 시간이 걸리는 함수
for i in range(5):
time.sleep(1) # 1초간 대기
print("working:%s\n" % i)
print("Start")
for i in range(5):
long_task()
print("End")
Start working:0 working:1 working:2 working:3 working:4 working:0 working:1 working:2 working:3 working:4 working:0 working:1 working:2 working:3 working:4 working:0 working:1 working:2 working:3 working:4 working:0 working:1 working:2 working:3 working:4 End
long_task 함수 : 수행하는 데 5초의 시간이 걸리는 함수
위 프로그램은 이 함수를 총 5번 반복해서 수행하는 프로그램.
이 프로그램은 5초가 5번 반복되니 총 25초의 시간이 걸림.
하지만 스레드를 사용하면 5초의 시간이 걸리는 long_task 함수를 동시에 실행할 수 있으니 시간을 줄일 수 있다.
- 스레드를 사용해 수정한 프로그램
import time
import threading # 스레드 생성을 위해서는 threading 모듈 필요
def long_task():
for i in range(5):
time.sleep(1)
print("working:%s\n" % i)
print("Start")
threads = []
for i in range(5):
t = threading.Thread(target=long_task) # 스레드 생성
threads.append(t)
for t in threads:
t.start() # 스레드 실행
print("End")
Start End working:0 working:0 working:0 working:0 working:0 working:1 working:1 working:1 working:1 working:1 working:2 working:2 working:2 working:2 working:2 working:3 working:3 working:3 working:3 working:3 working:4 working:4 working:4 working:4 working:4
이와 같이 프로그램을 수정 후 실행해 보면 25초 걸리던 작업이 5초 정도에 수행된다.
threading.Thread를 사용해 만든 스레드 객체가 동시 작업을 가능하게 해 주기 때문
하지만 위 프로그램을 실행 시 "Start"와 "End"가 먼저 출력되고 그 이후에 스레드의 결과가 출력됨. 또한 프로그램이 정상 종료되지 않음.
우리가 기대하는 것은 "Start"가 출력되고 그 다음에 스레드의 결과 출력 후 마지막으로 "End"가 출력되는 것
- 문제 해결을 위해 수정한 프로그램
import time
import threading
def long_task():
for i in range(5):
time.sleep(1)
print("working:%s\n" % i)
print("Start")
threads = []
for i in range(5):
t = threading.Thread(target=long_task)
threads.append(t)
for t in threads:
t.start()
for t in threads:
t.join() # join으로 스레드가 종료될 때까지 기다림
print("End")
Start working:0 working:0 working:0 working:0 working:0 working:1 working:1 working:1 working:1 working:1 working:2 working:2 working:2 working:2 working:2 working:3 working:3 working:3 working:3 working:3 working:4 working:4 working:4 working:4 working:4 End
스레드의 join함수는 해당 스레드가 종료될 때까지 기다리게 함.
따라서 위와 같이 수정하면 우리가 원하던 출력을 보게 됨.
6장 파이썬 프로그래밍, 어떻게 시작해야 할까?¶
6-1 내가 프로그램을 만들 수 있을까?¶
구구단 만들기¶
#답1.
def GuGu(n):
result = []
for i in range(1,10):
result.append(n*i)
return result
print(GuGu(2))
[2, 4, 6, 8, 10, 12, 14, 16, 18]
def GuGu(n):
result = []
i = 1
while i < 10:
result.append(n*i)
i = i + 1
return result
print(GuGu(2))
[2, 4, 6, 8, 10, 12, 14, 16, 18]
6-2 3과 5의 배수 합하기¶
result = 0
for n in range(1,1000):
if n%3 == 0 or n%5 == 0:
result += n
print(result)
233168
- 15와 같은 수를 이중으로 더하여 잘못된 결과를 출력하는 경우
result = 0
for n in range(1,1000):
if n%3 == 0:
result += n
if n%5 == 0:
result += n
print(result)
266333
- 코딩연습사이트
6-3 게시판 페이징하기¶
게시판 프로그램 만들기¶
- 게시물의 총 건수와 한 페이지에 보여 줄 게시물 수를 입력으로 주었을 때 총 페이지 수 출력
def getTotalPage(m,n):
return m // n + 1
print(getTotalPage(5,10)) # 첫 번째 케이스, 1 출력
print(getTotalPage(15,10)) # 두 번째 케이스, 2 출력
print(getTotalPage(25,10)) # 세 번째 케이스, 3 출력
print(getTotalPage(30,10)) # 네 번째 케이스, 3이 출력되어야 하는데 4가 출력
1 2 3 4
- 코드 변경
def getTotalPage(m,n):
if m % n == 0:
return m // n
else:
return m // n + 1
print(getTotalPage(5,10))
print(getTotalPage(15,10))
print(getTotalPage(25,10))
print(getTotalPage(30,10))
1 2 3 3
6-4 간단한 메모장 만들기¶
- 원하는 메모를 파일에 저장하고 추가 및 조회가 가능한 간단한 메모장을 만들어 보자.
- 입력으로 받은 옵션과 메모를 출력하는 코드 작성
# memo.py
import sys
option = sys.argv[1]
memo = sys.argv[2]
print(option)
print(memo)
-f C:\Users\user\AppData\Roaming\jupyter\runtime\kernel-63ce7524-6808-449b-b6ca-b1a52ad2b60d.json
# 다음 명령 수행
>>python memo.py -a "Life is too short"
-a
Life is too short
Cell In[2], line 2 python memo.py -a "Life is too short" ^ SyntaxError: invalid syntax
- 입력으로 받은 메모를 파일에 쓰도록 코드 변경
# memo.py
import sys
option = sys.argv[1]
if option == '-a':
memo = sys.argv[2]
f = open('memo.txt', 'a')
f.write(memo)
f.write('\n')
f.close()
다시 명령어를 수행하면 추가한 메모가 정상적으로 저장
- 메모 출력 코드
#memo.py
import sys
option = sys.argv[1]
if option == '-a':
memo = sys.argv[2]
f = open('memo.txt', 'a')
f.write(memo)
f.write('\n')
f.close()
elif option == '-v':
f = open('memo.txt')
memo = f.read()
f.close()
print(memo)
>> python memo.py -v
Life is too short
입력한 메모가 그대로 출력
6-5 탭을 4개의 공백을 바꾸기¶
- 스크립트
필요한 기능은? 문서 파일 읽어 들이기, 문자열 변경
입력받는 값은? 탭을 포함한 문서 파일
출력하는 값은? 탭이 공백으로 수정된 문서 파일
7장 정규표현식¶
7-1 정규표현식 살펴보기¶
정규표현식은 왜 필요한가?¶
- 주민등록번호를 포함하고 있는 텍스트가 있다. 이 텍스트에 포함된 모든 주민등록번호의 뒷자리를 * 문자로 변경해 보자.
# 정규표현식 없이 작성
data = """
park 800905-1049118
kim 700905-1059119
"""
result = []
for line in data.split("\n"):
word_result = []
for word in line.split(" "):
if len(word) == 14 and word[:6].isdigit() and word[7:].isdigit():
word = word[:6] + "-" + "*******"
word_result.append(word)
result.append(" ".join(word_result))
print("\n".join(result))
park 800905-******* kim 700905-*******
- 정규표현식 사용해 코드 작성
import re
data = """
park 800905-1049118
kim 700905-1059119
"""
pat = re.compile("(\d{6})[-]\d{7}")
print(pat.sub("\g<1>-*******", data))
park 800905-******* kim 700905-*******
7-2 정규 표현식 시작하기¶
정규 표현식의 기초, 메타 문자¶
- .^$+?{}[]|()
문자 클래스¶
- [] 사이의 문자들과 매치
- ex) [abc] = 'a,b,c 중 한 개의 문자와 매치'
- [] 안의 두 문자 사이에 하이픈(-) 사용 = 두 문자 사이의 범위(From - To)
- ex) [a-c] = [abc]
[0-5] = [012345]
- [a-zA-Z]: 알파벳 모두
- ^ : 반대(not)의 의미
- ex) [^0-9] : 숫자가 아닌 문자만 매치
자주 사용하는 문자 클래스¶
정규표현식 | 설명 |
---|---|
\d | 숫자와 매치, [0-9]와 동일 |
\D | 숫자가 아닌 것과 매치, [^0-9]와 동일 |
\s | whitespace 문자(space나 tab처럼 공백을 표현하는 문자)와 매치, [/t/n/r/f/v]와 동일. 맨 앞의 빈칸은 공백 문자(space)를 의미 |
\S | whitespace 문자가 아닌 것과 매치, [^/t/n/r/f/v]와 동일 |
\w | 문자+숫자(alphanumeric)와 매치, [a-zA-Z0-9_]와 동일 |
\W | 문자+숫자(alphanumeric)가 아닌 문자와 매치, [^a-zA-Z0-9_]와 동일 |
Dot(.)¶
- \n을 제외한 모든 문자와 매치
- re.DOTALL 옵션을 주면 \n 문자와도 매치
a.b # a와 b 사이에 줄바꿈 문자를 제외한 어떤 문자가 들어가도 모두 매치
"a + 모든 문자 + b"
a[.]b # a와 b 사이에 Dot(.) 문자가 있으면 매치
"a + Dot(.)문자 + b"
반복(*) : 0번 이상¶
ca*t # 문자 바로 앞에 있는 a가 0번 이상 반복되면 매치
은 바로 앞에 있는 문자 a가 0부터 무한대로 반복될 수 있다는 의미
반복(+) : 1번 이상¶
- +는 최소 1번 이상 반복될 때 사용
- *은 반복 횟수 0부터
- +은 반복 횟수 1부터
ca+t # 문자 바로 앞에 있는 a가 1번 이상 반복되면 매치
"c + a(1번 이상 반복) + t"
반복({m,n}, ?)¶
- {} 메타 문자를 사용하면 반복 횟수 고정 가능
- {m,n} 정규식을 사용하면 반복 횟수가 m부터 n까지 매치 가능
- m 또는 n을 생략 가능
- 생략된 m은 0과 동일, 생략된 n은 무한대(2억 개 미만)의 의미
- {3,} : 반복 횟수 3 이상
- {,3} : 반복 횟수 3 이하
- {1,}은 + 와 동일
- {0,}은 * 와 동일
1. {m}¶
ca{2}t #a가 2번 반복되면 매치
"c + a(반드시 2번 반복) + t"
2. {m,n}¶
ca(2,5)t # a가 2~5번 반복되면 매치
"c + a(2~5번 반복) + t"
3. ?¶
- {0,1}을 의미
ab?c # b가 0~1번 사용되면 매치
"a + b(있어도 되고 없어도 된다) + c"
지금까지 아주 기초적인 정규 표현식에 대해 알아보았다.
이제 파이썬으로 이러한 정규 표현식을 어떻게 사용할 수 있는지 먼저 알아보자.
파이썬에서 정규 표현식을 지원하는 re 모듈¶
- 파이썬은 정규 표현식을 지원하기 위해 re(regular expression의 약어) 모듈을 제공
- 파이썬을 설치할 때 자동으로 설치되는 기본 라이브러리
- re 모듈 사용 방법
import re
p = re.compile('ab*')
re.compile을 사용하여 정규 표현식(위 예에서는 ab)을 컴파일
**re.compile***의 결과로 돌려주는 객체 p(컴파일된 패턴 객체)를 사용하여 그 이후의 작업 수행 가능
정규식을 사용한 문자열 검색¶
- 이제 컴파일된 패턴 객체를 사용해 문자열 검색을 수행해 보자.
- 컴파일된 패턴 객체는 다음과 같은 4가지 메서드를 제공
메서드 | 목적 |
---|---|
match() | 문자열의 처음부터 정규식과 매치되는지 조사 |
search() | 문자열 전체를 검색하여 정규식과 매치되는지 조사 |
findall() | 정규식과 매치되는 모든 문자열(substring)을 리스트로 돌려줌 |
finditer() | 정규식과 매치되는 모든 문자열(substring)을 반복 가능한 객체로 돌려줌 |
match, search는 정규식과 매치될 때는 match 객체를 돌려주고,
매치되지 않을 때는 None을 돌려줌
import re
p = re.compile('[a-z]+')
match : 문자열 처음부터¶
- match 메서드는 문자열의 처음부터 정규식과 매치되는지 조사
m = p.match("python")
print(m)
<re.Match object; span=(0, 6), match='python'>
"python" 문자열은 [a-z]+ 정규식에 부합되므로 match 객체를 돌려줌
m = p.match("3 python")
print(m)
None
"3 python" 문자열은 처음에 나오는 문자 3이 정규식[a-z]+에 부합되지 않으므로 None을 돌려줌
- match의 결과로 match 객체 또는 None을 돌려주기 때문에 파이썬 정규식 프로그램은 보통 다음과 같은 흐름으로 작성
p = re.compile(정규 표현식)
m = p.match("조사할 문자열")
if m:
print('Match found: ', m.group())
else:
print('No match')
즉 match의 결괏값이 있을 때만 그다음 작업을 수행하겠다는 것
search : 문자열 전체¶
m = p.search("python")
print(m)
<re.Match object; span=(0, 6), match='python'>
"python" 문자열에 search 메서드를 수행하면 match 메서드를 수행했을 때와 동일하게 매치됨
m = p.search("3 python")
print(m)
<re.Match object; span=(2, 8), match='python'>
"3 python" 문자열의 첫 번째 문자는 "3"이지만 search는 문자열의 처음부터 검색하는 것이 아니라 문자열 전체를 검색하기 때문에 "3" 이후의 "python" 문자열과 매치됨
이렇듯 match 메서드와 search 메서드는 문자열의 처음부터 검색할지의 여부에 따라 다르게 사용
findall¶
result = p.findall("life is too short")
print(result)
['life', 'is', 'too', 'short']
"life is too short" 문자열의 'life', 'is', 'too', 'short' 단어를 각각 [a-z]+ 정규식과 매치해서 리스트로 돌려줌
finditer¶
result = p.finditer("life is too short")
print(result)
<callable_iterator object at 0x0000020D8DA144F0>
for r in result:
print(r)
<re.Match object; span=(0, 4), match='life'> <re.Match object; span=(5, 7), match='is'> <re.Match object; span=(8, 11), match='too'> <re.Match object; span=(12, 17), match='short'>
finditer은 findall과 동일하지만 그 결과로 반복 가능한 객체(iterable object)를 돌려줌.
반복 가능한 객체가 포함하는 각각의 요소는 match 객체
예제¶
- msg = "010-1234-5678 peter 010-1234-5679" 에서 전화번호만 골라서 출력
# search 사용
import re
msg = "010-1234-5678 peter 010-1234-5679"
p = re.compile("\d{3}-\d{4}-\d{4}")
m = p.search(msg)
print(m)
<re.Match object; span=(0, 13), match='010-1234-5678'>
# findall 사용
print(p.findall(msg))
['010-1234-5678', '010-1234-5679']
phones = p.findall(msg)
for phone in phones:
print(phone)
010-1234-5678 010-1234-5679
#finditer 사용
result = p.finditer(msg)
print(result)
for r in result: print(r.group())
<callable_iterator object at 0x0000020D926537F0> 010-1234-5678 010-1234-5679
match 객체의 메서드¶
메서드 | 목적 |
---|---|
group() | 매치된 문자열을 돌려줌 |
start() | 매치된 문자열의 시작 위치를 돌려줌 |
end() | 매치된 문자열의 끝 위치를 돌려줌 |
span() | 매치된 문자열의 (시작,끝)에 해당하는 튜플을 돌려줌 |
import re
p = re.compile('[a-z]+')
m = p.match("python")
m.group()
'python'
m.start()
0
m.end()
6
m.span()
(0, 6)
match 메서드를 수행한 결과로 돌려준 match 객체의 start()의 결괏값은 항상 0일 수밖에 없다.
왜냐하면 match 메서드는 항상 문자열의 시작부터 조사하기 때문
- search 메서드를 사용한 경우 start() 값은 다르게 나옴
m = p.search("3 python")
m.group()
'python'
m.start()
2
m.end()
8
m.span()
(2, 8)
모듈 단위로 수행하기¶
- 지금까지 우리는 re.compile을 사용해 컴파일된 패턴 객체로 그 이후의 작업을 수행함.
re 모듈은 이것을 좀 축약한 형태로 사용할 수 있는 방법을 제공
#re.compile 사용
p = re.compile('[a-z]+')
m = p.match("python")
# re 모듈 사용
m = re.match('[a-z]+', "python")
위 예처럼 사용하면 컴파일과 match 메서드를 한 번에 수행 가능
보통 한 번 만든 패턴 객체를 여러 번 사용해야 할 때는 이 방법보다 re.compile을 사용하는 것이 편함
컴파일 옵션¶
- 정규식을 컴파일 할 때 다음 옵션 사용 가능
옵션 이름 | 약어 | 설명 |
---|---|---|
DOTALL | S | dot 문자(.)가 줄바꿈 문자를 포함해 모든 문자와 매치 |
IGNORECASE | I | 대소문자에 관계 없이 매치 |
MULTILINE | M | 여러 줄과 매치(^,$ 메타 문자의 사용과 관계가 있는 옵션) |
VERBOSE | X | verbose 모드 사용(정규식을 보기 편하게 만들 수도 있고 주석 등을 사용할 수도 있다.) |
DOTALL, S¶
- . 메타 문자는 줄바꿈 문자(\n)를 제외한 모든 문자와 매치되는 규칙이 있다.
만약 \n 문자도 포함해 매치하고 싶으면 re.DOTALL 또는 re.S 옵션을 사용해 정규식을 컴파일하면 된다.
import re
p = re.compile('a.b')
m = p.match('a\nb')
print(m) # 문자열과 정규식이 매치되지 않음
None
정규식이 a.b인 경우 문자열 a\nb는 매치되지 않음. 왜냐하면 \n은 . 메타 문자와 매치되지 않기 때문
\n 문자와도 매치되게 하려면 다음과 같이 re.DOTALL 옵션을 사용해야 한다.
p = re.compile('a.b', re.DOTALL)
m = p.match('a\nb')
print(m)
<re.Match object; span=(0, 3), match='a\nb'>
보통 re.DOㅡTALL 옵션은 여러 줄로 이루어진 문자열에서 \n 상관없이 검색할 때 많이 사용
IGNORECASE, I¶
- re.IGNORECASE 또는 re.I 옵션은 대소문자 구별 없이 매치를 수행할 때 사용
p = re.compile('[a-z]', re.I)
p.match('python')
<re.Match object; span=(0, 1), match='p'>
p.match('Python')
<re.Match object; span=(0, 1), match='P'>
p.match('PYTHON')
<re.Match object; span=(0, 1), match='P'>
[a-z] 정규식은 소문자만을 의미하지만 re.I 옵션으로 대소문자 구별 없이 매치됨
MULTILINE, M¶
- re.MULTILINE 또는 re.M 옵션은 조금 후에 설명할 메타 문자인
^,$
와 연관된 옵션 - ^ : 문자열의 처음
- $ : 문자열의 마지막
^python
: 문자열의 처음은 항상 python으로 시작해야 함python$
: 문자열의 마지막은 항상 python으로 끝나야 함
import re
p = re.compile("^python\s\w+")
data = """python one
life is too short
python two
you need python
"""
print(p.findall(data))
['python one']
정규식 '^python\s\w+'은 python이라는 문자열로 시작하고 그 뒤에 whitespace, 그 뒤에 단어가 와야 한다는 의미이다. 검색할 문자열 data는 여러 줄로 이루어져 있다.
실행결과는
['python one']
이는 ^메타 문자에 의해 python이라는 문자열을 사용한 첫 번째 줄만 매치된 것이다.
- ^메타 문자를 문자열 전체의 처음이 아니라 각 라인의 처음으로 인식시키고 싶은 경우
re.MULTILINE 또는 re.M 사용
import re
p = re.compile("^python\s\w+", re.MULTILINE)
data = """python one
life is too short
python two
you need python
python three"""
print(p.findall(data))
['python one', 'python two', 'python three']
re.MULTILINE 옵션으로 인해 ^메타 문자가 문자열 전체가 아닌 각 줄의 처음이라는 의미를 갖게 되었다.
즉 re.MULTILINE 옵션은 ^, $ 메타 문자를 문자열의 각 줄마다 적용해 주는 것
VERBOSE,X¶
- 이해하기 어려운 정규식을 주석 또는 줄 단위로 구분
- re.VERBOSE 또는 re.X 옵션
charref = re.compile(r'&[#](0[0-7]+|[0-9]+|x[0-9a-fA-F]+);')
charref = re.compile(r"""
&[#] # Start of a numeric entiity reference
(
0[0-7]+ # Octal form
| [0-9]+ # Decimal form
| x[0-9a-fA-F]+ # Hexadecimal form
)
; # Trailing semicolon
""", re.VERBOSE)
첫 번째와 두 번째 예를 비교해 보면 컴파일될 객체인 charref는 모두 동일한 역할을 한다.
하지만 정규식이 복잡할 경우 두 번째처럼 주석을 적고 여러 줄로 표현하는 것이 훨씬 가독성이 좋다.
re.VERBOSE 옵션 사용 시 문자열에 사용된 whitespace는 컴파일할 때 제거됨(단 [] 안에 사용한 whitespace는 제외)
그리고 줄 단위로 #기호를 사용해 주석문 작성 가능
백슬래시 문제¶
- 정규 표현식을 파이썬에서 사용할 때 혼란을 주는 요소가 한 가지 있는데, 바로 백슬래시(/)
- 어떤 파일 안에 있는 "\section" 문자열을 찾기 위한 정규식 만들기
\section
이 정규식은 \s문자가 whitespace로 해석되어 의도한 대로 매치가 이루어지지 않는다.ㅡㅡ
- 위 표현과 동일한 의미의 정규식
[ \t\n\r\f\v]ection #\s문자가 이스케이프 코드 \t,\n,\r,\f,\v로 해석됨
- 의도한 대로 매치하고 싶다면 다음과 같이 변경
\\section
즉 위 정규식에서 사용한 \문자가 문자열 자체임을 알려주기 위해 백슬래시 2개를 사용해 익스케이프 처리
- 위 정규식을 컴파일하려면 다음과 같이 작성
p = re.compile('\\section')
그런데 여기서 또 하나의 문제 발생
위처럼 정규식을 만들어서 컴파일하면 실제 파이썬 정규식 엔진에는 파이썬 문자열 리터럴 규칙에 따라 \이 \로 변경되어 \section이 전달됨ㅡㅡ
결국 정규식 엔진에 \문자를 전달하려면 파이썬은 \\처럼 백슬래시 4개를 사용해야 함
p = re.compile('\\\\section')
이렇게 해야만 원하는 결과를 얻을 수 있다. 하지만 너무 복잡하다
만약 위와 같이 \를 사용한 표현이 계속 반복되는 정규식이라면 너무 복잡해서 이해하기 쉽지 않다.
이러한 문제로 인해 파이썬 정규식에는 Raw String 규칙이 생겨났다.
즉 컴파일해야 하는 정규식이 Raw String임을 알려 줄 수 있도록 파이썬 문법을 만든 것이다.
방법은 다음과 같다.
p = re.compile(r'\\section)
위와 같이 정규식 문자열 앞에 r문자를 삽입하면 이 정규식은 Raw String 규칙에 의해 백슬래시 2개 대신 1개만 써도 2개를 쓴 것과 동일한 의미를 지닌다.
7-3 강력한 정규 표현식의 세계로¶
메타 문자¶
아직 살펴보지 않은 메타문자에 대해 알아보자.
여기서 다룰 메타문자는 앞에서 살펴본 메타 문자와 성격이 조금 다르다.
앞에서 살펴본 +,*,[],{} 등의 메타문자는 매치가 진행될 때 현재 매치되고 있는 문자열의 위치가 변경된다(보통 소비된다고 표현)
하지만 이와 달리 문자열을 소비시키지 않는 메타 문자도 있다.
이번에는 이런 문자열 소비가 없는(zero-width assertions) 메타 문자에 대해 살펴보자.
|¶
- or과 동일한 의미
- A|B : A 또는 B
import re
p = re.compile('Crow|Servo')
m = p.match('CrowHello')
print(m)
<re.Match object; span=(0, 4), match='Crow'>
^¶
- 문자열의 맨 처음과 일치
- 앞에서 살펴본 컴파일 옵션 re.MULTILINE을 사용할 경우 : 여러 줄의 문자열일 때 각 줄의 처음과 일치
print(re.search('^Life', 'Life is too short'))
<re.Match object; span=(0, 4), match='Life'>
print(re.search('^Life', 'My Life'))
None
- Life 문자열이 처음에 온 경우 : 매치됨
- 처음 위치가 아닌 경우 : 매치되지 않음
$¶
- ^문자와 반대의 경우
- 문자열의 끝과 매치
print(re.search('short$', 'Life is too short'))
<re.Match object; span=(12, 17), match='short'>
print(re.search('short$', 'Life is too short, you need python'))
None
- 검색할 문자열이 short로 끝난 경우 : 매치됨
- 그 이외의 경우: 매치되지 않음
^
또는 $
문자를 메타 문자가 아닌 문자 그 자체로 매치하고 싶은 경우 : \^
, \$
사용
\A¶
- 문자열의 처음과 매치
- ^ 메타 문자와 동일한 의미이지만 re.MULTILINE 옵션을 사용할 경우 다르게 해석됨
- re.MULTILINE 옵션을 사용할 경우
- ^ : 각 줄의 문자열의 처음과 매치
- \A : 줄과 상관없이 전체 문자열의 처음하고만 매치
\Z¶
- 문자열의 끝과 매치
- \A와 동일하게 re.MULTILINE 옵션 사용 시
$
메타 문자와는 달리 전체 문자열의 끝과 매치
\b¶
- 단어 구분자(Word boundary)
- 보통 단어는 whitespace에 의해 구분됨
p = re.compile(r'\bclass\b')
print(p.search('no class at all'))
<re.Match object; span=(3, 8), match='class'>
'\bclass\b' 정규식은 앞뒤가 whitespace로 구분된 class라는 단어와 매치됨을 의미
따라서 no class at all의 class라는 단어와 매치됨
print(p.search('the declassified algorithm'))
None
위 예의 the declassified algorithm 문자열 안에도 class 문자열이 포함되어 있지만 whitespace로 구분된 단어가 아니므로 매치되지 X
print(p.search('one subclass is'))
None
subclass 문자열 역시 class 앞에 sub 문자열이 더해져 있으므로 매치되지 않음
\b 메타 문자 사용 시 주의할 점
- \b는 파이썬 리터럴 규칙에 의하면 백스페이스(BackSpace)를 의미
그러므로 \b가 백스페이스가 아닌 단어 구분자임을 알려주기 위해 r'\bclass\b'처럼 Raw string임을 알려주는 기호r을 반드시 붙여주어야 함
\B¶
- \b 메타 문자와 반대의 경우
- whitespace로 구분된 단어가 아닌 경우에만 매치
p = re.compile(r'\Bclass\B')
print(p.search('no class at all'))
None
print(p.search('the declassified algorithm'))
<re.Match object; span=(6, 11), match='class'>
print(p.search('one subclass is'))
None
class 단어의 앞뒤에 whitespace가 하나라도 있는 경우 매치가 안 됨
그루핑¶
ABC 문자열이 계속해서 반복되는지 조사하는 정규식을 작성하고 싶다. 어떻게 해야 할까?
이럴 때 필요한 것이 바로 그루핑(Grouping)
위 경우는 다음처럼 그루핑을 사용하여 작성 가능
(ABC)+
() : 그룹을 만들어주는 메타 문자
import re
p = re.compile('(ABC)+')
m = p.search('ABCABCABC OK?')
print(m)
<re.Match object; span=(0, 9), match='ABCABCABC'>
다음 예를 보자.
p = re.compile(r"\w\s+\d+[-]\d+[-]\d+")
m = p.search("park 010-1234-1234")
\w+\s+\d+[-]\d+[-]\d+
은 이름 + " " + 번화번호
형태의 문자열을 찾는 정규식
이렇게 매치된 문자열 중 이름만 뽑아내고 싶다면?
보통 반복되는 문자열을 찾을 때 그룹을 사용하는데, 그룹을 사용하는 보다 큰 이유는 위에서 볼 수 있듯이 매치된 문자열 중에서 특정 부분의 문자열만 뽑아내기 위해서인 경우가 더 많다.
위 예에서 만약 '이름' 부분만 뽑아내려면?
p = re.compile(r"(\w+)\s+\d+[-]\d+[-]\d+")
m = p.search("park 010-1234-1234")
print(m.group(1))
park
이름에 해당하는 '\w+' 부분을 그룹('\w+')으로 만들면 match 객체의 group(인덱스) 메서드를 사용해 그루핑된 부분의 문자열만 뽑아낼 수 있다.
- group 메서드의 인덱스의 의미
group(인덱스) | 설명 |
---|---|
group(0) | 매치된 전체 문자열 |
group(1) | 첫 번째 그룹에 해당하는 문자열 |
group(2) | 두 번째 그룹에 해당하는 문자열 |
group(3) | 세 번째 그룹에 해당하는 문자열 |
p = re.compile(r"(\w+)\s+(\d+[-]\d+[-]\d+)")
m = p.search("park 010-1234-1234")
print(m.group(2))
010-1234-1234
이번에는 전화번호 부분을 추가로 그룹 '(\d+[-]\d+[-]\d+)'로 만들었다.
이렇게 하면 group(2)처럼 사용해 전화번호만 뽑아낼 수 있다.
전화번호 중 국번만 뽑아내고 싶다면?
- 국번 부분을 그루핑
p = re.compile(r"(\w+)\s+((\d+)[-]\d+[-]\d+)")
m = p.search("park 010-1234-1234")
print(m.group(3))
010
위 예에서 볼 수 있듯이 '(\w+)\s+((\d+)[-]\d+[-]\d+)' 처럼 그룹을 중첩되게 사용하는 것도 가능
그룹이 중첩되어 있는 경우 : 바깥쪽부터 시작하여 안쪽으로 들어갈수록 인덱스 증가
그루핑된 문자열 재참조¶
- 그룹의 또 하나 좋은 점은 한 번 그루핑한 문자열을 재참조(Backreferences)할 수 있다는 점이다.
p = re.compile(r'(\b\w+)\s+\1')
p.search('Paris in the the spring').group()
'the the'
정규식 '(\b\w+)\s+\1'은 '(그룹) + " " + 그룹과 동일한 단어'와 매치됨을 의미
이렇게 정규식을 만들면 2개의 동일한 단어를 연속적으로 사용해야만 매치됨
이것을 가능케 하는 것이 바로 재참조 메타 문자인 \1
\1은 정규식의 그룹 중 첫 번째 그룹을 가리킴
그루핑된 문자열에 이름 붙이기¶
정규식 안에 그룹이 무척 많아진다고 가정해 보자. 예를 들어 정규식 안에 그룹이 10개 이상만 되어도 매우 혼란스럽다.
거기에 더해 정규식이 수정되면서 그룹이 추가, 삭제되면 그 그룹을 인덱스로 참조한 프로그램도 모두 변경해주어야 하는 위험도 갖게 됨.
만약 그룹을 인덱스가 아닌 이름(Named Groups)으로 참조할 수 있다면 이런 문제를 해결할 수 있지 않을까?
이러한 이유로 정규식은 그룹을 만들 때 그룹 이름을 지정할 수 있게 함.
(?P<name>\w+)\s+((\d+)[-]\d+[-]\d+)
위 정규식은 앞에서 본 이름과 전화번호를 추출하는 정규식
(/w+)만 (?P
복잡해 보이지만 (/w+)라는 그룹에 name이라는 이름을 붙인 것에 불과
여기에서 사용한 (?...) 표현식은 정규 표현식의 확장 구문
- 그룹에 이름을 지어주는 확장 구문
(?P<그룹 이름>...)
- 그룹에 이름을 지정하고 참조하기
p = re.compile(r"(?P<name>\w+)\s+((\d+)[-]\d+[-]\d+)")
m = p.search("park 010-1234-1234")
print(m.group("name"))
park
위 예에서 볼 수 있듯이 name이라는 그룹 이름으로 참조 가능
그룹 이름 사용 시 정규식 안에서 재참조도 가능
p = re.compile(r'(?P<word>\b\w+)\s+(?P=word)')
p.search('Paris in the the spring').group()
'the the'
위 예에서 볼 수 있듯이 재참조할 때에는 (?P=그룹 이름)이라는 확장 구문 사용
전방 탐색¶
p = re.compile(".+:")
m = p.search("http://google.com")
print(m.group())
http:
정규식 ".+:"와 일치하는 문자열로 http:를 돌려줌
만약 http:라는 검색 결과에서 :를 제외하고 출력하려면?
위 예는 그나마 간단하지만 훨씬 복잡한 정규식이어서 그루핑은 추가로 할 수 없다는 조건까지 더해진다면?
이럴 때 사용하는 것이 전방 탐색
전방 탐색에는 긍정(Positive)와 부정(Negative)의 2종류가 있고 다음과 같이 표현
정규식 | 종류 | 설명 |
---|---|---|
(?=...) | 긍정형 전방 탐색 | ...에 해당하는 정규식과 매치되어야 하며 조건이 통과되어도 문자열이 소비되지 X |
(?!...) | 부정형 전방 탐색 | ...에 해당하는 정규식과 매치되지 않아야 하며 조건이 통과되어도 문자열이 소비되지 X |
긍정형 전방 탐색¶
- 긍정형 전방 탐색을 사용하면 http:의 결과를 http로 바꿀 수 있다.
p = re.compile(".+(?=:)")
m = p.search("http://google.com")
print(m.group())
http
정규식 중 :에 해당하는 부분에 긍정형 전방 탐색 기법을 적용해 (?=:)으로 변경
이렇게 되면 기존 정규식과 검색에선느 동일한 효과를 발휘하지만 :에 해당하는 문자열이 정규식 엔진에 의해 소비되지 않아(검색에는 포함되지만 검색 결과에는 제외됨)
검색 결과에서는 :이 제거된 후 돌려주는 효과
- '파일 이름 + . + 확장자'를 나타내는 정규식
.*[.].*$
이 정규식은 foo.bar, autoexec.bar, sendmail.cf 같은 형식의 파일과 매치됨
- 이 정규식에 'bat인 파일은 제외해야 한다'는 조건 추가
.*[.][^b].*$ # 문자 클래스 [] 안의 ^ 메타 문자는 반대(not)을 의미
이 정규식은 확장자가 b라는 문자로 시작하면 안 된다는 의미.
하지만 이 정규식은 bar라는 파일마저 걸러냄.
정규식을 다음과 같이 수정하자.
.*[.]([^b]..|.[^a].|..[^t])$
이 정규식은 | 메타 문자를 사용해 확장자의 첫 번째 문자가 b가 아니거나 두 번째 문자가 a가 아니거나 세 번째 문자가 t가 아닌 경우를 의미.
이 정규식에 의해 foo.bar은 제외되지 않고 autoexec.bat은 제외되어 만족스러운 결과를 돌려줌.
하지만 이 정규식은 아쉽게도 sendmail.cf처럼 확장자의 문자 개수가 2개인 케이스를 포함하지 못하는 오동작을 하기 시작
따라서 다음과 같이 바꾸자.
.*[.]([^b].?.?|[.[^a]?.?|..?[^t]?])$
확장자의 문자 개수가 2개여도 통과되는 정규식이 만들어짐.
하지만 정규식은 점점 더 복잡해지고 이해하기 어려워짐
그런데 여기서 bat 파일말고 exe 파일도 제외하라는 조건이 추가로 생긴다면?
이 모든 조건을 만족하는 정규식을 구현하려면 패턴은 더욱더 복잡해짐
부정형 전방 탐색¶
이러한 상황의 구원 투수는 바로 부정형 전방 탐색
위 예는 부정형 전방 탐색을 사용하면 다음과 같이 간단하게 처리됨
.*[.](?!bat$).*$
확장자가 bat가 아닌 경우에만 통과된다는 의미
bat 문자열이 있는지 조사하는 과정에서 문자열이 소비되지 않으므로 bat가 아니라고 판단되면 그 이후 정규식 매치가 진행됨
- exe 역시 제외하라는 조건이 추가되더라도 다음과 같이 간단히 표현 가능
.*[.](?!bat$|exe$).*$
추가) 전방탐색과 후방탐색¶
전방탐색¶
string = '''
http://www.forta.com a
https://mail.forta.com b
ftp://ftp.forta.com c
'''
# 문자, 특수문자 등이 하나 이상 마지막은 f
p = re.compile(".+f")# 전방탐색으로 f를 표시
p.findall(string)
['http://www.f', 'https://mail.f', 'ftp://ftp.f']
p = re.compile(".+(?=f)") # 전방탐색으로 f를 표시하지 X
p.findall(string)
['http://www.', 'https://mail.', 'ftp://ftp.']
p = re.compile(".+(?=:)")
p.findall(string)
['http', 'https', 'ftp']
#### 후방탐색
string = '''
http://www.forta.com a
https://mail.forta.com b
ftp://ftp.forta.com c
'''
import re
p = re.compile("(?=f).+") # 후방탐색으로 f를 표시
p.findall(string)
['forta.com a', 'forta.com b', 'ftp://ftp.forta.com c']
p = re.compile("(?<=f).+") #후방탐색으로 f 표시 X
p.findall(string)
['orta.com a', 'orta.com b', 'tp://ftp.forta.com c']
- 예제
s = "http://naver.com http://google.com ftp://daum.net"
1. ['http:', 'http:', 'ftp:']
2. ['http', 'http', 'ftp']
3. ['naver.com', 'google.com', 'daum.net']
p = re.compile("\w+:")
p.findall(s)
['http:', 'http:', 'ftp:']
p = re.compile("\w+(?=:)")
p.findall(s)
['http', 'http', 'ftp']
p = re.compile(r"(?<=//)\S+")
p.findall(s)
['naver.com', 'google.com', 'daum.net']
- tag 내용 뽑아내기
html = 'Kakao <p>ryan</p> keep a straight face.'
# 왼쪽 p 기준 후방탐색, 오른쪽 p 기준 전방탐색
p = re.compile(r"(?<=<p>)\w+(?=</p>)")
p.findall(html)
['ryan']
문자열 바꾸기 (sub)¶
- sub 메서드를 사용하면 정규식과 매치되는 부분을 다른 문자로 쉽게 바꿀 수 있음
- sub 메서드의 첫 번째 매개변수 : 바꿀 문자열(replacement)
- sub 메서드의 두 번째 매개변수 : 대상 문자열
p = re.compile('(blue|white|red)')
p.sub('colour', 'blue socks and red shoes')
'colour socks and colour shoes'
blue 또는 white 또는 red라는 문자열이 colour라는 문자열로 바뀜
바꾸기 횟수 제어
- 세 번째 매개변수로 count 값 넘기기
p.sub('colour', 'blue socks and red shoes', count = 1)
'colour socks and red shoes'
처음 일치하는 blue만 colour라는 문자열로 한 번만 바꾸기가 실행됨
sub 메서드와 유사한 subn 메서드¶
- subn 역시 sub와 동일한 기능을 하지만 반환 결과를 튜플로 돌려준다는 차이가 있음
- 돌려준 튜플의 첫째 요소 : 변경된 문자열
- 돌려준 튜플의 두번째 요소 : 바꾸기가 발생한 횟수
p = re.compile('(blue|white|red)')
p.subn('colour', 'blue socks and red shoes')
('colour socks and colour shoes', 2)
sub 메서드를 사용할 때 참조 구문 사용하기¶
p = re.compile(r"(?P<name>\w+)\s+(?P<phone>(\d+)[-]\d+[-]\d+)")
print(p.sub("\g<phone> \g<name>", "park 010-1234-1234"))
010-1234-1234 park
위 예는 '이름 + 전화번호'의 문자열을 '전화번호 + 이름'으로 바꾸는 예
sub의 바꿀 문자열 부분에 '\g<그룹 이름>'을 사용하면 정규식의 그룹 이름 참조 가능
- 그룹 이름 대신 참조 번호를 사용해도 같은 결과
p = re.compile(r"(?P<name>\w+)\s+(?P<phone>(\d+)[-]\d+[-]\d+)")
print(p.sub("\g<2> \g<1>", "park 010-1234-1234"))
010-1234-1234 park
sub 메서드의 매개변수로 함수 넣기¶
- sub 메서드의 첫 번째 매개변수로 함수를 넣을 수도 있다.
def hexrepl(match):
value = int(match.group())
return hex(value)
p = re.compile(r'\d+')
p.sub(hexrepl, 'Call 65490 for printing, 49152 for user code.')
'Call 0xffd2 for printing, 0xc000 for user code.'
hexrepl 함수는 match 객체(위에서 숫자에 매치되는)를 입력으로 받아 16진수로 변환하여 돌려주는 함수
sub의 첫 번째 매개변수로 함수를 사용할 경우 해당 함수의 첫 번째 매개변수에는 정규식과 매치된 match 객체가 입력됨.
그리고 매치되는 문자열은 함수의 반환 값으로 바뀜
Greedy vs Non-Greedy¶
s = '<html><head><title>Title</title>'
len(s)
32
print(re.match('<.*>', s).span())
(0, 32)
print(re.match('<.*>', s).group())
<html><head><title>Title</title>
'<.>' 정규식의 매치 결과로 <html>
문자열을 돌려주기를 기대했을 것이다.
하지만 메타 문자는 매우 탐욕스러워서 매치할 수 있는 최대한의 문자열인 <html><head><title>Title</title>
문자열을 모두 소비해 버렷다.
어떻게 하면 이 탐욕스러움을 제한하고 <html>
문자열까지만 소비하도록 막을 수 있을까?
- 다음과 같이 non-greedy 문자인 ?를 사용하면 *의 탐욕을 제한 가능
print(re.match('<.*?>',s).group())
<html>
non-greedy 문자인 ?는 *?, +?, ??, {m,n}?와 같이 사용 가능
가능한 한 가장 최소한의 반복을 수행하도록 도와주는 역할
정규표현식 살펴보기¶
import re
print(re.__doc__)
Support for regular expressions (RE). This module provides regular expression matching operations similar to those found in Perl. It supports both 8-bit and Unicode strings; both the pattern and the strings being processed can contain null bytes and characters outside the US ASCII range. Regular expressions can contain both special and ordinary characters. Most ordinary characters, like "A", "a", or "0", are the simplest regular expressions; they simply match themselves. You can concatenate ordinary characters, so last matches the string 'last'. The special characters are: "." Matches any character except a newline. "^" Matches the start of the string. "$" Matches the end of the string or just before the newline at the end of the string. "*" Matches 0 or more (greedy) repetitions of the preceding RE. Greedy means that it will match as many repetitions as possible. "+" Matches 1 or more (greedy) repetitions of the preceding RE. "?" Matches 0 or 1 (greedy) of the preceding RE. *?,+?,?? Non-greedy versions of the previous three special characters. {m,n} Matches from m to n repetitions of the preceding RE. {m,n}? Non-greedy version of the above. "\\" Either escapes special characters or signals a special sequence. [] Indicates a set of characters. A "^" as the first character indicates a complementing set. "|" A|B, creates an RE that will match either A or B. (...) Matches the RE inside the parentheses. The contents can be retrieved or matched later in the string. (?aiLmsux) The letters set the corresponding flags defined below. (?:...) Non-grouping version of regular parentheses. (?P<name>...) The substring matched by the group is accessible by name. (?P=name) Matches the text matched earlier by the group named name. (?#...) A comment; ignored. (?=...) Matches if ... matches next, but doesn't consume the string. (?!...) Matches if ... doesn't match next. (?<=...) Matches if preceded by ... (must be fixed length). (?<!...) Matches if not preceded by ... (must be fixed length). (?(id/name)yes|no) Matches yes pattern if the group with id/name matched, the (optional) no pattern otherwise. The special sequences consist of "\\" and a character from the list below. If the ordinary character is not on the list, then the resulting RE will match the second character. \number Matches the contents of the group of the same number. \A Matches only at the start of the string. \Z Matches only at the end of the string. \b Matches the empty string, but only at the start or end of a word. \B Matches the empty string, but not at the start or end of a word. \d Matches any decimal digit; equivalent to the set [0-9] in bytes patterns or string patterns with the ASCII flag. In string patterns without the ASCII flag, it will match the whole range of Unicode digits. \D Matches any non-digit character; equivalent to [^\d]. \s Matches any whitespace character; equivalent to [ \t\n\r\f\v] in bytes patterns or string patterns with the ASCII flag. In string patterns without the ASCII flag, it will match the whole range of Unicode whitespace characters. \S Matches any non-whitespace character; equivalent to [^\s]. \w Matches any alphanumeric character; equivalent to [a-zA-Z0-9_] in bytes patterns or string patterns with the ASCII flag. In string patterns without the ASCII flag, it will match the range of Unicode alphanumeric characters (letters plus digits plus underscore). With LOCALE, it will match the set [0-9_] plus characters defined as letters for the current locale. \W Matches the complement of \w. \\ Matches a literal backslash. This module exports the following functions: match Match a regular expression pattern to the beginning of a string. fullmatch Match a regular expression pattern to all of a string. search Search a string for the presence of a pattern. sub Substitute occurrences of a pattern found in a string. subn Same as sub, but also return the number of substitutions made. split Split a string by the occurrences of a pattern. findall Find all occurrences of a pattern in a string. finditer Return an iterator yielding a Match object for each match. compile Compile a pattern into a Pattern object. purge Clear the regular expression cache. escape Backslash all non-alphanumerics in a string. Each function other than purge and escape can take an optional 'flags' argument consisting of one or more of the following module constants, joined by "|". A, L, and U are mutually exclusive. A ASCII For string patterns, make \w, \W, \b, \B, \d, \D match the corresponding ASCII character categories (rather than the whole Unicode categories, which is the default). For bytes patterns, this flag is the only available behaviour and needn't be specified. I IGNORECASE Perform case-insensitive matching. L LOCALE Make \w, \W, \b, \B, dependent on the current locale. M MULTILINE "^" matches the beginning of lines (after a newline) as well as the string. "$" matches the end of lines (before a newline) as well as the end of the string. S DOTALL "." matches any character at all, including the newline. X VERBOSE Ignore whitespace and comments for nicer looking RE's. U UNICODE For compatibility only. Ignored for string patterns (it is the default), and forbidden for bytes patterns. This module also defines an exception 'error'.
'Python, Jupyter 🐍 > [python]점프 투 파이썬' 카테고리의 다른 글
점프투파이썬 4장까지 정리 (0) | 2023.03.24 |
---|---|
[Window]파이썬과 jupyter 설치하기 (0) | 2023.03.09 |
5장 파이썬 날개 달기¶
5-1 클래스¶
클래스는 왜 필요한가?¶
result = 0
def add(num):
global result
result += num
return result
print(add(3))
print(add(4))
3 7
result1 = 0
result2 = 0
#계산기1
def add1(num):
global result1
result1 += num
return result1
#계산기2
def add2(num):
global result2
result2 += num
return result2
print(add1(3))
print(add1(4))
print(add2(3))
print(add2(7))
3 7 3 10
#클래스 사용
class Calculator:
def __init__(self):
self.result = 0
def add(self, num):
self.result += num
return self.result
#빼기 기능 추가
def sub(self, num):
self.result -= num
return self.result
cal1 = Calculator()
cal2 = Calculator()
print(cal1.add(3))
print(cal1.add(4))
print(cal2.add(3))
print(cal2.add(7))
3 7 3 10
클래스와 객체¶
class Cookie:
pass
a=Cookie()
b=Cookie()
사칙연산 클래스 만들기¶
클래스 구조 만들기¶
class FourCal:
pass
a = FourCal()
type(a) # a는 FourCal클래스의 객체
__main__.FourCal
객체에 숫자 지정할 수 있게 만들기¶
class FourCal:
def setdata(self, first, second): # 1. 메서드의 매개변수
self.first = first
self.second = second #2.매서드의 수행문(first, second)
1. setdata 메서드의 매개변수¶
a = FourCal()
# 메서드의 첫 번째 매개변수 self에는 setdata메서드를 호출한 객체 a가 자동으로 전달되기 때문에 first,second만 넣어주면 된다.
a.setdata(4,2)
메서드의 또 다른 호출 방법¶
# '클래스 이름.메서드' : 객체 a를 첫 번째 매개변수 self에 꼭 전달
a = FourCal()
FourCal.setdata(a,4,2)
# '객체.메서드' : self를 반드시 생략해서 호출
a = FourCal()
a.setdata(4,2)
2. setdata 메서드의 수행문¶
def setdata(self, first, second):
self.first = first
self.second = second #메서드의 수행문 (first, second)
a.setdata(4,2)호출하면 first, second에는 각각 값 4와 2가 전달되어 setdata 메서드의 수행문은 다음과 같이 해석 self.first = 4 self.second = 2 self는 전달된 객체 a이므로 다시 다음과 같이 해석 a.first = 4 a.second = 2
- a.first = 4 문장 수행 -> a 객체에 객체변수 first 생성 -> 값 4 저장
- a.second = 2 문장 수행 -> a 객체에 객체변수 second 생성 -> 값 2 저장
a = FourCal()
a.setdata(4,2)
print(a.first)
4
print(a.second)
2
#a,b 객체 만들기
a = FourCal()
b = FourCal()
#a객체의 객체변수 first 생성
a.setdata(4,2)
print(a.first)
4
#b객체의 객체변수 first 생성
b.setdata(3,7)
print(b.first)
3
# a 객체의 first 값은 b 객체의 first값에 영향받지 않고 원래 값 유지
print(a.first)
4
- 클래스로 만든 객체의 객체변수는 다른 객체의 객체변수와 상관없이 독립적인 값 유지!!
# 지금까지 완성된 FourCal 클래스
class FourCal:
def setdata(self, first, second):
self.first = first
self.second = second
더하기 기능 만들기¶
class FourCal:
def setdata(self, first, second):
self.first = first
self.second = second
def add(self):
result = self.first + self.second
return result
a = FourCal()
a.setdata(4,2)
# add 메서드 호출
print(a.add())
6
- add 메서드 자세히 살펴보기
def add(self):
result = self.first + self.second
return result
# add 메서드의 매개변수는 self, 반환 값은 result
# 반환 값인 result를 계산하는 부분
result = self.first + self.second
# a.add()와 같이 a 객체에 의해 add 메서드가 수행되면 add메서드의 self에는 객체 a가 자동입력되므로 위 내용은 다음과 같이 해석
result = a.first + a.second
# 위 내용은 a.add() 메서드 호출 전 a.setdata(4,2)가 먼저 호출되어
# a.first = 4, a.second = 2라고 미리 설정되었기에 다음과 같이 해석
result = 4 + 2
print(a.add())
6
곱하기, 빼기 ,나누기 기능 만들기¶
class FourCal:
def setdata(self, first, second):
self.first = first
self.second = second
def add(self):
result = self.first + self.second
return result
def mul(self):
result = self.first * self.second
return result
def sub(self):
result = self.first - self.second
return result
def div(self):
result = self.first / self.second
return result
a = FourCal()
b = FourCal()
a.setdata(4,2)
b.setdata(3,8)
a.add()
6
a.mul()
8
a.sub()
2
a.div()
2.0
b.add()
11
b.mul()
24
b.sub()
-5
b.div()
0.375
생성자(Constructor)¶
a = FourCal()
a.add() # FourCal 클래스의 인스턴스 a에 setdata 메서드를 수행하지 않고 add 메서드를 수행하면 오류 발생
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) Cell In[67], line 1 ----> 1 a.add() # FourCal 클래스의 인스턴스 a에 setdata 메서드를 수행하지 않고 add 메서드를 수행하면 오류 발생 Cell In[51], line 6, in FourCal.add(self) 5 def add(self): ----> 6 result = self.first + self.second 7 return result AttributeError: 'FourCal' object has no attribute 'first'
- 이렇게 객체에 초깃값을 설정해야 할 필요가 있을 때 : setdata 메서드 호출보다는 '생성자 구현'이 안전!!
- 생성자(Constructor) : 객체가 생성될 때 자동으로 호출되는 메서드
- 파이썬 메서드 이름으로 init을 사용하면 이 메서드는 생성자가 된다.
#FourCal 클래스에 생성자 추가
class FourCal:
def __init__(self, first, second):
self.first = first
self.second = second
def setdata(self, first, second):
self.first = first
self.second = second
def add(self):
result = self.first + self.second
return result
def mul(self):
result = self.first * self.second
return result
def sub(self):
result = self.first - self.second
return result
def div(self):
result = self.first / self.second
return result
# 새롭게 추가된 생성자 __init__ 메서드만 따로 떼어 내서 살펴보기
def __init__(self, first, second):
self.first = first
self.second = second
- init 메서드는 setdata 메서드와 이름만 다르고 모든 게 동일.
- 단 메서드 이름을 init으로 했기 때문에 생성자로 인식되어 객체가 생성되는 시점에 자동으로 호출되는 차이
# 생성자 first와 second에 해당하는 값이 전달되지 않아 오류 발생
a = FourCal()
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[76], line 2 1 # 생성자 first와 second에 해당하는 값이 전달되지 않아 오류 발생 ----> 2 a = FourCal() TypeError: FourCal.__init__() missing 2 required positional arguments: 'first' and 'second'
a = FourCal(4,2)
a = FourCal(4,2)
print(a.first)
4
print(a.second)
2
a = FourCal(4,2)
a.add()
6
a.div()
2.0
클래스의 상속¶
- class 클래스 이름(상속할 클래스 이름)
class MoreFourCal(FourCal):
pass
a = MoreFourCal(4,2)
a.add()
6
a = MoreFourCal(4,2)
- MoreFourCal 클래스는 FourCal 클래스를 상속했으므로 FourCal 클래스의 모든 기능 사용 가능
a.add()
6
a.mul()
8
a.sub()
2
a.div()
2.0
class MoreFourCal(FourCal):
def pow(self):
result = self.first ** self.second
return result
a = MoreFourCal(4,2)
a.pow()
16
메서드 오버라이딩(Overriding, 덮어쓰기)¶
- 부모 클래스(상속한 클래스)에 있는 메서드를 동일한 이름으로 다시 만드는 것
a = FourCal(4,0)
a.div() #4를 0으로 나누려고 해서 오류 발생
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) Cell In[100], line 1 ----> 1 a.div() Cell In[73], line 19, in FourCal.div(self) 18 def div(self): ---> 19 result = self.first / self.second 20 return result ZeroDivisionError: division by zero
class SafeFourCal(FourCal):
def div(self):
if self.second == 0: # 나누는 값이 0인 경우 숫자 0을 돌려주도록 수정
return 0
else:
return self.first/ self.second
a = SafeFourCal(4,0)
a.div()
0
#### 상속과 변수 (super())
https://supermemi.tistory.com/178
Cell In[1], line 2 https://supermemi.tistory.com/178 ^ SyntaxError: invalid syntax
상속 super()¶
#예시
class Nintendo:
def __init__(self,name, character):
self.country='Japan'
self.game_name=name
self.character=character
class New(Nintendo):
def __init__(self,name,character,genre,income):
super().__init__(name,character)
self.ceo='Shigeru Miyamoto'
self.genre=genre
self.income=income
p1 = New("simono", "warm", "mystery", 100)
print(p1.country, p1.game_name, p1.ceo, p1.income)
Japan simono Shigeru Miyamoto 100
클래스 변수¶
- 클래스이름.클래스변수
class Family:
lastname = "김" # 클래스 변수
print(Family.lastname)
김
a = Family()
b = Family()
print(a.lastname)
김
print(b.lastname)
김
- 클래스 변수 값을 변경하면 클래스로 만든 객체의 lastname 값도 모두 변경된다 = 클래스 변수는 클래스로 만든 모든 객체에 공유된다
Family.lastname = "박" #Family.lastname 수정하면?
print(a.lastname)
박
print(b.lastname)
박
클래스 변수와 객체 변수¶
- a.lastname을 변경하면?
a.lastname = "최"
print(a.lastname)
최
- 이렇게 하면 Family클래스의 lastname이 바뀌는 것이 아니라 a 객체에 lastname이라는 객체변수가 새롭게 생성
- 즉, 객체변수는 클래스 변수와 동일한 이름으로 생성 가능
- 이제부터 a.lastname은 Family클래스의 lastname이 아닌 객체 a의 객체변수 lastname을 가리킴
- a.lastname의 객체변수를 생성하더라도 Family 클래스의 lastname과는 상관이 없다
print(Family.lastname)
박
print(b.lastname)
박
- Family 클래스의 lastname 값은 변하지 않았다
5-2 모듈¶
- 함수나 변수 또는 클래스를 모아 놓은 파일
- 다른 파이썬 프로그램에서 불러와 사용할 수 있게끔 만든 파이썬 파일
모듈 만들기¶
#mod1.py
def add(a,b):
return a+b
def sub(a,b):
return a-b
파이썬 확장자 .py로 만든 파이썬 파일은 모두 모듈이다.
모듈 불러오기¶
- 모듈 실행 방법
C:\Users\user>cd doit # mod1.py 저장한 디렉터리로 이동
C:\Users\user\doit>dir # C:\Users\user\doit 디렉터리에 파일이 있는지 확인
2023-03-21 오후 06:50 58 mod1.py
C:\Users\user\doit>python # 대화형 인터프리터 실행
반드시 mod1.py를 저장한 C:\Users\user\doit 디렉터리로 이동한 다음 예제 진행.
그래야만 대화형 인터프리터에서 mod1.py를 읽을 수 있다.
>>> import mod1
>>> print(mod1.add(3,4))
7
>>> print(mod1.sub(4,2))
2
mod1.py를 불러오기 위해 import mod1이라고 입력.
실수로 import mod1.py로 입력하지 않도록 주의!!
- import : 이미 만들어 놓은 파이썬 모듈을 사용할 수 있게 해주는 명령어
- mod1.py 파일에 있는 add 함수를 사용하기 위해서는 위 예와 같이 mod1.add처럼 모듈 이름 뒤에 '.'(도트 연산자)를 붙이고 함수 이름을 쓰면 된다.
- import 사용방법
import 모듈 이름
여기서 모듈 이름은 mod1.py에서 .py 확장자를 제거한 mod1만을 가리킴
- mod1.add, mod1.sub 처럼 쓰지 않고 add,sub 처럼 모듈 이름 없이 함수 이름만 쓰고 싶은 경우
from 모듈 이름 import 모듈 함수
위 형식을 사용하면 모듈 이름을 붙이지 않고 바로 해당 모듈의 함수를 쓸 수 있다.
>>> from mod1 import add
>>> add(3,4)
7
위와 같이 하면 add 함수만 사용 가능
add 함수와 sub 함수 둘 다 사용하고 싶다면?
- 2가지 방법
from mod1 import add, sub
from mod1 import *
ifname == "main__": 의 의미¶
mod1.py 파일을 다음과 같이 변경하자.
#mod1.py
def add(a,b):
return a+b
def sub(a,b):
return a-b
# ----- 추가 -----
print(add(1,4))
print(sub(4,2))
- 실행 결과
C:\Users\user\doit>python mod1.py
5
2
- mod1.py 파일의 add와 sub 함수를 사용하기 위해 mod1 모듈을 import할 때 문제 생김
C:\Users\user\doit>python
Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec 6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import mod1
5
2
import mod1을 수행하는 순간 mod1.py가 실행되어 결괏값 출력.
우리는 단지 add와 sub 함수만 사용하려고 했는데 말이다.
이런 문제를 방지하려면 mod1.py 파일을 다음처럼 변경
#mod1.py
def add(a,b):
return a+b
def sub(a,b):
return a-b
# 바뀐 코드
if __name__ == "__main__":
print(add(1,4))
print(sub(4,2))
if __name__ == "__main__"
을 사용하면
- C:\Users\user\doit>python mod1.py처럼 직접 이 파일을 실행할 경우 :
if __name__ == "__main__"
이 참이 되어 if 다음 문장 수행 - 대화형 인터프리터나 다른 파일에서 이 모듈을 불러서 사용할 경우 :
if __name__ == "__main__"
이 거짓이 되어 if 다음 문장 수행 X
- 위와 같이 수정 후 다시 실행
>>> import mod1
>>>
아무 결괏값도 출력되지 않는다.
__name__
변수란?¶
파이썬의 __name__
변수는 파이썬이 내부적으로 사용하는 특별한 변수 이름
- C:\Users\user\doit>python mod1.py처럼 직접 이 파일을 실행할 경우 : mod1.py의
__name__
변수에는__main__
값이 저장 - 파이썬 셸이나 다른 파이썬 모듈에서 mod1을 import할 경우 : mod1.py의
__name__
변수에는 mod1.py의 모듈 이름 값 mod1이 저장
클래스나 변수 등을 포함한 모듈¶
- 지금까지 살펴본 모듈은 함수만 포함했지만 클래스나 변수 등을 포함할 수도 있다.
# mod2.py
PI = 3.141592
class Math:
def solv(self, r):
return PI * (r**2)
def add(a,b):
return a+b
- 클래스 : 원의 넓이를 계산하는 Math 클래스
- 함수 : 두 값을 더하는 add 함수
- 변수 : 원주율 값에 해당되는 PI 변수
- mod2.PI처럼 입력해서 mod2.py 파일에 있는 PI 변수 값 사용 가능
C:\Users\user\doit>python
Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec 6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import mod2
>>> print(mod2.PI)
3.141592
- mode2.py에 있는 Math 클래스 사용하기
>>> a =mod2.Math()
>>> print(a.solv(2))
12.566368
모듈 안에 클래스를 사용하려면 '.'(도트 연산자)로 클래스 이름 앞에 모듈 이름 먼저 입력
- mode2.py에 있는 add 함수 사용하기
>>> print(mod2.add(mod2.PI, 4.4))
7.5415920000000005
다른 파일에서 모듈 불러오기¶
지금까지는 만들어 놓은 모듈 파일을 사용하기 위해 대화형 인터프리터만 사용
이번에는 다른 파이썬 파일에서 이전에 만들어 놓은 모듈을 불러와서 사용
- mod2.py 파일을 다른 파이썬 파일에서 불러와 사용하기
# modtest.py
import mod2
result = mod2.add(3,4)
print(result)
C:\Users\user\doit>python modtest.py
7
결과 정상적으로 출력
모듈을 불러오는 또 다른 방법¶
우리는 지금껏 명령 프롬프트 창을 열고 모듈이 있는 디렉터리로 이동 후 모듈을 사용할 수 있었다.
이번에는 모듈을 저장한 디렉터리로 이동하지 않고 모듈을 불러와 사용하는 방법에 대해 알아보자.
5-3 패키지¶
- 다음에 정리
5-4 예외 처리¶
오류는 어떨 때 발생?¶
- 디렉터리 안에 없는 파일을 열려고 시도
f = open("나없는파일", 'r')
--------------------------------------------------------------------------- FileNotFoundError Traceback (most recent call last) Cell In[4], line 1 ----> 1 f = open("나없는파일", 'r') File ~\AppData\Local\Programs\Python\Python310\lib\site-packages\IPython\core\interactiveshell.py:282, in _modified_open(file, *args, **kwargs) 275 if file in {0, 1, 2}: 276 raise ValueError( 277 f"IPython won't let you open fd={file} by default " 278 "as it is likely to crash IPython. If you know what you are doing, " 279 "you can use builtins' open." 280 ) --> 282 return io_open(file, *args, **kwargs) FileNotFoundError: [Errno 2] No such file or directory: '나없는파일'
FileNotFoundError 오류 발생
- 0으로 다른 숫자를 나누는 경우
4/0
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) Cell In[6], line 1 ----> 1 4/0 ZeroDivisionError: division by zero
4를 0으로 나누려니까 ZeroDivisionError 오류 발생
a = [1,2,3]
a[4]
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) Cell In[9], line 1 ----> 1 a[4] IndexError: list index out of range
IndexError 오류 발생
오류 예외 처리 기법¶
try, except문¶
- 기본 구조
try:
...
except [발생 오류[as 오류 메시지 변수]]:
...
- try 블록 수행 중 오류 발생 : except 블록 수행
- try 블록 수행 중 오류 발생X : except 블록 수행되지 X
- except 구문
except [발생 오류 [as 오류 메시지 변수]]:
[]
기호 : 괄호 안의 내용을 생략할 수 있다는 관례 표기법
except 구문을 사용하는 3가지 방법¶
1. try, except만 쓰는 방법¶
오류 종류에 상관없이 오류 발생하면 except 블록 수행
try:
...
except:
...
2. 발생 오류만 포함한 except문¶
오류 발생 시 except문에 미리 정해 놓은 오류 이름과 일치할 때만 except 블록 수행
try:
...
except 발생 오류:
...
3. 발생 오류와 오류 메시지 변수까지 포함한 except문¶
두 번째 경우에서 오류 메시지의 내용까지 알고 싶을 때 사용
try:
...
except 발생 오류 as 오류 메시지 변수:
...
try:
4/0
except ZeroDivisionError as e:
print(e)
division by zero
위처럼 4를 0으로 나누려고 하면 ZeroDivisionError가 발생해 except 블록이 실행되고 변수 e에 담기는 오류 메시지를 출력(division by zero)
- 나코딩
try:
a = [1,2,3]
a[4]
except IndexError as e:
print(e)
list index out of range
try ... finally¶
- finally절은 try문 수행 도중 예외 발생 여부에 상관없이 항상 수행
- 보통 finally절은 사용한 리소스를 close해야 할 때 많이 사용
f = open('foo.txt', 'w')
try:
#무언가 수행
finally:
f.close()
Cell In[15], line 4 finally: ^ IndentationError: expected an indented block after 'try' statement on line 2
foo.txt 파일을 쓰기 모드로 연 후 try문을 수행 후 예외 발생 여부와 상관없이 finally절에서 f.close()로 열린 파일 닫기 가능
여러 개의 오류 처리하기¶
- 구문
try:
...
except 발생 오류 1:
...
except 발생 오류 2:
...
try:
a = [1,2]
print(a[3])
4/0
except ZeroDivisionError:
print("0으로 나눌 수 없습니다.")
except IndexError:
print("인덱싱할 수 없습니다.")
인덱싱할 수 없습니다.
인덱싱 오류가 먼저 발생했으므로 4/0으로 발생되는 ZeroDivisionError 오류는 발생되지 않았다.
- 오류 메시지도 가져오기
try:
a = [1,2]
print(a[3])
4/0
except ZeroDivisionError as e:
print(e)
except IndexError as e:
print(e)
list index out of range
- ZeroDivisionError와 IndexError 함께 처리
try:
a = [1,2]
print(a[3])
4/0
except (ZeroDivisionError, IndexError) as e:
print(e)
list index out of range
2개 이상의 오류를 동시에 처리하기 위해서는 위와 같이 괄호를 사용해 함께 묶어 처리
오류 회피하기¶
try:
f = open("나없는파일", 'r')
except FileNotFoundError: # 파일이 없더라도 오류를 발생시키지 않고 통과
pass
오류 일부러 발생시키기(raise)¶
- raise 명령어를 사용해 오류를 강제로 발생시킬 수 있다.
- Bird 클래스를 상속받는 자식 클래스는 반드시 fly라는 함수를 구현하도록 만들고 싶은 경우(강제로 그렇게 하고 싶은 경우)
class Bird:
def fly(self):
raise NotImplementedError
- 자식 클래스가 fly 함수를 구현하지 않은 상태로 fly 함수 호출한 경우
class Eagle(Bird): #Eagle 클래스는 Bird 클래스를 상속 받음
pass
eagle = Eagle()
eagle.fly()
--------------------------------------------------------------------------- NotImplementedError Traceback (most recent call last) Cell In[7], line 5 2 pass 4 eagle = Eagle() ----> 5 eagle.fly() Cell In[6], line 3, in Bird.fly(self) 2 def fly(self): ----> 3 raise NotImplementedError NotImplementedError:
Eagle클래스는 Bird클래스를 상속받는다. 그런데 Eagle클래스에서 fly함수를 구현하지 않았기 때문에 Bird 클래스의 fly 함수가 호출된다.
그리고 raise문에 의해 NotImplemented Error 발생
- NotImplementedError가 발생되지 않도록 다음과 같이 Eagle클래스에 fly 함수 반드시 구현
class Eagle(Bird):
def fly(self):
print("very fast")
eagle = Eagle()
eagle.fly()
very fast
예외 만들기¶
- 프로그램 수행 도중 특수한 경우에만 예외 처리를 하기 위해 종종 예외를 만들어서 사용
- 파이썬 내장 클래스인 Exception 클래스를 상속하여 예외를 만들 수 있다
class MyError(Exception):
pass
- 별명 출력해주는 함수 작성
def say_nick(nick):
if nick == '바보':
raise MyError()
print(nick)
say_nick("천사")
천사
say_nick("바보") # MyError 발생
--------------------------------------------------------------------------- MyError Traceback (most recent call last) Cell In[12], line 1 ----> 1 say_nick("바보") Cell In[10], line 3, in say_nick(nick) 1 def say_nick(nick): 2 if nick == '바보': ----> 3 raise MyError() 4 print(nick) MyError:
- 예외 처리 기법을 사용해 MyError 발생을 예외 처리
try:
say_nick("천사")
say_nick("바보")
except MyError:
print("허용되지 않는 별명입니다.")
천사 허용되지 않는 별명입니다.
- 오류 메시지 사용한 예외 처리
try:
say_nick("천사")
say_nick("바보")
except MyError as e:
print(e)
천사
하지만 프로그램을 실행해 보면 print(e)로 오류 메시지가 출력되지 않음.
오류 메시지 출력 시 오류 메시지가 보이게 하려면 오류 클래스에 다음과 같은 str 메서드 구현
str 메서드 : print(e)처럼 오류 메시지를 print문으로 출력할 경우 호출되는 메서드
class MyError(Exception):
def __str__(self):
return "허용되지 않는 별명입니다."
try:
say_nick("천사")
say_nick("바보")
except MyError as e:
print(e)
천사 허용되지 않는 별명입니다.
# total(1,'2'3,4,5,'6')은 13이 출력되도록 total()를 만드시오.
def total(*args):
result = 0
for arg in args:
try:
result += arg
except:
print(f"{arg}는 int가 아닙니다.")
return result
total(1,'2',3,4,5,'6')
2는 int가 아닙니다. 6는 int가 아닙니다.
13
"허용되지 않는 별명입니다." 라는 오류메시지 출력
5-5 내장 함수¶
abs(x)¶
- 어떤 숫자를 입력받았을 때, 그 숫자의 절댓값을 돌려주는 함수
abs(3)
3
abs(-3)
3
abs(-1.2)
1.2
all(x)¶
- 반복 가능한(iterable) 자료형 x를 입력 인수로 받으며 이 x가 모두 참이면 True, 거짓이 하날도 있으면 False를 돌려줌
all([1,2,3])
True
all([1,2,3,0])
False
any(x)¶
- x 중 하나라도 참이 있으면 True를 돌려주고, x가 모두 거짓일 때에만 False를 돌려줌. all(x)의 반대
any([1,2,3,0])
True
any([0,""])
False
chr(i)¶
- 아스키(ASCII) 코드 값을 입력받아 그 코드에 해당하는 문자를 출력하는 함수
chr(97)
'a'
chr(48)
'0'
dir¶
- 객체가 자체적으로 가지고 있는 변수나 함수를 보여줌
- 다음 예는 리스트와 딕셔너리 객체 관련 함수(메서드)를 보여주는 예
dir([1,2,3])
['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
dir({'1':'a'})
['__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__ior__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__ror__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
divmod(a,b)¶
- 2개의 숫자를 입력으로 받으며, a를 b로 나눈 몫과 나머지를 튜플 형태로 돌려줌
divmod(7,3)
(2, 1)
7//3
2
7%3
1
enumerate¶
- '열거하다'라는 뜻. 이 함수는 순서가 있는 자료형(리스트, 튜플, 문자열)을 입력으로 받아 인덱스 값을 포함하는 enumerate 객체를 돌려줌.
- for문과 함께 자주 사용
for i, name in enumerate(['body', 'foo', 'bar']):
print(i, name)
0 body 1 foo 2 bar
위 예제와 같이 enumerate을 for문과 함께 사용하면 자료형의 현재 순서(index)와 그 값을 쉽게 알 수 있다.
for문처럼 반복되는 구간에서 객체가 현재 어느 위치에 있는지 알려 주는 인덱스 값이 필요할 때 enumberate 함수를 사용하면 매우 유용함
eval(expression)¶
- 실행 가능한 문자열(1+2, 'hi'+'a' 같은 것)을 입력으로 받아 문자열을 실행한 결괏값을 돌려주는 함수
eval('1+2')
3
eval("'hi' + 'a'")
'hia'
eval('divmod(4,3)')
(1, 1)
filter¶
- 첫 번째 인수 : 함수 이름
- 두 번째 인수 : 그 함수에 차례로 들어가 반복 가능한 자료형
#filter함수 없이
def positive(l):
result = []
for i in l:
if i > 0:
result.append(i)
return result
print(positive([1,-3,2,0,-5,6]))
[1, 2, 6]
#filter 함수 사용
def positive(x):
return x > 0
print(list(filter(positive, [1,-3,2,0,-5,6])))
[1, 2, 6]
list(filter(lambda x: x>0, [1,-3,2,0,-5,6]))
[1, 2, 6]
hex(x)¶
- 정수 값을 입력받아 16진수(hexadecimal)로 변환하여 돌려주는 함수
hex(234)
'0xea'
hex(3)
'0x3'
id(object)¶
- 객체를 입력받아 객체의 고유 주소 값(레퍼런스)을 돌려주는 함수
a=3
id(3)
2093048332592
b=a
id(b)
2093048332592
- 3, a, b가 모두 같은 객체를 가리킴
id(4) # 다른 고유 주소값
2093048332624
input([prompt])¶
- 사용자 입력을 받는 함수
a = input()
a
'hi'
b = input("Enter: ")
b
'hi'
int(x)¶
- 문자열 형태의 숫자나 소수점이 있는 숫자 등을 정수 형태로 돌려주는 함수
int('3')
3
int(3.4)
3
int(x, radix)¶
- radix 진수로 표현된 문자열 x를 10진수로 변환하여 돌려줌
int('11',2) #2진수로 표현된 11의 10진수 값 구하기
3
int('1A', 16) #16진수로 표현된 1A의 10진수 값 구하기
26
isinstance(object, class)¶
- 첫 번째 인수: 인스턴스 , 두 번째 인수: 클래스 이름
- 입력으로 받은 인스턴스가 그 클래스의 인스턴스인지를 판다하여 참이면 True, 거짓이면 False를 돌려줌
class Person:
pass
a = Person()
isinstance(a, Person) #a가 Person클래스의 인스턴스인지 확인
True
b=3
isinstance(b, Person) #b가 Person클래스의 인스턴스인지 확인
False
len(s)¶
- 입력값 s의 길이(요소의 전체 개수)를 돌려주는 함수
len("python")
6
len([1,2,3])
3
len((1,'a'))
2
list(s)¶
- 반복 가능한 자료형 s를 입력받아 리스트로 만들어 돌려주는 함수
list("python")
['p', 'y', 't', 'h', 'o', 'n']
list((1,2,3))
[1, 2, 3]
- 리스트 함수에 리스트를 입력으로 주면 똑같은 리스트를 복사해 돌려줌
a = [1,2,3]
b = list(a)
b
[1, 2, 3]
map(f, iterable)¶
- 함수(f)와 반복 가능한(iterable) 자료형을 입력으로 받음
- map은 입력받은 자료형의 각 요소를 함수 f가 수행한 결과를 묶어서 돌려주는 함수
#map 사용 전
def two_times(numberList):
result = []
for number in numberList:
result.append(number*2)
return result
result = two_times([1,2,3,4])
print(result)
[2, 4, 6, 8]
#map 사용 후
def two_times(x): return x*2
list(map(two_times, [1,2,3,4]))
[2, 4, 6, 8]
list(map(lambda a:a*2, [1,2,3,4]))
[2, 4, 6, 8]
max(iterable)¶
- 인수로 반복 가능한 자료형을 입력받아 그 최댓값을 돌려주는 함수
max([1,2,3])
3
max("python")
'y'
min(iterable)¶
- max함수와 반대로, 인수로 반복 가능한 자료형을 입력받아 그 최솟값을 돌려주는 함수
min([1,2,3])
1
min("python")
'h'
oct(x)¶
- 정수 형태의 숫자를 8진수 문자열로 바꾸어 돌려주는 함수
oct(34)
'0o42'
oct(12345)
'0o30071'
open(filename, [mode])¶
- '파일 이름'과 '읽기 방법'을 입력받아 파일 객체를 돌려주는 함수
- 읽기 방법(mode)을 생략하면 기본값인 읽기 전용 모드(r)로 파일 객체를 만들어 돌려줌
f = open("binary_file", "rb") #rb는 '바이너리 읽기 모드'
--------------------------------------------------------------------------- FileNotFoundError Traceback (most recent call last) Cell In[53], line 1 ----> 1 f = open("binary_file", "rb") #rb는 '바이너리 읽기 모드' File ~\AppData\Local\Programs\Python\Python310\lib\site-packages\IPython\core\interactiveshell.py:282, in _modified_open(file, *args, **kwargs) 275 if file in {0, 1, 2}: 276 raise ValueError( 277 f"IPython won't let you open fd={file} by default " 278 "as it is likely to crash IPython. If you know what you are doing, " 279 "you can use builtins' open." 280 ) --> 282 return io_open(file, *args, **kwargs) FileNotFoundError: [Errno 2] No such file or directory: 'binary_file'
# fread와 fread2는 동일한 방법
fread = open("read_mode.txt", 'r')
fread2 = open("read_mode.txt")
fappend = open("append_mode.txt", 'a')
ord(c)¶
- 문자의 아스키 코드 값을 돌려주는 함수
ord('a')
97
ord('0')
48
pow¶
- pow(x,y)는 x의 y제곱한 결괏값을 돌려주는 함수
pow(2,4)
16
pow(3,3)
27
range([start,] stop [,step])¶
- for문과 함께 자주 사용
- 입력받은 숫자에 해당하는 범위 값을 반복 가능한 객체로 만들어 돌려줌
인수가 하나일 경우¶
list(range(5))
[0, 1, 2, 3, 4]
인수가 2개일 경우¶
list(range(5,10))
[5, 6, 7, 8, 9]
인수가 3개일 경우¶
list(range(1,10,2))
[1, 3, 5, 7, 9]
list(range(9,-10,-1))
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
round(number[,ndigits])¶
- 숫자를 입력받아 반올림해주는 함수
- round 함수의 두 번째 매개변수는 반올림하여 표시하고 싶은 소수점의 자릿수(ndigits)
round(4.6)
5
round(4.2)
4
round(5.678,2)
5.68
sorted(iterable)¶
- 입력값을 정렬한 후 그 결과를 리스트로 돌려주는 함수
sorted([3,1,2])
[1, 2, 3]
sorted(['a','c','b'])
['a', 'b', 'c']
sorted("zero")
['e', 'o', 'r', 'z']
sorted((3,2,1))
[1, 2, 3]
str(object)¶
- 문자열 형태로 객체를 변환하여 돌려주는 함수
str(3)
'3'
str('hi')
'hi'
str('hi'.upper())
'HI'
sum(iterable)¶
- 입력받은 리스트나 튜플의 모든 요소의 합을 돌려주는 함수
sum([1,2,3])
6
sum([4,5,6])
15
tuple¶
- 반복 가능한 자료형을 입력받아 튜플 형태로 바꾸어 돌려주는 함수
- 만약 튜플이 입력을 들어오면 그대로 돌려줌
tuple("abc")
('a', 'b', 'c')
tuple([1,2,3])
(1, 2, 3)
tuple((1,2,3))
(1, 2, 3)
type(object)¶
- 입력값의 자료형이 무엇인지 알려주는 함수
type("abc")
str
type([])
list
type(open("test", 'w'))
_io.TextIOWrapper
zip(*iterable)¶
- 동일한 개수로 이루어진 자료형을 묶어 주는 역할을 하는 함수
- *iterable : 반복 가능(iter-able)한 자료형 여러 개를 입력할 수 있다는 의미
list(zip([1,2,3], [4,5,6]))
[(1, 4), (2, 5), (3, 6)]
list(zip([1,2,3],[4,5,6],[7,8,9]))
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]
list(zip("abc", "def"))
[('a', 'd'), ('b', 'e'), ('c', 'f')]
5-6 라이브러리¶
sys¶
- 파이썬 인터프리터가 제공하는 변수와 함수를 직접 제어할 수 있게 해주는 모듈
명령 행에서 인수 전달 - sys.argv¶
>> python test.py abc pey guido
명령 프롬프트 창에서 위과 같이 test.py 뒤에 또 다른 값을 함께 넣어주면 sys.argv 리스트에 그 값 추가
- 예제
argv_test.py 파일은 C:/Users/user/Mymod 디렉터리에 저장했다고 가정
#argv_test.py
import sys
print(sys.argv)
명령 프롬프트 창에서 Mymod 디렉토리로 들어간 뒤 다음과 같이 실행
C:/Users/user/Mymod> python argv_test.py you need python
['argv_test.py', 'you', 'need', 'python']
python 명령어 뒤의 모든 것들이 공백을 기준으로 나뉘어서 sys.argv 리스트의 요소가 된다.
강제로 스크립트 종료 - sys.exit¶
>>> sys.exit()
자신이 만든 모듈 불러와 사용 - sys.path¶
- sys.path는 파이썬 모듈들이 저장되어 있는 위치를 나타냄
- 즉, 이 위치에 있는 파이썬 모듈은 경로에 상관없이 어디에서나 불러올 수 있다.
>>> import sys
>>> sys.path
['', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\python310.zip', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\DLLs', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\lib', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\win32', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\win32\\lib', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\Pythonwin']
위 예에서 ''는 현재 디렉터리를 말한다.
#path_append.py
import sys
sys.path.append("C:/Users/user/Mymod")
위와 같이 파이썬 프로그램 파일에서 sys.path.append를 사용해 경로 이름을 추가할 수 있다.
이렇게 하고 난 후에는 C:/Users/user/Mymod 디렉터리에 있는 파이썬 모듈을 불러와서 사용 가능
pickle¶
- 객체의 형태를 그대로 유지하면서 파일에 저장하고 불러올 수 있게 하는 모듈
- pickle 모듈의 dump 함수를 사용해 딕셔너리 객체인 data를 그대로 파일에 저장하는 방법
import pickle
f = open("test.txt", 'wb')
data = {1:'python', 2: 'you need'}
pickle.dump(data, f)
f.close()
- pickle.dump로 저장한 파일을 pickle.load를 사용해서 원래 있던 딕셔너리 객체(data) 상태 그대로 불러오기
import pickle
f = open("test.txt", 'rb')
data = pickle.load(f)
print(data)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100]
위 예에서는 딕셔너리 객체를 사용했지만 어떤 자료형이든 저장하고 불러오기 가능
# 추가
my_list = ["a", "b", "c"]
with open("data.pickle", "wb") as f:
pickle.dump(my_list, f)
import pickle
with open("data2.pickle", "wb") as fw:
pickle.dump(b, fw)
with open('data2.pickle', 'rb') as fr:
df = pickle.load(fr)
print(df)
OS¶
- OS모듈은 환경 변수나 디렉터리, 파일 등의 OS 자원을 제어할 수 있게 해주는 모듈
내 시스템의 환경 변수 값을 알고 싶을 때 - os.environ¶
- 시스템은 제각기 다른 환경 변수 값을 가지고 있는데, os.environ은 현재 시스템의 환경 변수 값을 보여줌.
import os
os.environ
environ{'ALLUSERSPROFILE': 'C:\\ProgramData', 'APPDATA': 'C:\\Users\\user\\AppData\\Roaming', 'COMMONPROGRAMFILES': 'C:\\Program Files\\Common Files', 'COMMONPROGRAMFILES(X86)': 'C:\\Program Files (x86)\\Common Files', 'COMMONPROGRAMW6432': 'C:\\Program Files\\Common Files', 'COMPUTERNAME': 'DESKTOP-2PGRMF4', 'COMSPEC': 'C:\\windows\\system32\\cmd.exe', 'DRIVERDATA': 'C:\\Windows\\System32\\Drivers\\DriverData', 'FPS_BROWSER_APP_PROFILE_STRING': 'Internet Explorer', 'FPS_BROWSER_USER_PROFILE_STRING': 'Default', 'HOMEDRIVE': 'C:', 'HOMEPATH': '\\Users\\user', 'JAVA_HOME': 'C:\\Program Files\\Amazon Corretto\\jdk11.0.18_10', 'LOCALAPPDATA': 'C:\\Users\\user\\AppData\\Local', 'LOGONSERVER': '\\\\DESKTOP-2PGRMF4', 'NUMBER_OF_PROCESSORS': '12', 'ONEDRIVE': 'C:\\Users\\user\\OneDrive', 'OS': 'Windows_NT', 'PATH': 'C:\\Program Files\\Amazon Corretto\\jdk11.0.18_10\\bin;C:\\windows\\system32;C:\\windows;C:\\windows\\System32\\Wbem;C:\\windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\windows\\System32\\OpenSSH\\;C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\Scripts\\;C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\;C:\\Users\\user\\AppData\\Local\\Microsoft\\WindowsApps;', 'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC', 'PROCESSOR_ARCHITECTURE': 'AMD64', 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 167 Stepping 1, GenuineIntel', 'PROCESSOR_LEVEL': '6', 'PROCESSOR_REVISION': 'a701', 'PROGRAMDATA': 'C:\\ProgramData', 'PROGRAMFILES': 'C:\\Program Files', 'PROGRAMFILES(X86)': 'C:\\Program Files (x86)', 'PROGRAMW6432': 'C:\\Program Files', 'PROMPT': '$P$G', 'PSMODULEPATH': 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\windows\\system32\\WindowsPowerShell\\v1.0\\Modules', 'PUBLIC': 'C:\\Users\\Public', 'SESSIONNAME': 'Console', 'SYSTEMDRIVE': 'C:', 'SYSTEMROOT': 'C:\\windows', 'TEMP': 'C:\\Users\\user\\AppData\\Local\\Temp', 'TMP': 'C:\\Users\\user\\AppData\\Local\\Temp', 'USERDOMAIN': 'DESKTOP-2PGRMF4', 'USERDOMAIN_ROAMINGPROFILE': 'DESKTOP-2PGRMF4', 'USERNAME': 'user', 'USERPROFILE': 'C:\\Users\\user', 'WINDIR': 'C:\\windows', 'ZES_ENABLE_SYSMAN': '1', 'PYDEVD_USE_FRAME_EVAL': 'NO', 'JPY_SESSION_NAME': 'C:\\Users\\user\\New\\0309review.ipynb', 'JPY_INTERRUPT_EVENT': '3216', 'IPY_INTERRUPT_EVENT': '3216', 'JPY_PARENT_PID': '3236', 'TERM': 'xterm-color', 'CLICOLOR': '1', 'FORCE_COLOR': '1', 'CLICOLOR_FORCE': '1', 'PAGER': 'cat', 'GIT_PAGER': 'cat', 'MPLBACKEND': 'module://matplotlib_inline.backend_inline'}
위 결괏값은 필자의 시스템 정보
os.environ은 환경 변수에 대한 정보를 딕셔너리 객체로 돌려줌
돌려받은 객체가 딕셔너리이기 때문에 다음과 같이 호출 가능
- 필자 시스템의 PATH 환경 변수 내용
os.environ['PATH']
'C:\\Program Files\\Amazon Corretto\\jdk11.0.18_10\\bin;C:\\windows\\system32;C:\\windows;C:\\windows\\System32\\Wbem;C:\\windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\windows\\System32\\OpenSSH\\;C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\Scripts\\;C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\;C:\\Users\\user\\AppData\\Local\\Microsoft\\WindowsApps;'
현재 디렉터리 위치 변경 - os.chdir¶
os.chdir("C:/WINDOWS")
현재 디렉터리 위치 돌려받기 - os.getcwd¶
os.getcwd()
'C:\\WINDOWS'
시스템 명령어 호출 - os.system¶
- 시스템 자체의 프로그램이나 기타 명령어를 파이썬에서 호출할 수도 있다.
- os.system("명령어")
- 현재 디렉터리에서 시스템 명령어 dir 실행하기
os.system("dir")
0
실행한 시스템 명령어의 결괏값 돌려받기 - os.popen¶
- os.popen은 시스템 명령어를 실행한 결괏값을 읽기 모드 형태의 파일 객체로 돌려줌
f = os.popen("dir")
- 읽어 들인 파일 객체의 내용 보기
print(f.read())
기타 유용한 os 관련 함수¶
함수 | 설명 |
---|---|
os.mkdir(디렉터리) | 디렉터리 생성 |
os.rmdir(디렉터리) | 디렉터리 삭제. 단 디렉터리가 비어있어야 삭제 가능 |
os.unlink(파일 이름) | 파일을 지운다 |
os.rename(src,dst) | src라는 이름의 파일을 dst라는 이름으로 바꾼다. |
shutil¶
- 파일을 복사해 주는 파이썬 모듈
src라는 이름의 파일을 dst로 복사하기
- dst가 디렉터리 이름일 경우 : src라는 파일 이름으로 dst 디렉터리에 복사
- 동일한 파일 이름이 있을 경우 : 덮어쓰기
import shutil
shutil.copy("src.txt", "dst.txt")
'dst.txt'
위 예를 실행하면 src.txt 파일과 동일한 내용의 파일이 dst.txt로 복사됨
glob¶
- 가끔 파일을 읽고 쓰는 기능이 있는 프로그램을 만들다 보면 특정 디렉터리에 있는 파일 이름 모두를 알아야 할 때가 있다.
- 이럴 때 사용하는 모듈이 바로 glob
디렉터리에 있는 파일들을 리스트로 만들기 - glob(pathname)¶
- glob 모듈은 디렉터리 안의 파일들을 읽어서 돌려준다. *, ? 등 메타 문자를 써서 원하는 파일만 읽어 들일 수도 있다.
- C:/Users/user/test 디렉터리에 있는 파일 중 이름이 sys로 시작하는 파일을 모두 찾아서 읽어들이기
import os
os.chdir("C:/Users/user/test")
import glob
glob.glob("sys*")
['sys1.py', 'sys2.py']
tempfile¶
- 파일을 임시로 만들어서 사용할 때 유용한 모듈
- tempfile.mkstemp() : 중복되지 않는 임시 파일의 이름을 무작위로 만들어서 돌려줌
import tempfile
filename = tempfile.mkstemp()
filename
(3, 'C:\\Users\\user\\AppData\\Local\\Temp\\tmpodg2iu2y')
tempfile.TemporaryFile()¶
- 임시 저장 공간으로 사용할 파일 객체를 돌려줌
- 이 파일은 기본적으로 바이너리 쓰기 모드(wb)를 가짐
- f.close()가 호출되면 이 파일 객체는 자동으로 사라짐
import tempfile
f = tempfile.TemporaryFile()
f.close() # 생성한 임시 파일 자동 삭제
time¶
- 시간과 관련된 time 모듈에는 함수가 굉장히 많다. 그 중 가장 유용한 몇 가지만 살펴보자
time.time¶
- UTC(Universal Time Coordinated 협정 세계 표준시)를 사용해 현재 시간을 실수 형태로 돌려주는 함수
- 1970년 1월 1일 0시 0분 0초를 기준으로 지난 시간을 초 단위로 돌려줌
import time
time.time()
1679559502.4437962
time.time()/60
time.time()/60/60
time.time()/60/60/24 #며칠
time.time()/60/60/24/30 #몇 달
time.time()/60/60/24/30/12 # 몇 년
53.981645794929086
time.localtime¶
- time.time()이 돌려준 실수 값을 사용해 연도, 월, 일, 시, 분, 초, ...의 형태로 바꾸어주는 함수
time.localtime(time.time())
time.struct_time(tm_year=2023, tm_mon=3, tm_mday=23, tm_hour=17, tm_min=18, tm_sec=25, tm_wday=3, tm_yday=82, tm_isdst=0)
t = time.localtime()
print(t.tm_year, "년", t.tm_mday, "일")
2023 년 23 일
time.asctime¶
- 위 time.localtime에 의해서 반환된 튜플 형태의 값을 인수로 받아서 날짜와 시간을 알아보기 쉬운 형태로 돌려주는 함수
time.asctime(time.localtime(time.time()))
'Thu Mar 23 17:18:30 2023'
time.ctime¶
- time.asctime(time.localtime(tim.time()))은 time.ctime()을 사용해 간편하게 표시 가능
- asctime과 다른 점은 ctime은 항상 현재 시간만을 돌려줌
time.ctime()
'Thu Mar 23 17:18:53 2023'
strftime과 strptime¶
- strftime : 날짜와 시간(datetime)을 문자열로 출력
- strptime : 날짜와 시간 형식의 문자열을 datetime으로 변환
time.strftime¶
time.strftime('출력할 형식 포맷 코드', time.localtime(time.time()))
- strftime 함수는 시간에 관계된 것을 세밀하게 표현하는 여러 포맷 코드를 제공
코드 | 설명 | 예 |
---|---|---|
%a | 요일 줄임말 | Mon |
%A | 요일 | Monday |
%b | 달 줄임말 | Jan |
%B | 달 | January |
%c | 날짜와 시간 출력 | Thu Mar 23 17:34:23 2023 |
%d | 날(day) | [01,31] |
%H | 시간(hour):24시간 출력 형태 | [00,23] |
%I | 시간(hour):12시간 출력 형태 | [01,12] |
%j | 1년 중 누적 날짜 | [001,366] |
%m | 달 | [01,12] |
%M | 분 | [01,59] |
%p | AM or PM | AM |
%S | 초 | [00,59] |
%U | 1년 중 누적 주 : 일요일을 시작으로 | [00,53] |
%w | 숫자로 된 요일 | [0(일요일),6] |
%W | 1년 중 누적 주-월요일을 시작으로 | [00,53] |
%x | 현재 설정된 지역에 기반한 날짜 출력 | 06/01/01(월/일/년) |
%X | 현재 설정된 지역에 기반한 시간 출력 | 17:22:21 |
%Y | 연도 출력 | 2001 |
%Z | 시간대 출력 | 대한민국 표준시 |
%% | 문자 | % |
%y | 세기 부분을 제외한 연도 출력 | 01 |
- time.strftime을 사용하는 예시
import time
time.strftime('%x', time.localtime(time.time()))
'03/23/23'
time.strftime('%c', time.localtime(time.time()))
'Thu Mar 23 17:34:23 2023'
import datetime
now = datetime.datetime.now()
date = now.strftime('%Y-%m-%d')
date
'2023-03-17'
time = now.strftime('%H:%M:%S')
time
'18:30:07'
datetime = now.strftime('%Y-%m-%d %H:%M:%S')
datetime
'2023-03-17 18:30:07'
time = now.strftime('')
time.strptime¶
- datetime.strptime(문자열, 형식)
import datetime
str_datetime = '2021-04-08 21:31:48'
currdate = datetime.datetime.strptime(str_datetime, "%Y-%m-%d %H:%M:%S")
print(type(currdate))
<class 'datetime.datetime'>
time.sleep¶
- 주로 루프 안에서 많이 사용
- 이 함수를 사용하면 일정한 시간 간격을 두고 루프 실행 가능
import time
for i in range(10):
print(i)
time.sleep(1)
0 1 2 3 4 5 6 7 8 9
위 예는 1초 간격으로 0부터 9까지의 숫자 출력
위 예에서 볼 수 있듯이 time.sleep함수의 인수는 실수 형태 사용 가능
즉, 1이면 1초, 0.5면 0.5초가 된다.
calendar¶
- 파이썬에서 달력을 볼 수 있게 해주는 모듈
calendar.calendar(연도)¶
- 그 해의 전체 달력을 볼 수 있음
import calendar
print(calendar.calendar(2023))
2023 January February March Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 1 2 3 4 5 1 2 3 4 5 2 3 4 5 6 7 8 6 7 8 9 10 11 12 6 7 8 9 10 11 12 9 10 11 12 13 14 15 13 14 15 16 17 18 19 13 14 15 16 17 18 19 16 17 18 19 20 21 22 20 21 22 23 24 25 26 20 21 22 23 24 25 26 23 24 25 26 27 28 29 27 28 27 28 29 30 31 30 31 April May June Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 2 1 2 3 4 5 6 7 1 2 3 4 3 4 5 6 7 8 9 8 9 10 11 12 13 14 5 6 7 8 9 10 11 10 11 12 13 14 15 16 15 16 17 18 19 20 21 12 13 14 15 16 17 18 17 18 19 20 21 22 23 22 23 24 25 26 27 28 19 20 21 22 23 24 25 24 25 26 27 28 29 30 29 30 31 26 27 28 29 30 July August September Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 2 1 2 3 4 5 6 1 2 3 3 4 5 6 7 8 9 7 8 9 10 11 12 13 4 5 6 7 8 9 10 10 11 12 13 14 15 16 14 15 16 17 18 19 20 11 12 13 14 15 16 17 17 18 19 20 21 22 23 21 22 23 24 25 26 27 18 19 20 21 22 23 24 24 25 26 27 28 29 30 28 29 30 31 25 26 27 28 29 30 31 October November December Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 1 2 3 4 5 1 2 3 2 3 4 5 6 7 8 6 7 8 9 10 11 12 4 5 6 7 8 9 10 9 10 11 12 13 14 15 13 14 15 16 17 18 19 11 12 13 14 15 16 17 16 17 18 19 20 21 22 20 21 22 23 24 25 26 18 19 20 21 22 23 24 23 24 25 26 27 28 29 27 28 29 30 25 26 27 28 29 30 31 30 31
calendar.prcal(연도)¶
- 위와 똑같은 결괏값 출력
calendar.prcal(2023)
2023 January February March Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 1 2 3 4 5 1 2 3 4 5 2 3 4 5 6 7 8 6 7 8 9 10 11 12 6 7 8 9 10 11 12 9 10 11 12 13 14 15 13 14 15 16 17 18 19 13 14 15 16 17 18 19 16 17 18 19 20 21 22 20 21 22 23 24 25 26 20 21 22 23 24 25 26 23 24 25 26 27 28 29 27 28 27 28 29 30 31 30 31 April May June Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 2 1 2 3 4 5 6 7 1 2 3 4 3 4 5 6 7 8 9 8 9 10 11 12 13 14 5 6 7 8 9 10 11 10 11 12 13 14 15 16 15 16 17 18 19 20 21 12 13 14 15 16 17 18 17 18 19 20 21 22 23 22 23 24 25 26 27 28 19 20 21 22 23 24 25 24 25 26 27 28 29 30 29 30 31 26 27 28 29 30 July August September Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 2 1 2 3 4 5 6 1 2 3 3 4 5 6 7 8 9 7 8 9 10 11 12 13 4 5 6 7 8 9 10 10 11 12 13 14 15 16 14 15 16 17 18 19 20 11 12 13 14 15 16 17 17 18 19 20 21 22 23 21 22 23 24 25 26 27 18 19 20 21 22 23 24 24 25 26 27 28 29 30 28 29 30 31 25 26 27 28 29 30 31 October November December Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 1 2 3 4 5 1 2 3 2 3 4 5 6 7 8 6 7 8 9 10 11 12 4 5 6 7 8 9 10 9 10 11 12 13 14 15 13 14 15 16 17 18 19 11 12 13 14 15 16 17 16 17 18 19 20 21 22 20 21 22 23 24 25 26 18 19 20 21 22 23 24 23 24 25 26 27 28 29 27 28 29 30 25 26 27 28 29 30 31 30 31
calendar.prmonth(월)¶
- 2023년 12월의 달력만 출력
calendar.prmonth(2023, 12)
December 2023 Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
calendar.weekday(연도, 월, 일)¶
- 그 날짜에 해당하는 요일 정보 출력
- 월요일: 0, 화요일: 1, 수요일: 2, 목요일: 3, 금요일: 4, 토요일: 5, 일요일: 6
calendar.weekday(2023,12,31)
6
calendar.monthrange(연도, 월)¶
- 입력받은 달의 1일이 무슨 요일인지와 그 달이 며칠가지 있는지를 튜플 형태로 돌려줌
calendar.monthrange(2023, 12)
(4, 31)
위 예는 2023년 12월 1일은 금요일이고, 이 달은 31일까지 있다는 것을 보여줌
날짜 관련 프로그래밍을 할 때 위 2가지 함수는 매우 유용하게 사용됨
random¶
- 난수(규칙이 없는 임의의 수)를 발생시키는 모듈
- random, randint
random.random()¶
- 0부터 1사이의 랜덤 실수 리턴
import random
random.random() # Random float x, 0.0 <= x < 1.0
0.24893784658835794
random.randint¶
- 2개 숫자 사이의 랜덤 정수 리턴(2번째 인자로 넘어온 정수도 범위에 포함)
- 1에서 10 사이의 정수 중 난수 값을 돌려줌
random.randint(1,10) # Integer from 1 to 10, endpoints included
4
- 1에서 55사이의 정수 중에서 난수 값을 돌려줌
random.randint(1,55)
20
- random 모듈을 사용한 함수 만들기
import random
def random_pop(data):
number = random.randint(0,len(data)-1)
return data.pop(number)
if __name__=="__main__":
data=[1,2,3,4,5]
while data:
print(random_pop(data))
2 3 5 1 4
위 random_pop 수는 리스트의 요소 중 무작위를 하나 선택해 꺼낸 후 그 값을 돌려줌.
꺼낸 요소는 pop 메서드에 의해 사라짐
random.shuffle¶
- 리스트의 항목을 무작위로 섞고 싶을 때 사용
import random
data = [1,2,3,4,5]
random.shuffle(data)
data
[2, 1, 5, 3, 4]
[1,2,3,4,5] 리스트가 shuffle 함수에 의해 섞여서 [2,1,5,3,4]로 변함
random.uniform()¶
- 2개의 숫자 사이의 랜덤 실수 리턴
random.uniform(1,10) # Random float x, 1.0 <= x < 10.0
2.520366318317702
choice, choices, sample¶
- random.choice: 랜덤으로 요소 하나 취득
- random.choices : 랜덤으로 요로 여러 개 취득. 중복 O
- random.sample: 랜덤으로 요소 여러 개 취득. 중복 X
random.choice()¶
- 랜덤하게 하나의 원소 선택
import random
l = [0,1,2,3,4]
print(random.choice(l))
2
random.choice('abcdefghi') # Choose a random element
'g'
- 튜플이나 문자열에서도 choice 함수를 사용해 문자를 랜덤하게 취득 가능
import random
print(random.choice(('xxx','yyy','zzz')))
print(random.choice('abcde'))
yyy d
- 주의점 : 공백 리스트나 튜플 또는 문자열에 choice 함수를 사용하면 에러 발생
import random
print(random.choice([]))
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) Cell In[62], line 2 1 import random ----> 2 print(random.choice([])) File ~\AppData\Local\Programs\Python\Python310\lib\random.py:378, in Random.choice(self, seq) 376 """Choose a random element from a non-empty sequence.""" 377 # raises IndexError if seq is empty --> 378 return seq[self._randbelow(len(seq))] IndexError: list index out of range
random.choices()¶
- 형식: choices(리스트, k =취득개수)
- choices 함수의 첫 번째 파라미터 : 대상이 되는 리스트
- choices 함수의 두 번재 파라미터 : 랜덤으로 취득하고 싶은 요소 개수 k
import random
l = [0,1,2,3,4]
print(random.choices(l, k=3))
[0, 1, 2]
choices 함수를 사용해 취득한 결과를 보면 추출 대상 리스트에는 중복된 값을 지정하지 않았지만 중복된 값이 표시되어 있음
sample 함수와 다르게 choices 함수는 한번 추출한 요소를 제외시키지 않음
그래서 추출 대상 리스트의 요소수보다 랜덤하게 취득하고 싶은 요소를 크게 지정해도 에러가 발생하지 않음
import random
l = [0,1,2,3,4]
print(random.choices(l,k=10))
[1, 0, 1, 4, 0, 2, 2, 3, 3, 1]
추출 대상 리스트에는 요소가 5개 있지만 랜덤으로 10개 추출 가능
k를 생략할 경우 기본값으로 1 지정
random.sample()¶
- 랜덤하게 여러 개의 원소 선택
- sample로 랜덤하게 취득한 값은 중복되지 않음
- 형식
sample(리스트, 취득 개수)
sample 함수의 첫번째 파라미터 : 추출 대상이 되는 리스트
sample 함수의 두번째 파라미터 : 랜덤으로 취득하고 싶은 요소 개수
random.sample([1,2,3,4,5],3) # Choose 3 elements
[4, 5, 3]
#반환한 데이터 타입 확인
a = random.sample([1,2,3,4,5],3)
type(a)
list
sample을 사용해 취득한 결과값은 리스트 형태로 반환
결과값이 없는 경우에도 리스트 형태로 반환
import random
print(random.sample([0,1,2,3,4],0))
[]
- 취득하고 싶은 요소 개수가 추출 대상 리스트 요소수보다 큰 경우 에러발생
import random
l = [0,1,2,3,4]
print(random.sample(l,10))
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[65], line 3 1 import random 2 l = [0,1,2,3,4] ----> 3 print(random.sample(l,10)) File ~\AppData\Local\Programs\Python\Python310\lib\random.py:482, in Random.sample(self, population, k, counts) 480 randbelow = self._randbelow 481 if not 0 <= k <= n: --> 482 raise ValueError("Sample larger than population or is negative") 483 result = [None] * k 484 setsize = 21 # size of a small set minus size of an empty list ValueError: Sample larger than population or is negative
- sample 함수에도 튜플이나 문자열 지정 가능
import random
print(random.sample(('xxx','yyy','zzz'),2))
print(random.sample('abcde', 2))
['zzz', 'xxx'] ['a', 'c']
random.randrange()¶
- range(start, stop, step) 함수로 만들어지는 정수 중 하나를 랜덤하게 리턴
random.randrange(0,101,2) # Even integer from 0 to 100
random.sample() : 중복없이
random.shuffle()
random.choices() : k개 복원추출(중복가능)
random.randint(10,15) : 정수 1개 임의출력,
10~15사이의 정수 1개 출력?
random.random.random() : 0초과 1미만의 실수 중 1개 임의 출력
random.uniform(10,15) : 10~15 사이의 실수 1개 출력?
webbrowser¶
- 자신의 시스템에서 사용하는 기본 웹 브라우저를 자동으로 실행하는 모듈
webbrowser.open¶
- 웹 브라우저가 이미 실행된 상태 : 입력 주소로 이동
- 웹 브라우저가 실행되지 않은 상태 : 새로 웹 브라우저 실행 후 해당 주소로 이동
- 다음 예제는 웹 브라우저를 자동으로 실행하고 해당 URL인 google.com으로 가게 함
import webbrowser
webbrowser.open("http://google.com")
True
webbrowser.open_new¶
- 이미 웹브라우저가 실행된 상태이더라도 새로운 창으로 해당 주소가 열리게 함
webbrowser.open_new("http://google.com")
True
스레드를 다루는 threading 모듈¶
- 프로세스 : 컴퓨터에서 동작하고 있는 프로그램
- 보통 1개의 프로세스는 한 가지 일만 하지만 스레드(Thread)를 사용하면 한 프로세스 안에서 2가지 또는 그 이상의 일을 동시에 수행 가능
import time
def long_task(): # 5초의 시간이 걸리는 함수
for i in range(5):
time.sleep(1) # 1초간 대기
print("working:%s\n" % i)
print("Start")
for i in range(5):
long_task()
print("End")
Start working:0 working:1 working:2 working:3 working:4 working:0 working:1 working:2 working:3 working:4 working:0 working:1 working:2 working:3 working:4 working:0 working:1 working:2 working:3 working:4 working:0 working:1 working:2 working:3 working:4 End
long_task 함수 : 수행하는 데 5초의 시간이 걸리는 함수
위 프로그램은 이 함수를 총 5번 반복해서 수행하는 프로그램.
이 프로그램은 5초가 5번 반복되니 총 25초의 시간이 걸림.
하지만 스레드를 사용하면 5초의 시간이 걸리는 long_task 함수를 동시에 실행할 수 있으니 시간을 줄일 수 있다.
- 스레드를 사용해 수정한 프로그램
import time
import threading # 스레드 생성을 위해서는 threading 모듈 필요
def long_task():
for i in range(5):
time.sleep(1)
print("working:%s\n" % i)
print("Start")
threads = []
for i in range(5):
t = threading.Thread(target=long_task) # 스레드 생성
threads.append(t)
for t in threads:
t.start() # 스레드 실행
print("End")
Start End working:0 working:0 working:0 working:0 working:0 working:1 working:1 working:1 working:1 working:1 working:2 working:2 working:2 working:2 working:2 working:3 working:3 working:3 working:3 working:3 working:4 working:4 working:4 working:4 working:4
이와 같이 프로그램을 수정 후 실행해 보면 25초 걸리던 작업이 5초 정도에 수행된다.
threading.Thread를 사용해 만든 스레드 객체가 동시 작업을 가능하게 해 주기 때문
하지만 위 프로그램을 실행 시 "Start"와 "End"가 먼저 출력되고 그 이후에 스레드의 결과가 출력됨. 또한 프로그램이 정상 종료되지 않음.
우리가 기대하는 것은 "Start"가 출력되고 그 다음에 스레드의 결과 출력 후 마지막으로 "End"가 출력되는 것
- 문제 해결을 위해 수정한 프로그램
import time
import threading
def long_task():
for i in range(5):
time.sleep(1)
print("working:%s\n" % i)
print("Start")
threads = []
for i in range(5):
t = threading.Thread(target=long_task)
threads.append(t)
for t in threads:
t.start()
for t in threads:
t.join() # join으로 스레드가 종료될 때까지 기다림
print("End")
Start working:0 working:0 working:0 working:0 working:0 working:1 working:1 working:1 working:1 working:1 working:2 working:2 working:2 working:2 working:2 working:3 working:3 working:3 working:3 working:3 working:4 working:4 working:4 working:4 working:4 End
스레드의 join함수는 해당 스레드가 종료될 때까지 기다리게 함.
따라서 위와 같이 수정하면 우리가 원하던 출력을 보게 됨.
6장 파이썬 프로그래밍, 어떻게 시작해야 할까?¶
6-1 내가 프로그램을 만들 수 있을까?¶
구구단 만들기¶
#답1.
def GuGu(n):
result = []
for i in range(1,10):
result.append(n*i)
return result
print(GuGu(2))
[2, 4, 6, 8, 10, 12, 14, 16, 18]
def GuGu(n):
result = []
i = 1
while i < 10:
result.append(n*i)
i = i + 1
return result
print(GuGu(2))
[2, 4, 6, 8, 10, 12, 14, 16, 18]
6-2 3과 5의 배수 합하기¶
result = 0
for n in range(1,1000):
if n%3 == 0 or n%5 == 0:
result += n
print(result)
233168
- 15와 같은 수를 이중으로 더하여 잘못된 결과를 출력하는 경우
result = 0
for n in range(1,1000):
if n%3 == 0:
result += n
if n%5 == 0:
result += n
print(result)
266333
- 코딩연습사이트
6-3 게시판 페이징하기¶
게시판 프로그램 만들기¶
- 게시물의 총 건수와 한 페이지에 보여 줄 게시물 수를 입력으로 주었을 때 총 페이지 수 출력
def getTotalPage(m,n):
return m // n + 1
print(getTotalPage(5,10)) # 첫 번째 케이스, 1 출력
print(getTotalPage(15,10)) # 두 번째 케이스, 2 출력
print(getTotalPage(25,10)) # 세 번째 케이스, 3 출력
print(getTotalPage(30,10)) # 네 번째 케이스, 3이 출력되어야 하는데 4가 출력
1 2 3 4
- 코드 변경
def getTotalPage(m,n):
if m % n == 0:
return m // n
else:
return m // n + 1
print(getTotalPage(5,10))
print(getTotalPage(15,10))
print(getTotalPage(25,10))
print(getTotalPage(30,10))
1 2 3 3
6-4 간단한 메모장 만들기¶
- 원하는 메모를 파일에 저장하고 추가 및 조회가 가능한 간단한 메모장을 만들어 보자.
- 입력으로 받은 옵션과 메모를 출력하는 코드 작성
# memo.py
import sys
option = sys.argv[1]
memo = sys.argv[2]
print(option)
print(memo)
-f C:\Users\user\AppData\Roaming\jupyter\runtime\kernel-63ce7524-6808-449b-b6ca-b1a52ad2b60d.json
# 다음 명령 수행
>>python memo.py -a "Life is too short"
-a
Life is too short
Cell In[2], line 2 python memo.py -a "Life is too short" ^ SyntaxError: invalid syntax
- 입력으로 받은 메모를 파일에 쓰도록 코드 변경
# memo.py
import sys
option = sys.argv[1]
if option == '-a':
memo = sys.argv[2]
f = open('memo.txt', 'a')
f.write(memo)
f.write('\n')
f.close()
다시 명령어를 수행하면 추가한 메모가 정상적으로 저장
- 메모 출력 코드
#memo.py
import sys
option = sys.argv[1]
if option == '-a':
memo = sys.argv[2]
f = open('memo.txt', 'a')
f.write(memo)
f.write('\n')
f.close()
elif option == '-v':
f = open('memo.txt')
memo = f.read()
f.close()
print(memo)
>> python memo.py -v
Life is too short
입력한 메모가 그대로 출력
6-5 탭을 4개의 공백을 바꾸기¶
- 스크립트
필요한 기능은? 문서 파일 읽어 들이기, 문자열 변경
입력받는 값은? 탭을 포함한 문서 파일
출력하는 값은? 탭이 공백으로 수정된 문서 파일
7장 정규표현식¶
7-1 정규표현식 살펴보기¶
정규표현식은 왜 필요한가?¶
- 주민등록번호를 포함하고 있는 텍스트가 있다. 이 텍스트에 포함된 모든 주민등록번호의 뒷자리를 * 문자로 변경해 보자.
# 정규표현식 없이 작성
data = """
park 800905-1049118
kim 700905-1059119
"""
result = []
for line in data.split("\n"):
word_result = []
for word in line.split(" "):
if len(word) == 14 and word[:6].isdigit() and word[7:].isdigit():
word = word[:6] + "-" + "*******"
word_result.append(word)
result.append(" ".join(word_result))
print("\n".join(result))
park 800905-******* kim 700905-*******
- 정규표현식 사용해 코드 작성
import re
data = """
park 800905-1049118
kim 700905-1059119
"""
pat = re.compile("(\d{6})[-]\d{7}")
print(pat.sub("\g<1>-*******", data))
park 800905-******* kim 700905-*******
7-2 정규 표현식 시작하기¶
정규 표현식의 기초, 메타 문자¶
- .^$+?{}[]|()
문자 클래스¶
- [] 사이의 문자들과 매치
- ex) [abc] = 'a,b,c 중 한 개의 문자와 매치'
- [] 안의 두 문자 사이에 하이픈(-) 사용 = 두 문자 사이의 범위(From - To)
- ex) [a-c] = [abc]
[0-5] = [012345]
- [a-zA-Z]: 알파벳 모두
- ^ : 반대(not)의 의미
- ex) [^0-9] : 숫자가 아닌 문자만 매치
자주 사용하는 문자 클래스¶
정규표현식 | 설명 |
---|---|
\d | 숫자와 매치, [0-9]와 동일 |
\D | 숫자가 아닌 것과 매치, [^0-9]와 동일 |
\s | whitespace 문자(space나 tab처럼 공백을 표현하는 문자)와 매치, [/t/n/r/f/v]와 동일. 맨 앞의 빈칸은 공백 문자(space)를 의미 |
\S | whitespace 문자가 아닌 것과 매치, [^/t/n/r/f/v]와 동일 |
\w | 문자+숫자(alphanumeric)와 매치, [a-zA-Z0-9_]와 동일 |
\W | 문자+숫자(alphanumeric)가 아닌 문자와 매치, [^a-zA-Z0-9_]와 동일 |
Dot(.)¶
- \n을 제외한 모든 문자와 매치
- re.DOTALL 옵션을 주면 \n 문자와도 매치
a.b # a와 b 사이에 줄바꿈 문자를 제외한 어떤 문자가 들어가도 모두 매치
"a + 모든 문자 + b"
a[.]b # a와 b 사이에 Dot(.) 문자가 있으면 매치
"a + Dot(.)문자 + b"
반복(*) : 0번 이상¶
ca*t # 문자 바로 앞에 있는 a가 0번 이상 반복되면 매치
은 바로 앞에 있는 문자 a가 0부터 무한대로 반복될 수 있다는 의미
반복(+) : 1번 이상¶
- +는 최소 1번 이상 반복될 때 사용
- *은 반복 횟수 0부터
- +은 반복 횟수 1부터
ca+t # 문자 바로 앞에 있는 a가 1번 이상 반복되면 매치
"c + a(1번 이상 반복) + t"
반복({m,n}, ?)¶
- {} 메타 문자를 사용하면 반복 횟수 고정 가능
- {m,n} 정규식을 사용하면 반복 횟수가 m부터 n까지 매치 가능
- m 또는 n을 생략 가능
- 생략된 m은 0과 동일, 생략된 n은 무한대(2억 개 미만)의 의미
- {3,} : 반복 횟수 3 이상
- {,3} : 반복 횟수 3 이하
- {1,}은 + 와 동일
- {0,}은 * 와 동일
1. {m}¶
ca{2}t #a가 2번 반복되면 매치
"c + a(반드시 2번 반복) + t"
2. {m,n}¶
ca(2,5)t # a가 2~5번 반복되면 매치
"c + a(2~5번 반복) + t"
3. ?¶
- {0,1}을 의미
ab?c # b가 0~1번 사용되면 매치
"a + b(있어도 되고 없어도 된다) + c"
지금까지 아주 기초적인 정규 표현식에 대해 알아보았다.
이제 파이썬으로 이러한 정규 표현식을 어떻게 사용할 수 있는지 먼저 알아보자.
파이썬에서 정규 표현식을 지원하는 re 모듈¶
- 파이썬은 정규 표현식을 지원하기 위해 re(regular expression의 약어) 모듈을 제공
- 파이썬을 설치할 때 자동으로 설치되는 기본 라이브러리
- re 모듈 사용 방법
import re
p = re.compile('ab*')
re.compile을 사용하여 정규 표현식(위 예에서는 ab)을 컴파일
**re.compile***의 결과로 돌려주는 객체 p(컴파일된 패턴 객체)를 사용하여 그 이후의 작업 수행 가능
정규식을 사용한 문자열 검색¶
- 이제 컴파일된 패턴 객체를 사용해 문자열 검색을 수행해 보자.
- 컴파일된 패턴 객체는 다음과 같은 4가지 메서드를 제공
메서드 | 목적 |
---|---|
match() | 문자열의 처음부터 정규식과 매치되는지 조사 |
search() | 문자열 전체를 검색하여 정규식과 매치되는지 조사 |
findall() | 정규식과 매치되는 모든 문자열(substring)을 리스트로 돌려줌 |
finditer() | 정규식과 매치되는 모든 문자열(substring)을 반복 가능한 객체로 돌려줌 |
match, search는 정규식과 매치될 때는 match 객체를 돌려주고,
매치되지 않을 때는 None을 돌려줌
import re
p = re.compile('[a-z]+')
match : 문자열 처음부터¶
- match 메서드는 문자열의 처음부터 정규식과 매치되는지 조사
m = p.match("python")
print(m)
<re.Match object; span=(0, 6), match='python'>
"python" 문자열은 [a-z]+ 정규식에 부합되므로 match 객체를 돌려줌
m = p.match("3 python")
print(m)
None
"3 python" 문자열은 처음에 나오는 문자 3이 정규식[a-z]+에 부합되지 않으므로 None을 돌려줌
- match의 결과로 match 객체 또는 None을 돌려주기 때문에 파이썬 정규식 프로그램은 보통 다음과 같은 흐름으로 작성
p = re.compile(정규 표현식)
m = p.match("조사할 문자열")
if m:
print('Match found: ', m.group())
else:
print('No match')
즉 match의 결괏값이 있을 때만 그다음 작업을 수행하겠다는 것
search : 문자열 전체¶
m = p.search("python")
print(m)
<re.Match object; span=(0, 6), match='python'>
"python" 문자열에 search 메서드를 수행하면 match 메서드를 수행했을 때와 동일하게 매치됨
m = p.search("3 python")
print(m)
<re.Match object; span=(2, 8), match='python'>
"3 python" 문자열의 첫 번째 문자는 "3"이지만 search는 문자열의 처음부터 검색하는 것이 아니라 문자열 전체를 검색하기 때문에 "3" 이후의 "python" 문자열과 매치됨
이렇듯 match 메서드와 search 메서드는 문자열의 처음부터 검색할지의 여부에 따라 다르게 사용
findall¶
result = p.findall("life is too short")
print(result)
['life', 'is', 'too', 'short']
"life is too short" 문자열의 'life', 'is', 'too', 'short' 단어를 각각 [a-z]+ 정규식과 매치해서 리스트로 돌려줌
finditer¶
result = p.finditer("life is too short")
print(result)
<callable_iterator object at 0x0000020D8DA144F0>
for r in result:
print(r)
<re.Match object; span=(0, 4), match='life'> <re.Match object; span=(5, 7), match='is'> <re.Match object; span=(8, 11), match='too'> <re.Match object; span=(12, 17), match='short'>
finditer은 findall과 동일하지만 그 결과로 반복 가능한 객체(iterable object)를 돌려줌.
반복 가능한 객체가 포함하는 각각의 요소는 match 객체
예제¶
- msg = "010-1234-5678 peter 010-1234-5679" 에서 전화번호만 골라서 출력
# search 사용
import re
msg = "010-1234-5678 peter 010-1234-5679"
p = re.compile("\d{3}-\d{4}-\d{4}")
m = p.search(msg)
print(m)
<re.Match object; span=(0, 13), match='010-1234-5678'>
# findall 사용
print(p.findall(msg))
['010-1234-5678', '010-1234-5679']
phones = p.findall(msg)
for phone in phones:
print(phone)
010-1234-5678 010-1234-5679
#finditer 사용
result = p.finditer(msg)
print(result)
for r in result: print(r.group())
<callable_iterator object at 0x0000020D926537F0> 010-1234-5678 010-1234-5679
match 객체의 메서드¶
메서드 | 목적 |
---|---|
group() | 매치된 문자열을 돌려줌 |
start() | 매치된 문자열의 시작 위치를 돌려줌 |
end() | 매치된 문자열의 끝 위치를 돌려줌 |
span() | 매치된 문자열의 (시작,끝)에 해당하는 튜플을 돌려줌 |
import re
p = re.compile('[a-z]+')
m = p.match("python")
m.group()
'python'
m.start()
0
m.end()
6
m.span()
(0, 6)
match 메서드를 수행한 결과로 돌려준 match 객체의 start()의 결괏값은 항상 0일 수밖에 없다.
왜냐하면 match 메서드는 항상 문자열의 시작부터 조사하기 때문
- search 메서드를 사용한 경우 start() 값은 다르게 나옴
m = p.search("3 python")
m.group()
'python'
m.start()
2
m.end()
8
m.span()
(2, 8)
모듈 단위로 수행하기¶
- 지금까지 우리는 re.compile을 사용해 컴파일된 패턴 객체로 그 이후의 작업을 수행함.
re 모듈은 이것을 좀 축약한 형태로 사용할 수 있는 방법을 제공
#re.compile 사용
p = re.compile('[a-z]+')
m = p.match("python")
# re 모듈 사용
m = re.match('[a-z]+', "python")
위 예처럼 사용하면 컴파일과 match 메서드를 한 번에 수행 가능
보통 한 번 만든 패턴 객체를 여러 번 사용해야 할 때는 이 방법보다 re.compile을 사용하는 것이 편함
컴파일 옵션¶
- 정규식을 컴파일 할 때 다음 옵션 사용 가능
옵션 이름 | 약어 | 설명 |
---|---|---|
DOTALL | S | dot 문자(.)가 줄바꿈 문자를 포함해 모든 문자와 매치 |
IGNORECASE | I | 대소문자에 관계 없이 매치 |
MULTILINE | M | 여러 줄과 매치(^,$ 메타 문자의 사용과 관계가 있는 옵션) |
VERBOSE | X | verbose 모드 사용(정규식을 보기 편하게 만들 수도 있고 주석 등을 사용할 수도 있다.) |
DOTALL, S¶
- . 메타 문자는 줄바꿈 문자(\n)를 제외한 모든 문자와 매치되는 규칙이 있다.
만약 \n 문자도 포함해 매치하고 싶으면 re.DOTALL 또는 re.S 옵션을 사용해 정규식을 컴파일하면 된다.
import re
p = re.compile('a.b')
m = p.match('a\nb')
print(m) # 문자열과 정규식이 매치되지 않음
None
정규식이 a.b인 경우 문자열 a\nb는 매치되지 않음. 왜냐하면 \n은 . 메타 문자와 매치되지 않기 때문
\n 문자와도 매치되게 하려면 다음과 같이 re.DOTALL 옵션을 사용해야 한다.
p = re.compile('a.b', re.DOTALL)
m = p.match('a\nb')
print(m)
<re.Match object; span=(0, 3), match='a\nb'>
보통 re.DOㅡTALL 옵션은 여러 줄로 이루어진 문자열에서 \n 상관없이 검색할 때 많이 사용
IGNORECASE, I¶
- re.IGNORECASE 또는 re.I 옵션은 대소문자 구별 없이 매치를 수행할 때 사용
p = re.compile('[a-z]', re.I)
p.match('python')
<re.Match object; span=(0, 1), match='p'>
p.match('Python')
<re.Match object; span=(0, 1), match='P'>
p.match('PYTHON')
<re.Match object; span=(0, 1), match='P'>
[a-z] 정규식은 소문자만을 의미하지만 re.I 옵션으로 대소문자 구별 없이 매치됨
MULTILINE, M¶
- re.MULTILINE 또는 re.M 옵션은 조금 후에 설명할 메타 문자인
^,$
와 연관된 옵션 - ^ : 문자열의 처음
- $ : 문자열의 마지막
^python
: 문자열의 처음은 항상 python으로 시작해야 함python$
: 문자열의 마지막은 항상 python으로 끝나야 함
import re
p = re.compile("^python\s\w+")
data = """python one
life is too short
python two
you need python
"""
print(p.findall(data))
['python one']
정규식 '^python\s\w+'은 python이라는 문자열로 시작하고 그 뒤에 whitespace, 그 뒤에 단어가 와야 한다는 의미이다. 검색할 문자열 data는 여러 줄로 이루어져 있다.
실행결과는
['python one']
이는 ^메타 문자에 의해 python이라는 문자열을 사용한 첫 번째 줄만 매치된 것이다.
- ^메타 문자를 문자열 전체의 처음이 아니라 각 라인의 처음으로 인식시키고 싶은 경우
re.MULTILINE 또는 re.M 사용
import re
p = re.compile("^python\s\w+", re.MULTILINE)
data = """python one
life is too short
python two
you need python
python three"""
print(p.findall(data))
['python one', 'python two', 'python three']
re.MULTILINE 옵션으로 인해 ^메타 문자가 문자열 전체가 아닌 각 줄의 처음이라는 의미를 갖게 되었다.
즉 re.MULTILINE 옵션은 ^, $ 메타 문자를 문자열의 각 줄마다 적용해 주는 것
VERBOSE,X¶
- 이해하기 어려운 정규식을 주석 또는 줄 단위로 구분
- re.VERBOSE 또는 re.X 옵션
charref = re.compile(r'&[#](0[0-7]+|[0-9]+|x[0-9a-fA-F]+);')
charref = re.compile(r"""
&[#] # Start of a numeric entiity reference
(
0[0-7]+ # Octal form
| [0-9]+ # Decimal form
| x[0-9a-fA-F]+ # Hexadecimal form
)
; # Trailing semicolon
""", re.VERBOSE)
첫 번째와 두 번째 예를 비교해 보면 컴파일될 객체인 charref는 모두 동일한 역할을 한다.
하지만 정규식이 복잡할 경우 두 번째처럼 주석을 적고 여러 줄로 표현하는 것이 훨씬 가독성이 좋다.
re.VERBOSE 옵션 사용 시 문자열에 사용된 whitespace는 컴파일할 때 제거됨(단 [] 안에 사용한 whitespace는 제외)
그리고 줄 단위로 #기호를 사용해 주석문 작성 가능
백슬래시 문제¶
- 정규 표현식을 파이썬에서 사용할 때 혼란을 주는 요소가 한 가지 있는데, 바로 백슬래시(/)
- 어떤 파일 안에 있는 "\section" 문자열을 찾기 위한 정규식 만들기
\section
이 정규식은 \s문자가 whitespace로 해석되어 의도한 대로 매치가 이루어지지 않는다.ㅡㅡ
- 위 표현과 동일한 의미의 정규식
[ \t\n\r\f\v]ection #\s문자가 이스케이프 코드 \t,\n,\r,\f,\v로 해석됨
- 의도한 대로 매치하고 싶다면 다음과 같이 변경
\\section
즉 위 정규식에서 사용한 \문자가 문자열 자체임을 알려주기 위해 백슬래시 2개를 사용해 익스케이프 처리
- 위 정규식을 컴파일하려면 다음과 같이 작성
p = re.compile('\\section')
그런데 여기서 또 하나의 문제 발생
위처럼 정규식을 만들어서 컴파일하면 실제 파이썬 정규식 엔진에는 파이썬 문자열 리터럴 규칙에 따라 \이 \로 변경되어 \section이 전달됨ㅡㅡ
결국 정규식 엔진에 \문자를 전달하려면 파이썬은 \\처럼 백슬래시 4개를 사용해야 함
p = re.compile('\\\\section')
이렇게 해야만 원하는 결과를 얻을 수 있다. 하지만 너무 복잡하다
만약 위와 같이 \를 사용한 표현이 계속 반복되는 정규식이라면 너무 복잡해서 이해하기 쉽지 않다.
이러한 문제로 인해 파이썬 정규식에는 Raw String 규칙이 생겨났다.
즉 컴파일해야 하는 정규식이 Raw String임을 알려 줄 수 있도록 파이썬 문법을 만든 것이다.
방법은 다음과 같다.
p = re.compile(r'\\section)
위와 같이 정규식 문자열 앞에 r문자를 삽입하면 이 정규식은 Raw String 규칙에 의해 백슬래시 2개 대신 1개만 써도 2개를 쓴 것과 동일한 의미를 지닌다.
7-3 강력한 정규 표현식의 세계로¶
메타 문자¶
아직 살펴보지 않은 메타문자에 대해 알아보자.
여기서 다룰 메타문자는 앞에서 살펴본 메타 문자와 성격이 조금 다르다.
앞에서 살펴본 +,*,[],{} 등의 메타문자는 매치가 진행될 때 현재 매치되고 있는 문자열의 위치가 변경된다(보통 소비된다고 표현)
하지만 이와 달리 문자열을 소비시키지 않는 메타 문자도 있다.
이번에는 이런 문자열 소비가 없는(zero-width assertions) 메타 문자에 대해 살펴보자.
|¶
- or과 동일한 의미
- A|B : A 또는 B
import re
p = re.compile('Crow|Servo')
m = p.match('CrowHello')
print(m)
<re.Match object; span=(0, 4), match='Crow'>
^¶
- 문자열의 맨 처음과 일치
- 앞에서 살펴본 컴파일 옵션 re.MULTILINE을 사용할 경우 : 여러 줄의 문자열일 때 각 줄의 처음과 일치
print(re.search('^Life', 'Life is too short'))
<re.Match object; span=(0, 4), match='Life'>
print(re.search('^Life', 'My Life'))
None
- Life 문자열이 처음에 온 경우 : 매치됨
- 처음 위치가 아닌 경우 : 매치되지 않음
$¶
- ^문자와 반대의 경우
- 문자열의 끝과 매치
print(re.search('short$', 'Life is too short'))
<re.Match object; span=(12, 17), match='short'>
print(re.search('short$', 'Life is too short, you need python'))
None
- 검색할 문자열이 short로 끝난 경우 : 매치됨
- 그 이외의 경우: 매치되지 않음
^
또는 $
문자를 메타 문자가 아닌 문자 그 자체로 매치하고 싶은 경우 : \^
, \$
사용
\A¶
- 문자열의 처음과 매치
- ^ 메타 문자와 동일한 의미이지만 re.MULTILINE 옵션을 사용할 경우 다르게 해석됨
- re.MULTILINE 옵션을 사용할 경우
- ^ : 각 줄의 문자열의 처음과 매치
- \A : 줄과 상관없이 전체 문자열의 처음하고만 매치
\Z¶
- 문자열의 끝과 매치
- \A와 동일하게 re.MULTILINE 옵션 사용 시
$
메타 문자와는 달리 전체 문자열의 끝과 매치
\b¶
- 단어 구분자(Word boundary)
- 보통 단어는 whitespace에 의해 구분됨
p = re.compile(r'\bclass\b')
print(p.search('no class at all'))
<re.Match object; span=(3, 8), match='class'>
'\bclass\b' 정규식은 앞뒤가 whitespace로 구분된 class라는 단어와 매치됨을 의미
따라서 no class at all의 class라는 단어와 매치됨
print(p.search('the declassified algorithm'))
None
위 예의 the declassified algorithm 문자열 안에도 class 문자열이 포함되어 있지만 whitespace로 구분된 단어가 아니므로 매치되지 X
print(p.search('one subclass is'))
None
subclass 문자열 역시 class 앞에 sub 문자열이 더해져 있으므로 매치되지 않음
\b 메타 문자 사용 시 주의할 점
- \b는 파이썬 리터럴 규칙에 의하면 백스페이스(BackSpace)를 의미
그러므로 \b가 백스페이스가 아닌 단어 구분자임을 알려주기 위해 r'\bclass\b'처럼 Raw string임을 알려주는 기호r을 반드시 붙여주어야 함
\B¶
- \b 메타 문자와 반대의 경우
- whitespace로 구분된 단어가 아닌 경우에만 매치
p = re.compile(r'\Bclass\B')
print(p.search('no class at all'))
None
print(p.search('the declassified algorithm'))
<re.Match object; span=(6, 11), match='class'>
print(p.search('one subclass is'))
None
class 단어의 앞뒤에 whitespace가 하나라도 있는 경우 매치가 안 됨
그루핑¶
ABC 문자열이 계속해서 반복되는지 조사하는 정규식을 작성하고 싶다. 어떻게 해야 할까?
이럴 때 필요한 것이 바로 그루핑(Grouping)
위 경우는 다음처럼 그루핑을 사용하여 작성 가능
(ABC)+
() : 그룹을 만들어주는 메타 문자
import re
p = re.compile('(ABC)+')
m = p.search('ABCABCABC OK?')
print(m)
<re.Match object; span=(0, 9), match='ABCABCABC'>
다음 예를 보자.
p = re.compile(r"\w\s+\d+[-]\d+[-]\d+")
m = p.search("park 010-1234-1234")
\w+\s+\d+[-]\d+[-]\d+
은 이름 + " " + 번화번호
형태의 문자열을 찾는 정규식
이렇게 매치된 문자열 중 이름만 뽑아내고 싶다면?
보통 반복되는 문자열을 찾을 때 그룹을 사용하는데, 그룹을 사용하는 보다 큰 이유는 위에서 볼 수 있듯이 매치된 문자열 중에서 특정 부분의 문자열만 뽑아내기 위해서인 경우가 더 많다.
위 예에서 만약 '이름' 부분만 뽑아내려면?
p = re.compile(r"(\w+)\s+\d+[-]\d+[-]\d+")
m = p.search("park 010-1234-1234")
print(m.group(1))
park
이름에 해당하는 '\w+' 부분을 그룹('\w+')으로 만들면 match 객체의 group(인덱스) 메서드를 사용해 그루핑된 부분의 문자열만 뽑아낼 수 있다.
- group 메서드의 인덱스의 의미
group(인덱스) | 설명 |
---|---|
group(0) | 매치된 전체 문자열 |
group(1) | 첫 번째 그룹에 해당하는 문자열 |
group(2) | 두 번째 그룹에 해당하는 문자열 |
group(3) | 세 번째 그룹에 해당하는 문자열 |
p = re.compile(r"(\w+)\s+(\d+[-]\d+[-]\d+)")
m = p.search("park 010-1234-1234")
print(m.group(2))
010-1234-1234
이번에는 전화번호 부분을 추가로 그룹 '(\d+[-]\d+[-]\d+)'로 만들었다.
이렇게 하면 group(2)처럼 사용해 전화번호만 뽑아낼 수 있다.
전화번호 중 국번만 뽑아내고 싶다면?
- 국번 부분을 그루핑
p = re.compile(r"(\w+)\s+((\d+)[-]\d+[-]\d+)")
m = p.search("park 010-1234-1234")
print(m.group(3))
010
위 예에서 볼 수 있듯이 '(\w+)\s+((\d+)[-]\d+[-]\d+)' 처럼 그룹을 중첩되게 사용하는 것도 가능
그룹이 중첩되어 있는 경우 : 바깥쪽부터 시작하여 안쪽으로 들어갈수록 인덱스 증가
그루핑된 문자열 재참조¶
- 그룹의 또 하나 좋은 점은 한 번 그루핑한 문자열을 재참조(Backreferences)할 수 있다는 점이다.
p = re.compile(r'(\b\w+)\s+\1')
p.search('Paris in the the spring').group()
'the the'
정규식 '(\b\w+)\s+\1'은 '(그룹) + " " + 그룹과 동일한 단어'와 매치됨을 의미
이렇게 정규식을 만들면 2개의 동일한 단어를 연속적으로 사용해야만 매치됨
이것을 가능케 하는 것이 바로 재참조 메타 문자인 \1
\1은 정규식의 그룹 중 첫 번째 그룹을 가리킴
그루핑된 문자열에 이름 붙이기¶
정규식 안에 그룹이 무척 많아진다고 가정해 보자. 예를 들어 정규식 안에 그룹이 10개 이상만 되어도 매우 혼란스럽다.
거기에 더해 정규식이 수정되면서 그룹이 추가, 삭제되면 그 그룹을 인덱스로 참조한 프로그램도 모두 변경해주어야 하는 위험도 갖게 됨.
만약 그룹을 인덱스가 아닌 이름(Named Groups)으로 참조할 수 있다면 이런 문제를 해결할 수 있지 않을까?
이러한 이유로 정규식은 그룹을 만들 때 그룹 이름을 지정할 수 있게 함.
(?P<name>\w+)\s+((\d+)[-]\d+[-]\d+)
위 정규식은 앞에서 본 이름과 전화번호를 추출하는 정규식
(/w+)만 (?P
복잡해 보이지만 (/w+)라는 그룹에 name이라는 이름을 붙인 것에 불과
여기에서 사용한 (?...) 표현식은 정규 표현식의 확장 구문
- 그룹에 이름을 지어주는 확장 구문
(?P<그룹 이름>...)
- 그룹에 이름을 지정하고 참조하기
p = re.compile(r"(?P<name>\w+)\s+((\d+)[-]\d+[-]\d+)")
m = p.search("park 010-1234-1234")
print(m.group("name"))
park
위 예에서 볼 수 있듯이 name이라는 그룹 이름으로 참조 가능
그룹 이름 사용 시 정규식 안에서 재참조도 가능
p = re.compile(r'(?P<word>\b\w+)\s+(?P=word)')
p.search('Paris in the the spring').group()
'the the'
위 예에서 볼 수 있듯이 재참조할 때에는 (?P=그룹 이름)이라는 확장 구문 사용
전방 탐색¶
p = re.compile(".+:")
m = p.search("http://google.com")
print(m.group())
http:
정규식 ".+:"와 일치하는 문자열로 http:를 돌려줌
만약 http:라는 검색 결과에서 :를 제외하고 출력하려면?
위 예는 그나마 간단하지만 훨씬 복잡한 정규식이어서 그루핑은 추가로 할 수 없다는 조건까지 더해진다면?
이럴 때 사용하는 것이 전방 탐색
전방 탐색에는 긍정(Positive)와 부정(Negative)의 2종류가 있고 다음과 같이 표현
정규식 | 종류 | 설명 |
---|---|---|
(?=...) | 긍정형 전방 탐색 | ...에 해당하는 정규식과 매치되어야 하며 조건이 통과되어도 문자열이 소비되지 X |
(?!...) | 부정형 전방 탐색 | ...에 해당하는 정규식과 매치되지 않아야 하며 조건이 통과되어도 문자열이 소비되지 X |
긍정형 전방 탐색¶
- 긍정형 전방 탐색을 사용하면 http:의 결과를 http로 바꿀 수 있다.
p = re.compile(".+(?=:)")
m = p.search("http://google.com")
print(m.group())
http
정규식 중 :에 해당하는 부분에 긍정형 전방 탐색 기법을 적용해 (?=:)으로 변경
이렇게 되면 기존 정규식과 검색에선느 동일한 효과를 발휘하지만 :에 해당하는 문자열이 정규식 엔진에 의해 소비되지 않아(검색에는 포함되지만 검색 결과에는 제외됨)
검색 결과에서는 :이 제거된 후 돌려주는 효과
- '파일 이름 + . + 확장자'를 나타내는 정규식
.*[.].*$
이 정규식은 foo.bar, autoexec.bar, sendmail.cf 같은 형식의 파일과 매치됨
- 이 정규식에 'bat인 파일은 제외해야 한다'는 조건 추가
.*[.][^b].*$ # 문자 클래스 [] 안의 ^ 메타 문자는 반대(not)을 의미
이 정규식은 확장자가 b라는 문자로 시작하면 안 된다는 의미.
하지만 이 정규식은 bar라는 파일마저 걸러냄.
정규식을 다음과 같이 수정하자.
.*[.]([^b]..|.[^a].|..[^t])$
이 정규식은 | 메타 문자를 사용해 확장자의 첫 번째 문자가 b가 아니거나 두 번째 문자가 a가 아니거나 세 번째 문자가 t가 아닌 경우를 의미.
이 정규식에 의해 foo.bar은 제외되지 않고 autoexec.bat은 제외되어 만족스러운 결과를 돌려줌.
하지만 이 정규식은 아쉽게도 sendmail.cf처럼 확장자의 문자 개수가 2개인 케이스를 포함하지 못하는 오동작을 하기 시작
따라서 다음과 같이 바꾸자.
.*[.]([^b].?.?|[.[^a]?.?|..?[^t]?])$
확장자의 문자 개수가 2개여도 통과되는 정규식이 만들어짐.
하지만 정규식은 점점 더 복잡해지고 이해하기 어려워짐
그런데 여기서 bat 파일말고 exe 파일도 제외하라는 조건이 추가로 생긴다면?
이 모든 조건을 만족하는 정규식을 구현하려면 패턴은 더욱더 복잡해짐
부정형 전방 탐색¶
이러한 상황의 구원 투수는 바로 부정형 전방 탐색
위 예는 부정형 전방 탐색을 사용하면 다음과 같이 간단하게 처리됨
.*[.](?!bat$).*$
확장자가 bat가 아닌 경우에만 통과된다는 의미
bat 문자열이 있는지 조사하는 과정에서 문자열이 소비되지 않으므로 bat가 아니라고 판단되면 그 이후 정규식 매치가 진행됨
- exe 역시 제외하라는 조건이 추가되더라도 다음과 같이 간단히 표현 가능
.*[.](?!bat$|exe$).*$
추가) 전방탐색과 후방탐색¶
전방탐색¶
string = '''
http://www.forta.com a
https://mail.forta.com b
ftp://ftp.forta.com c
'''
# 문자, 특수문자 등이 하나 이상 마지막은 f
p = re.compile(".+f")# 전방탐색으로 f를 표시
p.findall(string)
['http://www.f', 'https://mail.f', 'ftp://ftp.f']
p = re.compile(".+(?=f)") # 전방탐색으로 f를 표시하지 X
p.findall(string)
['http://www.', 'https://mail.', 'ftp://ftp.']
p = re.compile(".+(?=:)")
p.findall(string)
['http', 'https', 'ftp']
#### 후방탐색
string = '''
http://www.forta.com a
https://mail.forta.com b
ftp://ftp.forta.com c
'''
import re
p = re.compile("(?=f).+") # 후방탐색으로 f를 표시
p.findall(string)
['forta.com a', 'forta.com b', 'ftp://ftp.forta.com c']
p = re.compile("(?<=f).+") #후방탐색으로 f 표시 X
p.findall(string)
['orta.com a', 'orta.com b', 'tp://ftp.forta.com c']
- 예제
s = "http://naver.com http://google.com ftp://daum.net"
1. ['http:', 'http:', 'ftp:']
2. ['http', 'http', 'ftp']
3. ['naver.com', 'google.com', 'daum.net']
p = re.compile("\w+:")
p.findall(s)
['http:', 'http:', 'ftp:']
p = re.compile("\w+(?=:)")
p.findall(s)
['http', 'http', 'ftp']
p = re.compile(r"(?<=//)\S+")
p.findall(s)
['naver.com', 'google.com', 'daum.net']
- tag 내용 뽑아내기
html = 'Kakao <p>ryan</p> keep a straight face.'
# 왼쪽 p 기준 후방탐색, 오른쪽 p 기준 전방탐색
p = re.compile(r"(?<=<p>)\w+(?=</p>)")
p.findall(html)
['ryan']
문자열 바꾸기 (sub)¶
- sub 메서드를 사용하면 정규식과 매치되는 부분을 다른 문자로 쉽게 바꿀 수 있음
- sub 메서드의 첫 번째 매개변수 : 바꿀 문자열(replacement)
- sub 메서드의 두 번째 매개변수 : 대상 문자열
p = re.compile('(blue|white|red)')
p.sub('colour', 'blue socks and red shoes')
'colour socks and colour shoes'
blue 또는 white 또는 red라는 문자열이 colour라는 문자열로 바뀜
바꾸기 횟수 제어
- 세 번째 매개변수로 count 값 넘기기
p.sub('colour', 'blue socks and red shoes', count = 1)
'colour socks and red shoes'
처음 일치하는 blue만 colour라는 문자열로 한 번만 바꾸기가 실행됨
sub 메서드와 유사한 subn 메서드¶
- subn 역시 sub와 동일한 기능을 하지만 반환 결과를 튜플로 돌려준다는 차이가 있음
- 돌려준 튜플의 첫째 요소 : 변경된 문자열
- 돌려준 튜플의 두번째 요소 : 바꾸기가 발생한 횟수
p = re.compile('(blue|white|red)')
p.subn('colour', 'blue socks and red shoes')
('colour socks and colour shoes', 2)
sub 메서드를 사용할 때 참조 구문 사용하기¶
p = re.compile(r"(?P<name>\w+)\s+(?P<phone>(\d+)[-]\d+[-]\d+)")
print(p.sub("\g<phone> \g<name>", "park 010-1234-1234"))
010-1234-1234 park
위 예는 '이름 + 전화번호'의 문자열을 '전화번호 + 이름'으로 바꾸는 예
sub의 바꿀 문자열 부분에 '\g<그룹 이름>'을 사용하면 정규식의 그룹 이름 참조 가능
- 그룹 이름 대신 참조 번호를 사용해도 같은 결과
p = re.compile(r"(?P<name>\w+)\s+(?P<phone>(\d+)[-]\d+[-]\d+)")
print(p.sub("\g<2> \g<1>", "park 010-1234-1234"))
010-1234-1234 park
sub 메서드의 매개변수로 함수 넣기¶
- sub 메서드의 첫 번째 매개변수로 함수를 넣을 수도 있다.
def hexrepl(match):
value = int(match.group())
return hex(value)
p = re.compile(r'\d+')
p.sub(hexrepl, 'Call 65490 for printing, 49152 for user code.')
'Call 0xffd2 for printing, 0xc000 for user code.'
hexrepl 함수는 match 객체(위에서 숫자에 매치되는)를 입력으로 받아 16진수로 변환하여 돌려주는 함수
sub의 첫 번째 매개변수로 함수를 사용할 경우 해당 함수의 첫 번째 매개변수에는 정규식과 매치된 match 객체가 입력됨.
그리고 매치되는 문자열은 함수의 반환 값으로 바뀜
Greedy vs Non-Greedy¶
s = '<html><head><title>Title</title>'
len(s)
32
print(re.match('<.*>', s).span())
(0, 32)
print(re.match('<.*>', s).group())
<html><head><title>Title</title>
'<.>' 정규식의 매치 결과로 <html>
문자열을 돌려주기를 기대했을 것이다.
하지만 메타 문자는 매우 탐욕스러워서 매치할 수 있는 최대한의 문자열인 <html><head><title>Title</title>
문자열을 모두 소비해 버렷다.
어떻게 하면 이 탐욕스러움을 제한하고 <html>
문자열까지만 소비하도록 막을 수 있을까?
- 다음과 같이 non-greedy 문자인 ?를 사용하면 *의 탐욕을 제한 가능
print(re.match('<.*?>',s).group())
<html>
non-greedy 문자인 ?는 *?, +?, ??, {m,n}?와 같이 사용 가능
가능한 한 가장 최소한의 반복을 수행하도록 도와주는 역할
정규표현식 살펴보기¶
import re
print(re.__doc__)
Support for regular expressions (RE). This module provides regular expression matching operations similar to those found in Perl. It supports both 8-bit and Unicode strings; both the pattern and the strings being processed can contain null bytes and characters outside the US ASCII range. Regular expressions can contain both special and ordinary characters. Most ordinary characters, like "A", "a", or "0", are the simplest regular expressions; they simply match themselves. You can concatenate ordinary characters, so last matches the string 'last'. The special characters are: "." Matches any character except a newline. "^" Matches the start of the string. "$" Matches the end of the string or just before the newline at the end of the string. "*" Matches 0 or more (greedy) repetitions of the preceding RE. Greedy means that it will match as many repetitions as possible. "+" Matches 1 or more (greedy) repetitions of the preceding RE. "?" Matches 0 or 1 (greedy) of the preceding RE. *?,+?,?? Non-greedy versions of the previous three special characters. {m,n} Matches from m to n repetitions of the preceding RE. {m,n}? Non-greedy version of the above. "\\" Either escapes special characters or signals a special sequence. [] Indicates a set of characters. A "^" as the first character indicates a complementing set. "|" A|B, creates an RE that will match either A or B. (...) Matches the RE inside the parentheses. The contents can be retrieved or matched later in the string. (?aiLmsux) The letters set the corresponding flags defined below. (?:...) Non-grouping version of regular parentheses. (?P<name>...) The substring matched by the group is accessible by name. (?P=name) Matches the text matched earlier by the group named name. (?#...) A comment; ignored. (?=...) Matches if ... matches next, but doesn't consume the string. (?!...) Matches if ... doesn't match next. (?<=...) Matches if preceded by ... (must be fixed length). (?<!...) Matches if not preceded by ... (must be fixed length). (?(id/name)yes|no) Matches yes pattern if the group with id/name matched, the (optional) no pattern otherwise. The special sequences consist of "\\" and a character from the list below. If the ordinary character is not on the list, then the resulting RE will match the second character. \number Matches the contents of the group of the same number. \A Matches only at the start of the string. \Z Matches only at the end of the string. \b Matches the empty string, but only at the start or end of a word. \B Matches the empty string, but not at the start or end of a word. \d Matches any decimal digit; equivalent to the set [0-9] in bytes patterns or string patterns with the ASCII flag. In string patterns without the ASCII flag, it will match the whole range of Unicode digits. \D Matches any non-digit character; equivalent to [^\d]. \s Matches any whitespace character; equivalent to [ \t\n\r\f\v] in bytes patterns or string patterns with the ASCII flag. In string patterns without the ASCII flag, it will match the whole range of Unicode whitespace characters. \S Matches any non-whitespace character; equivalent to [^\s]. \w Matches any alphanumeric character; equivalent to [a-zA-Z0-9_] in bytes patterns or string patterns with the ASCII flag. In string patterns without the ASCII flag, it will match the range of Unicode alphanumeric characters (letters plus digits plus underscore). With LOCALE, it will match the set [0-9_] plus characters defined as letters for the current locale. \W Matches the complement of \w. \\ Matches a literal backslash. This module exports the following functions: match Match a regular expression pattern to the beginning of a string. fullmatch Match a regular expression pattern to all of a string. search Search a string for the presence of a pattern. sub Substitute occurrences of a pattern found in a string. subn Same as sub, but also return the number of substitutions made. split Split a string by the occurrences of a pattern. findall Find all occurrences of a pattern in a string. finditer Return an iterator yielding a Match object for each match. compile Compile a pattern into a Pattern object. purge Clear the regular expression cache. escape Backslash all non-alphanumerics in a string. Each function other than purge and escape can take an optional 'flags' argument consisting of one or more of the following module constants, joined by "|". A, L, and U are mutually exclusive. A ASCII For string patterns, make \w, \W, \b, \B, \d, \D match the corresponding ASCII character categories (rather than the whole Unicode categories, which is the default). For bytes patterns, this flag is the only available behaviour and needn't be specified. I IGNORECASE Perform case-insensitive matching. L LOCALE Make \w, \W, \b, \B, dependent on the current locale. M MULTILINE "^" matches the beginning of lines (after a newline) as well as the string. "$" matches the end of lines (before a newline) as well as the end of the string. S DOTALL "." matches any character at all, including the newline. X VERBOSE Ignore whitespace and comments for nicer looking RE's. U UNICODE For compatibility only. Ignored for string patterns (it is the default), and forbidden for bytes patterns. This module also defines an exception 'error'.
'Python, Jupyter 🐍 > [python]점프 투 파이썬' 카테고리의 다른 글
점프투파이썬 4장까지 정리 (0) | 2023.03.24 |
---|---|
[Window]파이썬과 jupyter 설치하기 (0) | 2023.03.09 |