본문 바로가기

PYTHON-BACK

#파이썬 기초 15일차

728x90

계산기 프로세스부터 진행

#2일차 계산기 프로세스 부분 진행
 # gui 가상환경에서 진행함 .\Scripts\activate
from tkinter import Tk, Button, Entry, END

win = Tk()

opers = []
nums = []
numStr = ''

def calc(target):
    ch = target['text']
    global opers, nums, numStr

    if len(ch) == 1:
        if ch != 'C' and ch != '%' and ch != 'v':
            txt.insert(END, ch)

        if ord(ch) >= 48 and ord(ch) <= 57:
            numStr += ch

        if ch == '+' or ch == '-' or ch == '*' or ch == '/':
            nums.append(numStr)
            opers.append(ch)
            numStr = ''

        if ch == '=':
            nums.append(numStr)
            result = int(nums[0])
            for i, oper in enumerate(opers):
                if oper == '+':
                    result += int(nums[i+1])
                elif oper == '-':
                    result -= int(nums[i+1])
                elif oper == '*':
                    result *= int(nums[i+1])
                elif oper == '/':
                    result //= int(nums[i+1])

            txt.insert(END, str(result))

    return 0

txt = Entry(win, justify="right")
txt.grid(row=0, column=0, columnspan=5, pady=2)

btns = [
    [Button(win, text="MC"), Button(win, text="MR"), Button(win, text="MS"), Button(win, text="M+"), Button(win, text="-M")],
    [Button(win, text="<-"), Button(win, text="CE"), Button(win, text="C"),  Button(win, text="+-"), Button(win, text="V")],
    [Button(win, text="7"),  Button(win, text="8"),  Button(win, text="9"),  Button(win, text="/"),  Button(win, text="%")],
    [Button(win, text="4"),  Button(win, text="5"),  Button(win, text="6"),  Button(win, text="*"),  Button(win, text="1/x")],
    [Button(win, text="1"),  Button(win, text="2"),  Button(win, text="3"),  Button(win, text="-"),  Button(win, text="=")],
    [Button(win, text="0"),  Button(win, text="."),  Button(win, text="+")]
]

for btnArr in btns:
    for btn in btnArr:
        def clickEvent(target=btn):
            calc(target)
        btn.config(command=clickEvent)

for i in range(1, 6):
    for j in range(5):
        if i==6 and j==3:
            break
        if i==5 and j==4:
            btns[i-1][j].grid(row=i, column=j, rowspan=2, padx=2, pady=2, sticky='wens')
        else:
            btns[i-1][j].grid(row=i, column=j, padx=2, pady=2, sticky='wens')

btns[5][0].grid(row=6, column=0, columnspan=2, padx=2, pady=2, sticky='wens')
btns[5][1].grid(row=6, column=2, padx=2, pady=2, sticky='wens')
btns[5][2].grid(row=6, column=3, padx=2, pady=2, sticky='wens')

if __name__ == '__main__':
    win.mainloop()

 

4.2 메모장 만들기

 

메모장 개발

  • GUI 구성
  • 메모장 기능 구현
import os
from tkinter import *

root = Tk()
root.title("메모장 이름")
root.geometry("640x480") # 가로 * 세로

# 열기, 저장 파일 이름
filename = "저장됐을 때 파일 이름"

def open_file():
    if os.path.isfile(filename): # 파일 있으면 True, 없으면 False
        with open(filename, "r", encoding="utf8") as file:
            txt.delete("1.0", END) # 텍스트 위젯 본문 삭제
            txt.insert(END, file.read()) # 파일 내용을 본문에 입력

def save_file():
    with open(filename, "w", encoding="utf8") as file:
        file.write(txt.get("1.0", END)) # 모든 내용을 가져와서 저장

menu = Menu(root)

menu_file = Menu(menu, tearoff=0)
menu_file.add_command(label="열기", command=open_file)
menu_file.add_command(label="저장", command=save_file)
menu_file.add_separator()
menu_file.add_command(label="끝내기", command=root.quit)
menu.add_cascade(label="파일", menu=menu_file)

# 편집, 서식, 보기, 도움말(장식)
menu.add_cascade(label="편집")
menu.add_cascade(label="서식")
menu.add_cascade(label="보기")
menu.add_cascade(label="도움말")

# 스크롤 바
scrollbar = Scrollbar(root)
scrollbar.pack(side="right", fill="y")

# 본문 영역
txt = Text(root, yscrollcommand=scrollbar.set)
txt.pack(side="left", fill="both", expand=True)
scrollbar.config(command=txt.yview)

root.config(menu=menu)
root.mainloop()

if __name__ == '__main__':
    root.mainloop()

 

 

프로세스 추가

from tkinter import *
import os
from tkinter.filedialog import *

