import tkinter as tk
from tkinter import ttk # ttk를 임포트 함
from tkinter import scrolledtext
from tkinter import Menu
from tkinter import messagebox as msg
from tkinter import Spinbox
from tkinter import SCROLL
from time import sleep
win = tk.Tk() # Tk 클래스의 인스턴스 생성
win.title("파이썬 GUI") # 제목을 설정하기 위한 인스턴스 변수 사용
win.iconbitmap('pyc.ico')
tabControl = ttk.Notebook(win)
tab1 = ttk.Frame(tabControl)
tabControl.add(tab1, text='Tab 1')
tab2 = ttk.Frame(tabControl)
tabControl.add(tab2, text='Tab 2')
tabControl.pack(expand=1, fill="both")
# tab1을 부모로 사용한 라벨프레임
mighty = ttk.LabelFrame(tab1, text=' Mighty Python ')
mighty.grid(column=0, row=0, padx=8, pady=4)
# mighty를 부모로 사용한 라벨
a_label = ttk.Label(mighty, text="Enter a name:")
a_label.grid(column=0, row=0, sticky='W')
name = tk.StringVar() # StringVar 변수를 생성하고 tkinter의 별칭으로 tk를 사용
name_entered = ttk.Entry(mighty, width=12, textvariable=name) # ttk.Entry 위젯을 생성하고 다른 변수에 할당
name_entered.grid(column=0, row=1) # 위젯의 위치 지정
name_entered.focus()
# 다른 라벨 추가하기
ttk.Label(mighty, text="Choose a number:").grid(column=1, row=0)
number = tk.StringVar()
number_chosen = ttk.Combobox(mighty, width=12, textvariable=number) # ttk.Combobox 위젯 생성
number_chosen['values'] = (1, 2, 4, 10, 100) # 콤보박스 위젯 값 할당
number_chosen.grid(column=1, row=1) # 콤보박스 위젯 위치 지정
number_chosen.current(0)
def click_me(): # click_me() 함수 정의
action.configure(text='Hello ' + name.get())
a_label.configure(foreground='red')
action = ttk.Button(mighty, text="Click Me!", command=click_me) # ttkfmf 사용해 버튼을 생성하고 text 속성을 전잘
action.grid(column=2, row=1)
action.configure(state='enable')
# Spinbox 콜백
def _spin():
value = spin.get()
print(value)
# scrol.insert(tk.INSERT, value + 'n')
# Spinbox2 콜백
def _spin2():
value = spin2.get()
print(value)
# scrol.insert(tk.INSERT, value + '\n')
# Spinbox 위젯 추가하기
spin = Spinbox(mighty, from_=0, to=10, width=10, bd=8, command=_spin)
spin.grid(column=0, row=2)
spin2 = Spinbox(mighty, values=('0 50 100'), width=10, bd=8, command=_spin2, relief=tk.RIDGE)
spin2.grid(column=1, row=2)
spin3 = Spinbox(mighty, values=('0 50 100'), width=10, bd=8, command=_spin2, relief=tk.FLAT)
spin3.grid(column=2, row=2)
# 스크롤되는 텍스트 위젯
scrol_w = 50 # 높이와 넓이를 위한 변수 정의
scrol_h = 5
# ScrolledText 위젯 생성
scr = scrolledtext.ScrolledText(mighty, width=scrol_w, height=scrol_h, wrap=tk.WORD)
scr.grid(column=0, row=5, sticky='WE', columnspan=3) # 스크롤 위젯의 위치 지정
mighty2 = ttk.LabelFrame(tab2, text= 'The Snake ')
mighty2.grid(column=0, row=0, padx=8, pady=4)
chVarDis = tk.IntVar()
check1 = tk.Checkbutton(mighty2, text="Disabled", variable=chVarDis, state='disabled')
check1.select() # 상태를 select로 설정
check1.grid(column=0, row=4, sticky=tk.W, padx= 20, pady=10) # 체크박스 위치 지정
chVarUn = tk.IntVar()
check2 = tk.Checkbutton(mighty2, text="UnChecked", variable=chVarUn)
check2.deselect() # 상태를 deselect로 설정
check2.grid(column=1, row=4, sticky=tk.W, padx= 20, pady=10)
chVarEn = tk.IntVar() # tk.IntVar 인스턴스 생성
check3 = tk.Checkbutton(mighty2, text="Enabled", variable=chVarEn)
check3.select() # 상태를 select로 설정
check3.grid(column=2, row=4, sticky=tk.W, padx= 20, pady=10)
# 생상 이름을 저장하는 모듈 레벨의 전역변수 생성
COLOR1 = "Blue"
COLOR2 = "Gold"
COLOR3 = "Red"
# 라디오 버튼을 위한 콜백함수 생성
def radCall():
radSel=radVar.get()
if radSel == 1: mighty2.configure(tex=COLOR1)
elif radSel == 2: mighty2.configure(text=COLOR2)
elif radSel == 3: mighty2.configure(text=COLOR3)
# 1개의 변수를 사용하여 3개의 라디오버튼 생성
radVar = tk.IntVar()
# 3개의 tk 라디오 버튼 생성
for col in range(3):
curRad = tk.Radiobutton(mighty2, variable=radVar, value=col, command=radCall)
curRad.grid(column=col, row=6, sticky=tk.W)
# Tab2에 프로그레스바 추가
progress_bar = ttk.Progressbar(tab2, orient='horizontal', length=286, mode='determinate')
progress_bar.grid(column=0, row=3, pady=2)
# 콜백 함수에서 상태바 업데이트 하기
def run_progressbar():
progress_bar["maximum"] = 100
for i in range(101):
sleep(0.05)
progress_bar["value"] = i # 프로그레스바 증가시키기
progress_bar.update() # 순환문에서 update() 호출
progress_bar["value"] = 0 # 프로그레스바 리셋 및 정리
# start 프로그레스바
def start_progressbar():
progress_bar.start()
# stop 프로그레스바
def stop_progressbar():
progress_bar.stop()
# 0.1초 후 프로그레스바 stop
def progressbar_stop_after(wait_ms=1000):
win.after(wait_ms, progress_bar.stop)
#라벨 프레임
buttons_frame = ttk.LabelFrame(mighty2, text=' ProgressBar ')
buttons_frame.grid(column=0, row=7, sticky='W', columnspan=2, padx=20, pady=40)
# Progressbar 명령 버튼을 추가
ttk.Button(buttons_frame, text=" Run Progressbar ", command=run_progressbar).grid(column=0, row=0, sticky='W')
ttk.Button(buttons_frame, text=" Start Progressbar ", command=start_progressbar).grid(column=0, row=1, sticky='W')
ttk.Button(buttons_frame, text=" Stop immediately ", command=stop_progressbar).grid(column=0, row=2, sticky='W')
ttk.Button(buttons_frame, text=" Stop after second ", command=progressbar_stop_after).grid(column=0, row=3, sticky='W')
# 순환문에 buttons_frame의 자식인 추가적인 패딩 추가
for child in buttons_frame.winfo_children():
child.grid_configure(padx=2, pady=2)
# Tab2의 자식으로 추가적인 패딩 추가
for child in mighty2.winfo_children():
child.grid_configure(padx=8, pady=2)
# 각 라벨 주변에 공간 추가하기
for child in mighty.winfo_children():
child.grid_configure(padx=8)
for child in mighty2.winfo_children():
child.grid_configure(padx=8)
# 메뉴바 생성하기
menu_bar = Menu(win)
win.config(menu=menu_bar)
def _quit():
win.quit()
win.destroy()
exit()
# 메뉴를 생성하고 메뉴 아이템 추가하기
file_menu = Menu(menu_bar, tearoff=0)
file_menu.add_command(label="New")
file_menu.add_separator()
file_menu.add_command(label="Exit", command=_quit)
menu_bar.add_cascade(label="File", menu=file_menu)
def _msgBox():
msg.showinfo('Python Message Info Box', 'A Python GUI created using tkinter' 'This year is 2024.')
msg.showwarning('Python Message Warning Box', 'A Python GUI created using tkinter' '\nWarning: There might be a bug in this code.')
msg.showerror('Python Message Error Box', 'A Python GUI created using tkinter:' '\nError : Houston ~ we Do have a serious PROBLEM!')
answer = msg.askyesnocancel("Python Message Multi Choice Box", "Are you sure you really wish to do this?")
help_menu = Menu(menu_bar, tearoff=0)
help_menu.add_command(label="About", command=_msgBox)
menu_bar.add_cascade(label="Help", menu=help_menu)
win.mainloop()
프로그레스바를 생성하고 시작 및 중지하는 새 버튼을 만드는 단계는 다음과 같다.
모듈의 상단에 sleep을 임포트해 추가한다.
from time import sleep
3개의 라디오 버튼 위젯 생성한다.
# 3개의 tk 라디오 버튼 생성
for col in range(3):
curRad = tk.Radiobutton(mighty2, variable=radVar, value=col, command=radCall)
curRad.grid(column=col, row=6, sticky=tk.W)
# 콜백 함수에서 상태바 업데이트 하기
def run_progressbar():
progress_bar["maximum"] = 100
for i in range(101):
sleep(0.05)
progress_bar["value"] = i # 프로그레스바 증가시키기
progress_bar.update() # 순환문에서 update() 호출
progress_bar["value"] = 0 # 프로그레스바 리셋 및 정리
# start 프로그레스바
def start_progressbar():
progress_bar.start()
# stop 프로그레스바
def stop_progressbar():
progress_bar.stop()
# 0.1초 후 프로그레스바 stop
def progressbar_stop_after(wait_ms=1000):
win.after(wait_ms, progress_bar.stop)
프로그레스바를 담기 위한 컨테이너를 생성한다.
# 프로그레스바를 담기 위한 컨테이너 생성
buttons_frame = ttk.LabelFrame(mighty2, text=' ProgressBar ')
buttons_frame.grid(column=0, row=7, sticky='W', columnspan=2, padx=20, pady=40)
다음 4개의 새로운 버튼을 생성한다.
# Progressbar 명령 버튼을 추가
ttk.Button(buttons_frame, text=" Run Progressbar ", command=run_progressbar).grid(column=0, row=0, sticky='W')
ttk.Button(buttons_frame, text=" Start Progressbar ", command=start_progressbar).grid(column=0, row=1, sticky='W')
ttk.Button(buttons_frame, text=" Stop immediately ", command=stop_progressbar).grid(column=0, row=2, sticky='W')
ttk.Button(buttons_frame, text=" Stop after second ", command=progressbar_stop_after).grid(column=0, row=3, sticky='W')
순환문에 버튼프레임의 자식인 추가적인 패딩을 추가하고, Tab2의 자식으로 추가적인 패딩을 추가한다.
# 순환문에 buttons_frame의 자식인 추가적인 패딩 추가
for child in buttons_frame.winfo_children():
child.grid_configure(padx=2, pady=2)
# Tab2의 자식으로 추가적인 패딩 추가
for child in mighty2.winfo_children():
child.grid_configure(padx=8, pady=2)
메시지 박스는 사용자에게 피드백을 제공하는 팝업창이며, 잠재적 문제와 치명적인 오류를 암시하는 정보가 될 수 있다.
먼저 Help>About 메뉴를 만들고 About 메뉴를 클릭시 정보, 경고, 에러 메시지를 출력하는 프로그램을 만든다.
출력된 메시지 박스
전체코드
import tkinter as tk
from tkinter import ttk # ttk를 임포트 함
from tkinter import Menu
from tkinter import messagebox as msg
win = tk.Tk() # Tk 클래스의 인스턴스 생성
win.title("GUI Message_Box") # 제목을 설정하기 위한 인스턴스 변수 사용
# 메뉴바 생성하기
menu_bar = Menu(win)
win.config(menu=menu_bar)
def _quit():
win.quit()
win.destroy()
exit()
# 메뉴를 생성하고 메뉴 아이템 추가하기
file_menu = Menu(menu_bar, tearoff=0)
file_menu.add_command(label="New")
file_menu.add_separator()
file_menu.add_command(label="Exit", command=_quit)
menu_bar.add_cascade(label="File", menu=file_menu)
def _msgBox():
msg.showinfo('Python Message Info Box', 'A Python GUI created using tkinter' 'This year is 2024.')
msg.showwarning('Python Message Warning Box', 'A Python GUI created using tkinter' '\nWarning: There might be a bug in this code.')
msg.showerror('Python Message Error Box', 'A Python GUI created using tkinter:' '\nError : Houston ~ we Do have a serious PROBLEM!')
answer = msg.askyesnocancel("Python Message Multi Choice Box", "Are you sure you really wish to do this?")
help_menu = Menu(menu_bar, tearoff=0)
help_menu.add_command(label="About", command=_msgBox)
menu_bar.add_cascade(label="Help", menu=help_menu)
win.mainloop()
코드 설명
import문이 있는 모듈의 맨 위에 다음 코드를 추가한다.
from tkinter import messagebox as msg
다음 메시지박스를 표시하는 4개의 콜백함수를 만든다.
def _msgBox():
msg.showinfo('Python Message Info Box', 'A Python GUI created using tkinter' 'This year is 2024.')
msg.showwarning('Python Message Warning Box', 'A Python GUI created using tkinter' '\nWarning: There might be a bug in this code.')
msg.showerror('Python Message Error Box', 'A Python GUI created using tkinter:' '\nError : Houston ~ we Do have a serious PROBLEM!')
answer = msg.askyesnocancel("Python Message Multi Choice Box", "Are you sure you really wish to do this?")
파이썬은 매우 강력한 언어다. 내장된 tkinter 모듈이 함께 제공되므로 단 몇 줄의 코드로 파이썬 GUI를 만들 수 있다.
아래 그림은 완성된 파이썬 GUI 폼이다.
파이썬 GUI가 실행된 모습
전체코드
import tkinter as tk
from tkinter import ttk # ttk를 임포트 함
from tkinter import scrolledtext
win = tk.Tk() # Tk 클래스의 인스턴스 생성
win.title("파이썬 GUI") # 제목을 설정하기 위한 인스턴스 변수 사용
a_label = ttk.Label(win) # ttk를 사용한 라벨 추가
a_label.grid(column=0, row=0) # 라벨의 위치 지정
def click_me(): # click_me() 함수 정의
action.configure(text='Hello ' + name.get())
a_label.configure(foreground='red')
#a_label.configure(text='A Red Label')
ttk.Label(win, text="이름 입력").grid(column=0, row=0)
name = tk.StringVar() # StringVar 변수를 생성하고 tkinter의 별칭으로 tk를 사용
name_entered = ttk.Entry(win, width=12, textvariable=name) # ttk.Entry 위젯을 생성하고 다른 변수에 할당
name_entered.grid(column=0, row=1) # 위젯의 위치 지정
name_entered.focus()
action = ttk.Button(win, text="Click Me!", command=click_me) # ttkfmf 사용해 버튼을 생성하고 text 속성을 전잘
action.grid(column=2, row=1)
action.configure(state='enable')
ttk.Label(win, text="번호 선택").grid(column=1, row=0) # ttk.Label 위젯 생성
number = tk.StringVar()
number_chosen = ttk.Combobox(win, width=12, textvariable=number) # ttk.Combobox 위젯 생성
number_chosen['values'] = (1, 2, 4, 42, 1000) # 콤보박스 위젯 값 할당
number_chosen.grid(column=1, row=1) # 콤보박스 위젯 위치 지정
number_chosen.current(0)
# 3개의 체크박스 생성
chVarDis = tk.IntVar() # tk.IntVar 인스턴스 생성
check1 = tk.Checkbutton(win, text="Disabled", variable=chVarDis, state='disabled')
check1.select() # 상태를 select로 설정
check1.grid(column=0, row=4, sticky=tk.W) # 체크박스 위치 지정
chVarUn = tk.IntVar() # tk.IntVar 인스턴스 생성
check2 = tk.Checkbutton(win, text="UnChecked", variable=chVarUn)
check2.deselect() # 상태를 deselect로 설정
check2.grid(column=1, row=4, sticky=tk.W)
chVarEn = tk.IntVar() # tk.IntVar 인스턴스 생성
check3 = tk.Checkbutton(win, text="Enabled", variable=chVarEn)
check3.select() # 상태를 select로 설정
check3.grid(column=2, row=4, sticky=tk.W)
# 생상 이름을 저장하는 모듈 레벨의 전역변수 생성
COLOR1 = "Blue"
COLOR2 = "Gold"
COLOR3 = "Red"
# 라디오 버튼을 위한 콜백함수 생성
def radCall():
radSel=radVar.get()
if radSel == 1: win.configure(background=COLOR1)
elif radSel == 2: win.configure(background=COLOR2)
elif radSel == 3: win.configure(background=COLOR3)
# 1개의 변수를 사용하여 3개의 라디오버튼 생성
radVar = tk.IntVar()
# 3개의 tk 라디오 버튼 생성
# 그리드 레이아웃을 사용해 배치
rad1 = tk.Radiobutton(win, text=COLOR1, variable=radVar, value=1, command=radCall)
rad1.grid(column=0, row=5, sticky=tk.W, columnspan=3) # 그리드 레이아웃을 사용해 위치 지정
rad2 = tk.Radiobutton(win, text=COLOR2, variable=radVar, value=2, command=radCall)
rad2.grid(column=1, row=5, sticky=tk.W, columnspan=3)
rad3 = tk.Radiobutton(win, text=COLOR3, variable=radVar, value=3, command=radCall)
rad3.grid(column=2, row=5, sticky=tk.W, columnspan=3)
# 스크롤되는 텍스트 위젯
scrol_w = 50 # 높이와 넓이를 위한 변수 정의
scrol_h = 5
# ScrolledText 위젯 생성
scr = scrolledtext.ScrolledText(win, width=scrol_w, height=scrol_h, wrap=tk.WORD)
scr.grid(column=0, columnspan=3) # 스크롤 위젯의 위치 지정
win.resizable(True, False) # Tk 인스턴스 변수 win의 resizable 메소드 호출
win.mainloop() # 윈도우 메인 이벤트 순환문 시작
그럼 이제부터 위 전체코드에 대한 동작원리를 차례대로 살펴본다.
1. GUI 폼에 라벨 추가하기
라벨은 GUI에 값을 추가하는 매우 간단한 위젯이다. 이는 사용자에게 엔트리 위젯의 의미를 안내하며 사용자가 데이터를 입력할 필요없이 위젯이 표시하는 데이터를 설명할 수도 있다.
import tkinter as tk
from tkinter import ttk # ttk를 임포트 함
from tkinter import scrolledtext
win = tk.Tk() # Tk 클래스의 인스턴스 생성
win.title("파이썬 GUI") # 제목을 설정하기 위한 인스턴스 변수 사용
a_label = ttk.Label(win) # ttk를 사용한 라벨 추가
a_label.grid(column=0, row=0) # 라벨의 위치 지정
ttk.Label(win, text="이름 입력").grid(column=0, row=0)
위 코드에서는 tkinter 패키지에서 별도의 모듈을 가져온다. ttk 모듈에는 GUI를 멋지게 보이게 하는 노트북, 프로그레스바, 라벨과 색다른 버튼과 같은 고급 위젯이 있다. ttk는 tkinter 패키지 내의 확장이다.
은 mainloop를 호출하기 직전에 라벨을 GUI에 추가한다. window 인스턴스를 ttk.Label 생성자에 전달하고 text 속성을 설정한다.
2. 버튼 생성 및 텍스트박스 위젯 생성하기
아래 그림은 이름 입력칸에 문자를 입력하고 Click me! 버튼을 클릭하였을 때 모습이다.
이름입력칸에 문자를 입력하고 click me!를 누른 모습
a_label = ttk.Label(win) # ttk를 사용한 라벨 추가
a_label.grid(column=0, row=0) # 라벨의 위치 지정
def click_me(): # click_me() 함수 정의
action.configure(text='Hello ' + name.get())
a_label.configure(foreground='red')
#a_label.configure(text='A Red Label')
ttk.Label(win, text="이름 입력").grid(column=0, row=0)
name = tk.StringVar() # StringVar 변수를 생성하고 tkinter의 별칭으로 tk를 사용
name_entered = ttk.Entry(win, width=12, textvariable=name) # ttk.Entry 위젯을 생성하고 다른 변수에 할당
name_entered.grid(column=0, row=1) # 위젯의 위치 지정
name_entered.focus()
action = ttk.Button(win, text="Click Me!", command=click_me) # ttkfmf 사용해 버튼을 생성하고 text 속성을 전잘
action.grid(column=2, row=1)
action.configure(state='enable')
1단계에서 새로운 파이썬 모듈을 만들고 2단계에서 tkinter의 stringVar 타입을 추가하고 name 변수에 저장한다. 엔트리 위젯을 생성할 때 이 변수를 사용하고 엔트리 위젯의 textvariable 속성에 할당한다. 엔트리 위젯에서 텍스트를 입력할 때마다 이 텍스트는 name 변수에 저장된다.
action.configure(text='Hello ' + name.get())
name.get()을 사용해 엔트리 위젯의 값을 가져온다. 버튼을 생성할 때 action 변수에 참조를 저장한다. action 변수를 사용해 버튼의 configure 메소드를 호출하고 버튼의 텍스트를 업데이트 한다.
name = tk.StringVar()
이는 변수 name을 생성한다. 이 변수는 엔트리 위젯에 바인딩돼 있으며 click_me() 함수에서 이 변수에 대해 get()을 호출해 엔트리 위젯의 값을 검색할 수 있다.
3. 콤보박스 위젯 생성하기
여기서는 초기 기본값을 가질 수 있는 드롭다운 콤보박스를 추가해 GUI를 개선한다. 사용자의 선택을 제한할 수 있지만 사용자가 원하는 대로 입력하도록 허용할 수도 있다.
ttk.Label(win, text="번호 선택").grid(column=1, row=0) # ttk.Label 위젯 생성
number = tk.StringVar()
number_chosen = ttk.Combobox(win, width=12, textvariable=number) # ttk.Combobox 위젯 생성
number_chosen['values'] = (1, 2, 4, 42, 1000) # 콤보박스 위젯 값 할당
number_chosen.grid(column=1, row=1) # 콤보박스 위젯 위치 지정
number_chosen.current(0)
여기서는 3개의 라디오 버튼을 만들어 메인폼에 할당하고 콜백함수에서 사용할 변수를 전달해 메인 윈도우의 배경을 변경하는 액션을 생성한다.
Gold 라디오 버튼을 눌렀을 때 모습
6. 스크롤 되는 텍스트 위젯 만들기
메모장 같은 위젯으로 줄 바꿈과 텍스트가 ScrolledText 위젯의 높이보다 커지면 자동으로 세로 스크롤 막대가 활성화된다.
scrol_w = 50 # 높이와 넓이를 위한 변수 정의
scrol_h = 5
# ScrolledText 위젯 생성
scr = scrolledtext.ScrolledText(win, width=scrol_w, height=scrol_h, wrap=tk.WORD)
scr.grid(column=0, columnspan=3) # 스크롤 위젯의 위치 지정
# win.resizable(True, False) # Tk 인스턴스 변수 win의 resizable 메소드 호출
win.mainloop() # 윈도우 메인 이벤트 순환문 시작
from tkinter import scrolledtext
먼저 ScrolledText 위젯 클래스가 포함된 모듈을 가져온다.
scrol_w = 50 # 높이와 넓이를 위한 변수 정의
scrol_h = 5
만들고자 하는 ScrolledText 위젯의 너비와 높이를 정의한다. 이 값은 ScrolledText 위젯 생성자에 전달되는 하드코딩된 값이다.
#include<stdio.h>
int main(void)
{
int num1 = 12;
int num2 = 12;
printf("num1: %d \n", num1);
printf("num1++: %d \n", num1++); // 후위 증가
printf("num1: %d \n", num1);
printf("num2: %d \n", num2);
printf("++num2: %d \n", ++num2); // 전위 증가
printf("num2: %d \n", num2);
return 0;
}
++num : 값을 1 증가 후, 속한 문장의 나머지를 진행한다. (선 증가, 후 연산)
num++ : 속한 문장을 먼저 진행한 후 값을 1 증가한다. (선 연산, 후 증가)
--num : 값을 1감소 후, 속한 문장의 나머지를 진행한다. (선 감소, 후 연산)
num-- : 속한 문장을 먼저 진행한 후, 값을 1 감소한다. (선 연산, 후 감소)
++ 연산자와 -- 연산자는 이름 그대로 값을 1 증가 및 감소시키는 연산자이다. 그런데 이 두 연산자는 삽입된 위치에 따라서 그 의미가 달라진다. 피연산자의 왼편에 붙는 경우에는 먼저 변수에 저장된 값을 증가 및 감소시키고 나서 문장의 나머지 부분을 실행하게 된다. 반면 피연산자의 오른쪽에 붙는 경우에는 문장 전체를 실행한 다음에 값을 증가 및 감소시키게 된다.
출력결과
2. 감소 연산자
#include<stdio.h>
int main(void)
{
int num1 = 10;
int num2 = (num1--)+2;
printf("num1: %d \n", num1);
printf("num2: %d \n", num2); // 후위 증가
return 0;
}
출력결과
6행에서는 변수 num1에 대해서 선 연산 후 감소를 진행하고 있다. 그런데 이 연산의 앞과 뒤에 소괄호가 채워져 있다. C언어세는 소괄호도 연산자이다. 이는 수학의 소괄호와 의미가 같다. 즉 먼저 연산하라는 뜻이다.
웹에서 파일을 업로드하려면 <form> 태그의 enctype 속성을 multipart/form-data로 설정해야 한다. 그리고 <input> 태그의 type 속성을 file로 설정해야 업로드할 파일을 선택하는 양식을 생성할 수 있다. name 속성을 upload로 설정하면 업로드한 파일이 $_POST["upload"] 배열에 저장된다.
$_FILES["upload"]["name"]은 업로드된 파일명을 나타낸다. 따라서 $file_path에는 저장할 폴더와 파일명을 포함한 경로가 저장된다.
move_uploaded_file($_FILES["upload"]["tmp_name"], $file_path)는 업로드된 파일을 설정한 파일 경로에 저장한다는 의미이다. 여기서 $_FILES["upload"]["tmp_name"]은 서버에 임시로 저장된 업로드된 파일명이고 $file_path는 업로드된 파일을 저장할 경로를 의미한다.
$img_path는 <img> 태그의 src 속성으로 설정한 폴더와 이미지 파일명을 포함한 경로를 의미한다.
$_POST["comment"]는 사용자가 텍스트 영역에 입력한 내용을 의미한다.
move_uploaded_file() 함수는 HTTP POST를 이용하여 업로드된 파일을 지정된 경로에 저장할 때 사용한다. 만약 해당 경로에 동일한 파일이 있으면 덮어쓰기를 한다.
체크박스를 생성하려면 <input> 태그의 type 속성을 checkbox로 설정해야 한다. 그리고 중복 선택이 가능하도록 name 속성은 배열(hobby[]) 로 설정하고, value 속성에는 화면에 출력할 각 항목을 설정한다. 체크박스에서 선택된 항목의 value 속성값은 $_POST["hobby"]로 전달된다. checked 속성은 초깃값을 의미하며 실행 결과를 보면 맛집탐방이 초깃값이다.
체크박스의 항목을 선택하고 <확인>을 클릭하면 action속성에 설정한 view5.php 파일로 이동한다.
$_POST["hobby"]에는 체크박스의 name 속성으로 설정한 hobby[]의 value 속성 값이 배열 형태로 저장된다. 즉 체크박스 항목의 value 속성값이 $_POST["hobby"][0], $_POST["hobby"][1]...에 차례대로 전달된다. count() 함수는 배열의 개수를 세는데 사용하고 변수 $num에는 선택된 체크박스 항목의 개수가 저장된다.
for문은 배열의 개수만큼 반복 수행한다.
체크박스에서 선택된 항목의 value 속성값을 화면에 출력한다.
항목 사이에 쉼표(,)를 넣어 출력하기 위해 if 구문을 이용한다. 항목의 마지막이 아니라면 항목 사이에 쉼표를 출력하라는 의미이다.
다음 코드는 간단한 해시 함수를 사용하여 정수가 키인 딕셔너리를 구현하고 있다. 여기에서 기본적인 아이디어는 intDict 클래스의 인스턴스를 해시 버킷 리스트로 나타내는 것이며, 각 버킷은 키/값의 쌍들로 이루어진 리스트이다. 각 버킷을 리스트로 구현함으로 버킷에 해시되는 값들을 리스트에 저장하여 충돌을 해결할 수 있다. 인스턴스 변수 buckets는 numBuckets의 개수만큼의 빈 리스트로 초기화한다. dictkey키로 엔트리를 검색하거나 저장하려고 할 때 해시함수 %를 사용하여 dictkey를 정수로 반환하고 그 정수를 사용하여 buckets를 인덱스하여 해당하는 dictkey와 연관된 해시 버킷을 찾아낸다. 그 다음엔 그 버킷을 선형적으로 검색하여 dictkey키로 된 엔트리가 있는지 확인한다. 검색을 하는 경우에는 그 키로 된 엔트리가 없다면 None을 반환한다. 저장을 하려고 하는 경우에는 이미 들어가 있는 엔트리가 있다면 그 엔트리의 값을 대체하거나 엔트리가 없다면 새로운 엔트리를 추가한다.
# 해싱을 사용하여 딕셔너리 구현하기
class intDict(object):
def __init__(self, numBuckets):
self.buckets = []
self.numBuckets = numBuckets
for i in range(numBuckets):
self.buckets.append([])
def addEntry(self, dictKey, dictVal):
hashBucket = self.buckets[dictKey%self.numBuckets]
for i in range(len(hashBucket)):
if hashBucket[i][0] == dictKey:
hashBucket[i] = (dictKey, dictVal)
return
hashBucket.append((dictKey, dictVal))
def getValue(self, dicKey):
hashBucket = self.buckets[dicKey%self.numBuckets]
for e in hashBucket:
if e[0] == dicKey:
return e[1]
return None
def __str__(self):
result = '{'
for b in self.buckets:
for e in b:
result = result + str(e[0]) + ':' + str(e[1]) + ', '
return result[:-1] + '}'
import random
D = intDict(29)
for i in range(20):
key = random.randint(0, 10**5)
D.addEntry(key, i)
print('The value of the intDict is:')
print(D)
print('\n', 'The buckets are:')
for hashBucket in D.buckets:
print(' ', hashBucket)
__str__ 메소드에서 보면 요소들이 추가된 순서에 관계없이 키가 해시하려는 값의 순서로 딕셔너리를 만들고 있다는 것을 알 수가 있다. 이것이 dict 자료형의 키의 순서를 왜 예측할 수 없는지를 설명해준다. 위의 코드는 먼저 20개의 엔트리로 intDict를 만든다. 엔트리의 값은 정수 0에서 19이다. 키는 0과 10^5 -1 사이의 정수 중 하나를 임의로 선택한다. 그 다음에는 클래스에 정의된 __str__ 메소드를 사용하여 intDict를 출력한다. 마직막으로 D.bucket을 반복하여서 각 해시 버킷을 출력한다.
합병 정렬은 전형적인 분할정복 알고리즘으로 볼 수 있으며 1945년에 존 폰 노이만이 개발하였고 아직까지도 많이 사용되고 있다. 분할 정복 알고리즘처럼 재귀적으로 가장 쉽게 설명할 수 있다.
1. 리스트의 길이가 0이나 1일 때 리스트는 이미 정렬된 상태이다.
2. 리스트에 한 개 이상의 요소가 들어있으면 리스트를 두 개의 리스트로 나눈 후에 합병정렬을 사용하여 나뉘어진 리스트를 정렬한다.
3. 결과를 합병한다.
우선 각 리스트의 첫 번째 요소를 보고 둘 중 작은 요소를 결과 리스트의 끝으로 옮기는 것이다. 만약 둘 중 하나의 리스트가 비게 되면, 남아있는 리스트의 요소들을 모두 결과 리스트에 옮기면 된다.
다음 코드는 두 개의 배치 함수를 정의하고 있으며 이 두 함수를 이용하여 두 가지 방법으로 리스트를 정렬하고 있다. 각 함수는 표준 파이썬 모듈 string을 가져와서 그 모듈의 split 함수를 사용한다. split의 인자는 두개의 문자열들이고 두번 째 인자는 문자열을 부분열로 나눌 때 사용하는 구분자를 나타낸다.
# 이름 리스트 정렬하기
def merge(left, right, compare):
result = []
i, j = 0, 0
while i < len(left) and j < len(right):
if compare(left[i], right[j]):
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
while (i < len(left)):
result.append(left[i])
i += 1
while (j < len(right)):
result.append(right[j])
j += 1
return result
import operator
def mergeSort(L, compare = operator.lt):
if len(L) < 2:
return L[:]
else:
middle = len(L)//2
left = mergeSort(L[:middle], compare)
right = mergeSort(L[middle:], compare)
return merge(left, right, compare)
from string import *
def lastNameFirstName(name1, name2):
name1 = name1.split(' ')
name2 = name2.split(' ')
if name1[1] != name2[1]:
return name1[1] < name2[1]
else :
return name1[0] < name2[0]
def firstNameLastName(name1, name2):
name1 = name1.split(' ')
name2 = name2.split(' ')
if name1[0] != name2[0]:
return name1[0] < name2[0]
else:
return name1[1] < name2[1]
L = ['Chris Terman', 'Tom Brady', 'Eric Grimson', 'Gisels Bundchen']
newL = mergeSort(L, lastNameFirstName)
print('Sorted by last name =', newL)
newL = mergeSort(L, firstNameLastName)
print('Sorted by first name =', newL)
L = [3, 5, 2]
D = {'a' : 12, 'c' : 5, 'b' : 'dog'}
print(sorted(L))
L.sort()
print(L)
print(sorted(D))
파이썬 함수 sorted은 리스트나 딕셔너리처럼 반복 가능한 객체를 첫 번째 인자로 받아서 정렬된 새로운 리스트를 반환한다.
출력 결과
Sorted by last name = ['Tom Brady', 'Gisels Bundchen', 'Eric Grimson', 'Chris Terman']
Sorted by first name = ['Chris Terman', 'Eric Grimson', 'Gisels Bundchen', 'Tom Brady']
[2, 3, 5]
[2, 3, 5]
['a', 'b', 'c']
sorted 함수를 딕셔너리에 실행하면 딕셔너리의 키 값으로 정렬한 리스트를 반환한다. list.sort 메소드와 sorted 함수 모두 두 개의 추가 매개변수를 사용할 수가 있다. key 매개변수는 합병정렬에서 compare와 같은 역할을 하는 것으로 비교 함수를 제공하기 위한 것이다. reverse 매개변수는 리스트가 오름차순인지 내림차순인지를 지정해준다. 다음 코드는 L의 요소들을 내림차순으로 정렬하여 출력한다.
L = [[1,2,3], (3,2,1,0), 'abc']
print(sorted(L, key = len, reverse=True))
출력 결과
[(3, 2, 1, 0), [1, 2, 3], 'abc']
list.sort 메소드와 sorted 함수는 안전 정렬 함수이다. 즉 비교할 때 두 개의 요소가 같다면 원래 리스트의 순서가 상대적으로 적용되어 최종 리스트에도 원래 순서로 유지가 된다.