- 예제코드는 https://github.com/iseohyun/python-tutorial에서 다운로드 받을 수 있습니다.
- 예제코드 적용 방법 및 환경설정은 여기를 참고하십시오
- VScode의 사용법 안내는 여기를 참고하십시오
목차보기
- 환경구축하기 : 실습 준비, 프로그램, 예제코드 다운로드 방법
- 시작하기 1_HelloWorld : 예제코드 실행 및 코드 보는 방법
- 변수 2_variable : 데이터를 순서대로 읽고, 쓰는(저장하는) 방법
- 출력 테크닉 3_print : 저장된 데이터를 잘(보기 좋게) 출력하는 방법
- 로직 4_Logic : 조건에 따라 실행 순서를 변경(추가, 건너뜀, 반복)하는 방법
- 함수 5_Function : 만들어진 로직을 재사용 하는 방법
- 콜렉션 6_Collections : [저장 단위 확장] 코드에 사용될 데이터를 묶음 단위로 사용하는 방법
- 모듈 7_Module : [프로그램 연계] 작성한(작성된) 코드를 파일 단위로(또는 더 큰 단위로) 가져다 쓰는 방법
- 예외 8_Exception : 프로그램 오류에 대한 대처
- 객체 9_Class : [더 큰 프로젝트] 프로그램을 순서지가 아닌 객체로(대상으로) 대하는 자세(문법)
- 표준 라이브러리 10_Std lib : 기본으로 제공되는 객체(예제)
로직4_Logic
분기문은 어떤 특정 조건에 따라서, 임무를 추가로 수행하거나, 건너뛸 수 있습니다. 분기문의 조건에는 사용자의 입력이나, 센서의 반응, 시간 충족 등이 변수에 영향을 주고, 변수의 상태에 따라 분기가 결정됩니다.
들여쓰기
로직, 함수, 모듈, 객체 등 sub루틴에 진입할 때, 들여쓰기를 합니다. 문법에 위배되지 않지만, PEP 8(Python Enhancement Proposal 8)에서는 들여쓰기를 'tab'을 사용하기보다, '띄어쓰기 4회'를 사용할 것을 권장합니다. 이는 코드를 작성, 공유하는 사람들에게 일관성을 부여합니다.
모든 .py파일에 대하여 tab size를 4로 고정하기 위해서는 "setting.json"에 다음과 같이 추가해야 합니다.
"[python]": {
"editor.insertSpaces": true,
"editor.tabSize": 4
},
if
if문은 가장 단순한 분기를 만들어냅니다.
4_Logic > 01_IF.pyif val == 1:
print("val is 1")
4_Logic > 01-1_else.py
if val == 1:
print("val is 1")
elif val == 2:
print("val is 2")
elif val == 3:
print("val is 3")
else:
print("val is not 1, 2 or 3")
match
match문은 if문이 연속으로 있는 것과 같습니다. 가독성이 좋아집니다.
case _:는 다른 언어의 default:와 동일합니다. 모든 case에 해당사항이 없을 때, 수행됩니다.
4_Logic > 02_Match.pymatch val:
case 1:
print("first")
case 2:
print("second")
case 3:
print("third")
case _:
print("none of those")
조건이 2가지 일 때,
match val:
case 1 | 2:
print("val is 1 or 2")
for
for문은 n번 반복합니다.
4_Logic > 03_For.pyfor i in (1, 2, 3, 4, 5):
print(i, end=" ") # 0 1 2 3 4
4_Logic > 03-1_Range.py
for i in range(5): # 0이상 5미만
print(i, end=" ") # 0 1 2 3 4
for i in range(1, 5): # 1이상 5미만
print(i, end=" ") # 1 2 3 4
for ... else
for ... else는 for문이 break없이 모두 수행 되었을 때, 수행합니다.
4_Logic > 03-2_For_else.pyfor i in range(5):
print(i, end=" ")
else:
print("for else #1") # 수행 됩니다.
for i in range(5):
if i == 3:
break
print(i, end=" ")
else:
print("for else #2") # 수행되지 않습니다.
while
while문은 조건이 참이면 반복합니다. 조건의 변화가 없다면 무한으로 반복합니다.
4_Logic > 04_While.pywhile i < 5:
print(i)
i += 1
break/continue
- break를 만나면, loop를 탈출합니다.
- countinue를 만나면, loop의 처음으로 이동합니다.
for i in range(10):
if i == 2:
continue # 이번 루틴만 건너 뜀
if i == 5:
break # 현재 루프를 종료
print("%d 번째" % i)
pass, 미구현
로직, 함수, 모듈, 객체 등 구현할 때, 반드시 내용을 포함해야 합니다. 다만, 당장 구현이 어려운 경우 해당 부분을 미구현으로 남겨둘 수 있습니다.
4_Logic > 06_Pass.pyval = 1
if val == 1:
pass
else:
print(val)
함수5_Function
- 코드의 재사용을 위해 함수를 사용합니다.
- 함수를 호출하기 위해서는 먼저 함수가 정의되어야 합니다.
- 함수를 정의 할 때 def(define, 정의하다) 키워드를 사용합니다.
- :(콜론)으로 마무리 합니다.
- 내용(body)는 들여쓰기(indentation) 후 작성합니다.
- 함수의 작명규칙은 변수와 동일합니다(소문자+'_' 권장).
- 함수는 정의 및 호출시 소괄호()를 붙여야 합니다.
def func1(): # define 정의
print("contents 1") # 함수 내용
print("contents 2") # 함수 내용2
func1() # call 호출
func1() # call 호출(2번째)
scope
global | local | |
---|---|---|
위치 | main stream | sub stream(function, object ...) |
접근 | 모든 위치에서 접근 가능 | 해당 위치에서만 접근 가능 |
local변수가 필요한 이유
- 함수가 많아질수록 변수끼리의 충돌가능성이 있음
- 충돌하지 않기 위해 불필요하게 이름이 길어짐
- 신경써야 할 변수가 많아지면 관리가 어려움
그럼에도 불구하고 구조적으로 global변수에 접근을 하려면 global keywords를 사용합니다.
5_Function > 01-3_Scope.pydef scope_test():
def do_local():
spam = "local spam"
def do_nonlocal():
nonlocal spam
spam = "nonlocal spam"
def do_global():
global spam
spam = "global spam"
spam = "test spam"
do_local()
print("After local assignment:", spam) # After local assignment: test spams
do_nonlocal()
print("After nonlocal assignment:", spam) # After nonlocal assignment: nonlocal spam
do_global()
print("After global assignment:", spam) # After global assignment: nonlocal spam
# 접근 위치가 scope_test()이기 때문에 nonlocal이 호출
print("In global scope:", spam) # In global scope: global spam
arguments
입력인자를 통한 정보전달
5_Function > 02_Arguments.pydef func1(x): # step 2: 100 받음
print(x) # step 3: 100 출력
func1(100); # step 1: 100 전달
기본 값
다음과 같이 선언할 때, 값을 지정하면, 호출할 때 값을 전달하지 않으면 기본값으로 설정됩니다.
5_Function > 02-1_Keywords.pydef func1(x=1):
print(x)
func1(); # x=1
호출 방법
함수에게 정보를 전달하는 방법은 소괄호()안에 작성하는 방법입니다. 호출방법으로는:
- Positional : 호출 위치(순서)에 따라 값을 전달
def add(arg1, arg2): print(f"Data : {arg1}, {arg2}") add(10, 20)
- Keyword : 인자명을 명시하여 값을 전달
def func1(arg1, arg2): print(f"Data : {arg1}, {arg2}") func1(arg2=100, arg1=200) # 순서 무관
- combined : 특수 기호를 사용해서, 해당 argument의 속성을 지정
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2): --┬-------- -┬-------- -----┬---- | | | | Positional or keyword | | └- Keyword only └-- Positional only
def combined_example(pos_only, /, standard, *, kwd_only): print(pos_only, standard, kwd_only) combined_example("POS_ONLY_ARG", standard="STD_ARG", kwd_only="KW_ONLY_ARG")
모호함
'/', '*' 특수문자를 이용해서 argument의 특징을 강제할 수 있습니다.
5_Function > 02-3_Ambiguity.pydef foo(name, /, **kwds): # '/' 문자로 name의 성격을 pos로 강제
return "name" in kwds # name은 kwds의 name임이 확실합니다.
def bar(name, **kwds):
return "name" in kwds # kwds의 name인지, bar arg의 name인지???
ret = foo(1, **{"name": 2})
ret = bar(1, **{"name": 2}) # TypeError: bar()...
return 반환
5_Function > 03_Return.pydef ret100(): # step 2: 함수 시작
return 100 # step 3: 100 반환
ans = ret100() # step 1: 함수 호출
# step 4: ans에 100 저장
가변 함수
입력 인자의 갯수가 일정하지 않을 때(가변), '*'기호를 이용해서 전달 받을 수 있습니다.
5_Function > 04_Sequence.pydef concat(*args, sep="/"):
return sep.join(args)
concat("earth", "mars", "venus", "mercury", "jupiter")
# 출력: earth/mars/venus/mercury/jupiter
5_Function > 04-1_Unpack.py
def unpack(*args):
for i in args:
print(i, end=" ")
unpack("earth", "mars", "venus") # 출력: earth mars venus
딕션네리(자료형) 전달
5_Function > 05_Dictionary.pydef search(index="name", **dict):
print(dict[index])
dict = {"name": "광해군", "year": 1592} # 출력: 광해군
함수 부가 정보 관리
Documentation, 문서화(함수 설명서)
- 함수 뒤에 """로 작성된 문자열을 반환합니다.
5_Function > 06_Documentation.pydef f():
"""
This is a function that prints the string 'Hello, world!'
:return: None
"""
print("Hello, world!")
print(f.__doc__)
Annotation, 주석(함수 인자, 리턴의 성격 출력)
5_Function > 07_Annotation.pydef f(ham: str, eggs: str = "eggs") -> str:
print("Annotations:", f.__annotations__)
# 출력: Annotations: {'ham': , 'eggs': , 'return': }
f("spam")
Lambda
Lambda(람다) 함수는 함수의 이름을 기술하지 않고, 간략하게 작성됩니다. 다음 경우에 설계합니다.
- 함수의 구조가 너무 간단하거나,
- 함수가 반복적으로 호출되지 않고, 단 한 번 사용될 때
def make_incrementor(n):
return lambda x: x + n
f = make_incrementor(42)
print(f(0)) # 출력 : 42
print(f(1)) # 출력 : 43
콜렉션6_Collections
콜렉션은 자료구조, 데이터 묶음에 대하여 다룹니다.
list
- []로 감싸고, ,(콤마)로 구분합니다.
- 숫자, 문자열, 콜렉션(리스트, 튜플, 딕셔네리), 오브젝트 등을 멤버로 저장할 수 있습니다.
- 모든 멤버가 순서대로 index(순번)을 갖고 있습니다(0부터 시작).
- 반복작업에 유리합니다.
# 0 1 2 3 4 5 6
fruits = ["orange", "apple", "pear", "banana", "kiwi", "apple", "banana"]
fruits[0] # orange
fruits[6] # banana
fruits[3] = "tomato" # banana -> tomato
# ['orange', 'apple', 'pear', 'tomato', 'kiwi', 'apple', 'banana']
6_Collections > 01-1_Loop technique.py
for fruit in fruits:
print(fruit, end=", ")
# 출력: orange, apple, pear, banana, kiwi, apple, banana,
리스트의 찾기, 통계, 추가/삭제, 역순, 정렬 예제
함수명 | 기능 | 비고 |
---|---|---|
append(x) | 아이템 추가 | a[len(a):] = [x] |
extend(iterable) | 아이템 추가 | a[len(a):] = iterable |
insert(i, x) | 주어진 위치(i)에 항목(x)을 삽입 | |
remove(x) | 리스트에서 값이 x와 같은 첫 번째 항목을 삭제. 없으면 ValueError | |
pop([i]) | 주어진 위치(i)를 삭제, 생략시 마지막 아이템 삭제 | |
clear() | 모든 리스트 내 아이템 삭제 | del a[:] |
index(x[, start[, end]]) | 리스트에 있는 항목 중 값이 x 와 같은 첫 번째 것의 인덱스 반환. 없으면 ValueError | |
count(x) | 리스트에서 x 가 등장하는 횟수 | |
sort(*, key=None, reverse=False) | 정렬, 정렬 기준과 규칙(오름차순) | |
reverse() | 리스트의 요소들을 거꾸로 배치 | |
copy() | 리스트 복사 | b = a[:] |
print(fruits.count("apple")) # 2, 통계(갯수)
print(fruits.index("banana")) # 3, 찾기(0부터)
fruits.reverse()
# 거꾸로 나열: ["banana", "apple", "kiwi", "banana", "pear", "apple", "orange"]
fruits.append("grape")
# 멤버 추가: ["banana", "apple", "kiwi", "banana", "pear", "apple", "orange", "grape"]
fruits.sort()
# 정렬(a~z): ["apple", "apple", "banana", "banana", "grape", "kiwi", "orange", "pear"]
print(fruits.pop()) # pear, 마지막 멤버
리스트 묶기
2개 이상의 리스트를 동시에 취급할 수 있습니다.
6_Collections > 01-2a_Zip.pyquestions = ["name", "quest", "favorite color"]
answers = ["lancelot", "the holy grail", "blue"]
for q, a in zip(questions, answers):
print("What is your {0}? It is {1}.".format(q, a))
# What is your name? It is lancelot.
# What is your quest? It is the holy grail.
# What is your favorite color? It is blue.
리스트간 비교하기
- 앞의 멤버부터 비교한다.
- 멤버의 수가 많은 것이 우선한다.
- 세부 리스트가 있다면, 세부 리스트끼리 비교한다.
a = (1, 2, 3, 100)
b = (1, 2, 4, -100)
# (1, 2, 4, -100) > (1, 2, 3, 100)
a = (1, 2)
b = (1, 2, -1)
# (1, 2, -1) > (1, 2)
a = (1, 2, ("zz", "aa"))
b = (1, 2, ("aa", "ab", "ac"), 4)
# (1, 2, ('zz', 'aa')) > (1, 2, ('aa', 'ab', 'ac'), 4)
응용
stack으로 이용하기
6_Collections > 01-4_As stack.pystack = [3, 4, 5]
stack.append(6) # [3, 4, 5, 6]
stack.append(7) # [3, 4, 5, 6, 7]
stack.pop() # 7 # [3, 4, 5, 6]
stack.pop() # 6 # [3, 4, 5]
stack.pop() # 5 # [3, 4]
queue로 이용하기
6_Collections > 01-5_As queue.pyqueue = deque(["Eric", "John", "Michael"])
queue.append("Terry") # deque(['Eric', 'John', 'Michael', 'Terry'])
queue.append("Graham") # deque(['Eric', 'John', 'Michael', 'Terry', 'Graham'])
print(queue.popleft()) # "Eric" - The first to arrive now leaves
print(queue.popleft()) # "John" - The second to arrive now leaves
# deque(['Michael', 'Terry', 'Graham'])
자동생성하기 Comprehension
6_Collections > 01-6_List Comprehensions.pysquares = []
for x in range(10):
squares.append(x**2)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
comb = [(x, y) for x in [1, 2, 3] for y in [3, 1, 4] if x != y]
# [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
다중 리스트
6_Collections > 01-7_Nested list.pymatrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
]
matrix[1][1] #6
transposed = [[row[i] for row in matrix] for i in range(4)]
# [ [1, 5, 9],
# [2, 6, 10],
# [3, 7, 11],
# [4, 8, 12]
#]
멤버 삭제
6_Collections > 01-8_Del.pya = [i for i in range(6)] # [0, 1, 2, 3, 4, 5]
del a[0] # [1, 2, 3, 4, 5]
del a[2:4] # [1, 2, 5]
del a[:] # []
tuple
튜플의 특징은 불변(선언하면 추후에 변경이 불가함)입니다. 단순 나열이라는 성질은 리스트와 동일한데, 굳이 튜플을 사용하는 이유는:
- 나중이라도 데이터가 변경되면 안 될 때(해쉬(지문)이라던가, 원본데이터 라든가)
- (리스트보다) 더 적은 메모리 사용
- (리스트보다) 더 빠른 성능
- 의도를 명확히 하고자 (이 변수는 앞으로 불변입니다.)
t = (12345, 54321, "hello!")
t2 = 12345, 54321, "hello!" # 생략 가능
empty = () # 빈 튜플
len(empty) # 길이: 0
singleton = ("hello",) # comma로 끝나도 무시함
# 출력: ('hello',)
len(singleton) # 길이: 1
튜플 복사 예제(피보나치 수열): 데이터의 교환(a↔b)시 임시변수를 만드는 방법보다 효율적
6_Collections > 02-9a_Fibonacci.pya, b = 0, 1
while a < 10:
print(a)
a, b = b, a + b # (a, b) = (b, a + b) 튜플 복사
set
Set(집합): 중복을 인정하지 않는 리스트
6_Collections > 03_Set.pybasket = {"apple", "orange", "apple", "pear", "orange", "banana"}
# {"orange", "banana", "pear", "apple"} - 중복된 것 삭제
"orange" in basket # True - fast membership testing
"crabgrass" in basket # False
합집합, 교집합, 차집합
a = set("abracadabra") # {'b', 'c', 'r', 'a', 'd'}
b = set("alacazam") # {'c', 'z', 'a', 'l', 'm'}
print(a - b) # {'b', 'r', 'd'} = 차집합(A-B), 그룹A에만 있음
print(a | b) # {'b', 'c', 'r', 'z', 'a', 'l', 'd', 'm'} = 합집합
print(a & b) # {'c', 'a'} = 교집합
print(a ^ b) # {'b', 'm', 'd', 'r', 'z', 'l'} = 합집합 - 교집합
dictionary
key:value(색인:값)을 하나의 멤버로 저장합니다.
6_Collections > 04_Dictionary.pytel = {"jack": 4098, "sape": 4139}
tel["guido"] = 4127 # guido의 전화번호를 등록
# {"jack": 4098, "sape": 4139, "guido": 4127}
tel["jack"] # 4098
del tel["sape"] # sape 삭제
tel["irv"] = 4127 # irv 등록
# {"jack": 4098, "guido": 4127, "irv": 4127}
list(tel) # ["jack", "guido", "irv"]
tel = sorted(tel) # 정렬(오름차순)
# ["guido", "irv", "jack"]
"guido" in tel # True
"jack" not in tel # False
자동완성
6_Collections > 04-1_DictionaryComprehension.pydict = {x: x**2 for x in (2, 4, 6)}
# {2: 4, 4: 16, 6: 36}
루프 기술
6_Collections > 04-2_Loop technique.pyknights = {"gallahad": "the pure", "robin": "the brave"}
for k, v in knights.items():
print(k, v)
# gallahad the pure
# robin the brave
typecast
강제로 콜렉션 타입을 변경 할 수 있습니다.
6_Collections > 05_Typecast.pymenu = {"커피", "우유", "주스"}
# {'커피', '우유', '주스'}
menu = list(menu)
# ['커피', '우유', '주스']
menu = tuple(menu)
# ('커피', '우유', '주스')
menu = set(menu)
# {'커피', '주스', '우유'}