es = ""

def newFile():
    top.title("제목없음- 메모장")
    file = None
    ta.delete(1.0,END)

def openFile():
    file = askopenfilename(title = "파일 선택", filetypes = (("텍스트 파일", "*.txt"),("모든 파일", "*.*")))
    top.title(os.path.basename(file) + " - 메모장")
    ta.delete(1.0, END)
    f = open(file,"r")
    ta.insert(1.0,f.read())
    f.close()

def saveFile():
    f = asksaveasfile(mode = "w", defaultextension=".txt")
    if f is None:
        return
    ts = str(ta.get(1.0, END))
    f.write(ts)
    f.close()

def cut():
    global es
    es = ta.get(SEL_FIRST, SEL_LAST)
    ta.delete(SEL_FIRST, SEL_LAST)

def copy():
    global es
    es = ta.get(SEL_FIRST, SEL_LAST)

def paste():
    global es
    ta.insert(INSERT, es)

def delete():
    ta.delete(SEL_FIRST, SEL_LAST)

def help():
    he = Toplevel(top)
    he.geometry("200x200")
    he.title("정보")
    lb = Label(he, text = "메모장 버전 1.0\n 파이썬으로 만든 메모장입니다^^")
    lb.pack()


top = Tk()
top.title("메모장")
top.geometry("400x400")


ta = Text(top)
sb = Scrollbar(ta)
sb.config(command = ta.yview)
top.grid_rowconfigure(0, weight=1)
top.grid_columnconfigure(0, weight=1)
sb.pack(side = RIGHT, fill = Y)
ta.grid(sticky = N + E + S + W)

file = None


mb = Menu(top)
fi = Menu(mb, tearoff=0)
fi.add_command(label="새파일", command=newFile)
fi.add_command(label="열기", command=openFile)
fi.add_command(label="저장", command=saveFile)
fi.add_separator()
fi.add_command(label="종료", command=top.destroy)
mb.add_cascade(label="파일", menu=fi)

e = Menu(mb, tearoff=0)
e.add_command(label="잘라내기", command=cut)
e.add_command(label="복사", command=copy)
e.add_command(label="붙이기", command=paste)
e.add_command(label="삭제", command=delete)
mb.add_cascade(label="편집", menu=e)

h = Menu(mb, tearoff=0)
h.add_command(label="메모장 정보", command = help)
mb.add_cascade(label="도움말", menu=h)

top.config(menu=mb)

top.mainloop()

 

 

 

Tips & Examples

1. Magic Commands

 

  • IPython 커널에서 제공되는 기능으로 '%' 또는 '%%' 접두사를 사용하며, 다양한 기능을 수행함
    • 자주 쓰이는 Magic Commands
      • %time  %timeit: 코드 실행 시간 측정
        • %time: 한 번 실행한 시간 표시
        • %timeit: 여러 번 실행하여 평균 및 표준 편차 제공
      • %autosave: 파일 자동 저장 주기 설정
      • %%html: HTML 코드를 셀 내에서 실행하고 표시
      • %system: 시스템 명령어 실행
      • %%writefile: : 파일 쓰기
      • %run: 외부 Python 파일 실행
      • %who: 변수 목록을 표시
      • %store: 변수를 저장하고 공유하는 기능 제공. 주피터 노트북 간의 데이터 공유에 활용됨
      • %env: 환경 변수 나열
      • %matplotlib inline: matplotlib 그래프를 Jupyter Notebook에 표시
      • %history: 코드셀의 실행 이력을 목록으로 취득
  • IPython: Python 언어를 위해 개발된 상호작용적인 컴퓨팅을 위한 명령 셸
    • 자가 검사(introspection): 객체나 함수의 정보를 쉽게 확인할 수 있음
    • 대화형 매체(interactive media): 그림, 음성, 비디오 등 다양한 미디어를 표시, 재생할 수 있음
    • 셸 문법(shell syntax): 셸 명령어를 사용하여 파일을 관리하거나 시스템 명령을 실행할 수 있음
    • 탭 완성(tab completion): 탭 키를 누르면 자동으로 변수, 함수, 모듈 이름을 완성해줌
    • 히스토리(history): 이전에 실행한 코드를 검색하고 재사용할 수 있음

 

  • %time : 한 번 실행한 시간 측정
%time sum(range(10000))

CPU times: user 321 µs, sys: 53 µs, total: 374 µs
Wall time: 377 µs
49995000

 

  • %timeit: 여러 번 실행하여 평균 및 표준 편차 제공
%timeit sum(range(10000))

211 µs ± 8.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

 

  • Loop 횟수: 200번, 시행횟수: 5회 지정
%timeit -n 200 -r 5 sum(range(10000))

205 µs ± 12.2 µs per loop (mean ± std. dev. of 5 runs, 200 loops each)

 

  • 코드 셀 전체에 적용할 때 %% 사용
%%timeit -n 500 -r 3

for i in range(1000):
    i * 2

66.3 µs ± 6.13 µs per loop (mean ± std. dev. of 3 runs, 500 loops each)

 

  • 파일 자동 저장 주기 설정 (예: 60초)
  • 코렙의 경우 따로 하지 않아도 자동 설정되어 있음.
%autosave 60

Autosaving every 60 seconds

 

  • HTML 코드 실행 및 표시
%%html
<h1>Hello, world!</h1>

Hello, world!

  • 시스템 명령어 실행 (예: 디렉토리 내 파일 목록)
%system ls

['sample_data']

 

  • 파일 쓰기
%%writefile my_file.txt
Hello, world!

Writing my_file.txt

%%writefile my_script.py
print("Hello, World!!!")

Writing my_script.py

 

  • 외부 Python 파일 실행
%run my_script.py

Hello, World!!!

 

a = 100
b = 200
c = a + b
print(c)

300

 

변수 목록 표시

%who

a b c

 

데이터 공유

data = [1, 2, 3]
%store data

Stored 'data' (list)

 

노트북 종료하고 다시 시작한 수 변수 불러오기

%store -r data
print(data)

[1, 2, 3]

 

환경 변수 나열

%env

 

matplotlib 그래프 Jupyter Notebook에 표시(Colab에서는 불필요함)

%matplotlib inline
import matplotlib.pyplot as plt
plt.plot([1, 2, 3])
plt.show()

 

앞에 작성했던 코드들 쭉 나열

%history

 

2. Examples

2.1 웹서버 로그 처리하기
import gdown

 

output_name = 'access_log'
gdown.download(google_path, output_name, quiet=False)

 

2.1.1 총 페이지 뷰 수 계산하기

pageviews = 0

with open('access_log', 'r') as f:
   logs = f.readlines()
   for log in logs:
      log = log.split()
      status = log[8]
      if status == '200':
         pageviews += 1

print('총 페이지뷰: [%d]' %pageviews)

총 페이지뷰: [327]

2.1.2 고유 방문자 수 계산하기

visit_ip = []

with open('access_log', 'r') as f:
   logs = f.readlines()
   for log in logs:
      log = log.split()
      ip = log[0]
      if ip not in visit_ip:
         visit_ip.append(ip)

print('고유 방문자수: [%d]' %len(visit_ip))

고유 방문자수: [99]

 

2.1.3 총 서비스 용량 계산하기

KB = 1024
total_service = 0

with open('access_log', 'r') as f:
   logs = f.readlines()
   for log in logs:
      log = log.split()
      servicebyte = log[9]
      if servicebyte.isdigit():
         total_service += int(servicebyte)

total_service /= KB
print('총 서비스 용량: %dKB' %total_service)

총 서비스 용량: 29289KB

2.1.4 사용자별 서비스 용량 계산하기

서비스 아이피에 대해서 용량 정렬

services = {}

with open('access_log', 'r') as f:
   logs = f.readlines()
   for log in logs:
      log = log.split()
      ip = log[0]
      servicebyte = log[9]
      if servicebyte.isdigit():
         servicebyte = int(servicebyte)
      else:
         servicebyte = 0

      if ip not in services:
         services[ip] = servicebyte
      else:
         services[ip] += servicebyte

ret = sorted(services.items(), key=lambda x: x[1], reverse=True)

print('사용자IP – 서비스용량')
for ip, b in ret:
   print('[%s] – [%d]' %(ip, b))

 

2.2 에코 서버 만들기(1)

  • 에코 서버
    • 네트워크로 메시지를 수신하여 송신자에게 수신한 메시지를 그대로 돌려보내는 서버
    • 네트워크 통신의 기본이 되는 소켓 프로그래밍을 접해보자
 
  • 네트워크 소켓
    • 네트워크 통신에 있어서 시작점이자 끝점
    • 클라이언트-서버 프로그램의 가장 핵심이 되는 모듈
    • 서버와 클라이언트는 각자의 네트워크 소켓을 가지고 있음
    • 네트워크 통신을 위해 사용되는 프로토콜의 종류에 따라 TCP/UDP/Raw 소켓으로 구분됨
      • TCP 소켓:
        • TCP(Transmission Control Protocol)를 활용하는 네트워크 소켓
          • 연결 지향적 프로토콜(두 개를 완전히 연결)
          • 포트 번호를 이용하여 서비스를 식별
          • 데이터의 신뢰성 있는 전송을 보장함(중간에 떨어지지 않음)
          • 데이터의 순서, 무결성, 신뢰성을 보장함
          • 주로 웹, 메일, 파일 공유와 같이 데이터 누락을 허용하지 않는 서비스에서 사용됨
      • UDP 소켓:
        • UDP(User Datagram Protocol)를 활용하는 네트워크 소켓
          • 비연결 지향적 프로토콜
          • 포트 번호를 이용하여 서비스를 식별
          • 빠른 데이터 전송을 목적으로함(신뢰성 보다는 속도를 중시함)
          • 연결 설정 과정 없이 데이터를 전송
          • 데이터의 순서나 무결성은 보장하지 않음
          • VoIP (Voice over IP)와 같이 속도가 중요한 서비스에서 사용됨
      • Raw 소켓:
        • 특정한 프로토콜에 대한 전송 계층 포매팅 없이 인터넷 프로토콜 패킷을 직접 주고 받을 수 있는 인터넷 소켓
        • 데이터를 전송할 때 직접 프로토콜 헤더를 만들어 전송하고, 데이터를 수신할 때도 프로토콜 헤더를 포함하여 수신
        • 라우터나 네트워크 장비 등에 주로 활용되며 사용자 공간에서 새로운 전송 계층 프로토콜을 구현하는 데에도 활용됨

 

2.2.1 서버

import socket

HOST = ''
PORT = 9009

def runServer():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.bind(HOST, PORT) # 바인딩
        sock.listen(1)
        print("클라이언트 연결을 기다리는 중")
        conn, addr = sock.accept()

        with conn:
            print('[%s]와 연결됨' % addr[0])
            while True:
                data = conn.recv(1024)
                if not data:
                    break
                print('메세지 수진 [%s]' %data.decode())
                conn.sendall(data)

runServer()

 

2.2.2 클라이언트

 

클라이언트는 한번 주고 받으면 끝인데, 일을 계속 하고싶으면 계속 돌리면 된다.

import socket

HOST = 'localhost' # 127.0.0.1
PORT = 9009

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
   sock.connect((HOST, PORT))
   msg = input('메시지 입력: ')
   sock.sendall(msg.encode()) # 클라이언트는 인코딩을 통해 전달함
   data = sock.recv(1024)

print('에코 서버로부터 받은 데이터 [%s]' %data.decode())

 

 

각각 따로 터미널에서 실행시켜서 클라이언트 를 활용해 아래와 같이 동작시킴

터미널 2개를 따로 사용함(server 와 client 를 각각 다른 터미널에서 동작시킴)

 

메시지 입력: 안녕하세요
에코 서버로부터 받은 데이터 [안녕하세요] 

 

2.3 에코 서버 만들기(2)

2.3.1 서버

import socketserver

HOST = ''
PORT = 9009

class MyTcpHandler(socketserver.BaseRequestHandler):
   def handle(self):
      print('[%s] 연결됨' %self.client_address[0])

      try:
         while True:
            self.data = self.request.recv(1024)
            if self.data.decode() == '/quit':
               print('[%s] 사용자에 의해 중단' %self.client_address[0])
               return

            print('[%s]' %self.data.decode())
            self.request.sendall(self.data)
      except Exception as e:
         print(e)

def runServer():
   print('+++ 에코 서버를 시작합니다.')
   print('+++ 에코 서버를 끝내려면 Ctrl-C를 누르세요.')

   try:
       server = socketserver.TCPServer((HOST, PORT), MyTcpHandler)
       server.serve_forever()
   except KeyboardInterrupt:
      print('--- 에코 서버를 종료합니다.')

runServer()

 

2.3.2 클라이언트

import socket

HOST = 'localhost'
PORT = 9009

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
   sock.connect((HOST, PORT))

   while True:
       msg = input('메시지 입력: ')
       if msg == '/quit':
           sock.sendall(msg.encode())
           break

       sock.sendall(msg.encode())
       data = sock.recv(1024)
       print('에코 서버로부터 받은 데이터 [%s]' %data.decode())

print('클라이언트 종료')

 

메시지 입력: 안녕하세요2
에코 서버로부터 받은 데이터 [안녕하세요2]
메시지 입력: 반갑습니다
에코 서버로부터 받은 데이터 [반갑습니다]
메시지 입력: 파이팅
에코 서버로부터 받은 데이터 [파이팅]
메시지 입력: /quit

클라이언트 종료

 

 

 

 

 

 

728x90

'PYTHON-BACK' 카테고리의 다른 글

#파이썬 도서관 출납 시스템_16일차  (1) 2024.07.22
#파이썬 기초 16일차  (0) 2024.07.22
#파이썬 기초 14일차  (0) 2024.07.18
#파이썬 기초 13일차  (0) 2024.07.17
#파이썬 기초 12일차  (3) 2024.07.16