Python 정리 (내용을 클릭하세요)
1. 변수 2. 연산자 3. 집합형 자료 4. 정규 표현식 5. 조건 판단문 if
6. 반복문 while 7. 반복문 for 8. 함수 9. 변수의 생존 범위 10. closure(클로저)
11. 일급함수 12. Module 13. 사용자 정의 모듈 14. turtle 15. 외부 모듈 사용
16. Class 17. 포함관계 (has a) 18. 상속 19. 메소드 오버라이딩 20. 다중 상속
21. 추상클래스 22. 예외처리 23. file i/o 24. wxPython 25. SQLite
26.  DB 연동 27. socket 28. Thread 29. multi thread chat 30. pool
31. process 32. 웹 크롤링(crawling) 33. HttpServer 34. CGI 35. 챗봇(chatbot)

 

20. 다중 상속

21. 추상클래스

22. 예외처리

23. file i/o

24. wxPython

25. SQLite

26. 원격 DB 연동

27. socket

28. Thread

29. 멀티 쓰레드 채팅 프로그램

30. pool

31. process

32. 웹 크롤링

33. HttpServer

34. CGI

35. 챗봇(chatbot)


20. 다중 상속 - 순서 중요

 * test_24

print("이전 작업 진행")
class Tiger:
    data = '호랑이 세상'
    
    def cry(self):
        print('호랑이 울음')
    def eat(self):
        print('고기 먹음')

class Lion:
    data = '사자 세상'
    
    def cry(self):
        print('사자 울음')
        
    def hobby(self):
        print('사자 낮잠')

class Liger(Tiger, Lion): # 먼저 명시한 부모를 먼저 인식
    pass

aa = Liger()
aa.cry()        # 호랑이 울음
aa.eat()        # 고기 먹음
aa.hobby()      # 사자 낮잠
print(aa.data)  # 호랑이 세상
print()

class Liger2(Lion, Tiger):
    data = 'Liger2 멤버 변수'
    
    def play(self):
        print("Liger2 고유 메소드")
        self.hobby()
        super().hobby()
        print(self.data)
        print(super().data)
bb = Liger2()
bb.cry()       # 사자 울음
bb.eat()       # 고기 먹음
bb.hobby()     # 사자 낮잠
print(bb.data) # Liger2 멤버 변수
bb.play()
# Liger2 고유 메소드
# 사자 낮잠
# 사자 낮잠
# Liger2 멤버 변수
# 사자 세상
class Animal:
    def move(self):
        pass
    
class Dog(Animal):
    name = '개'
    
    def move(self):
        print('개가 낮에 돌아다님')
    
class Cat(Animal):
    name = '고양이'
    
    def move(self):
        print('고양이가 밤에 돌아다님')
    
class Wolf(Dog, Cat):
    pass

class Fox(Cat, Dog):
    def move(self):
        print('여우가 돌아다님(오버라이딩)')
    
    def foxMove(self):
        print('여우 고유 메소드')
dog = Dog()
cat = Cat()
wolf = Wolf()
fox = Fox()

anis = [dog, cat, wolf, fox]
for a in anis:
    a.move()
# 개가 낮에 돌아다님
# 고양이가 밤에 돌아다님
# 개가 낮에 돌아다님
# 여우가 돌아다님(오버라이딩)

21. 추상클래스

추상클래스 : 추상 메소드를 가지는 클래스.
추상 메소드: 자식 클래스에서 부모의 추상메소드를 일반 메소드로 반드시 오버라이딩 하도록 강요.

 * test25_abstract

from abc import *

class TestClass(metaclass = ABCMeta): # 추상 클래스
    @abstractmethod
    def abcMethod(self):              # 추상 메소드
        pass
    
    def normalMethod(self):           # 일반 메소드
        print('일반 메소드')

tt = TestClass()   # TypeError: Can't instantiate abstract class TestClass with abstract methods abcMethod 
                   # 추상클래스가 추상메소드를 가질 경우 인스턴스 생성 시 error 발생.
                   # 추상클래스가 추상메소드를 가지지 않을 경우 인스턴스 생성 가능.
class Child1(TestClass): # 추상 클래스를 상속 받을 경우 추상메소드를 오버라이드 하지않을 경우 error 발생
    name = 'Child1'
    
    def abcMethod(self):
        print('Child1 추상 메소드를 오버라이딩하여 일반 메소드 생성')

# TypeError: Can't instantiate abstract class Child1 with abstract methods abcMethod
c1 = Child1()
c1.abcMethod()       # Child1 추상 메소드를 오버라이딩하여 일반 메소드 생성
c1.normalMethod()    # 일반 메소드
class Child2(TestClass):
    name = 'Child2'
    
    def abcMethod(self):
        print('Child2 추상 메소드를 오버라이딩하여 일반 메소드 생성')
        print('다른 클래스의 abcMethod와 이름은 같으나 다른 기능을 수행.')
        
    def normalMethod(self):
        print('부모의 normalMethod를 오버라이딩. 부모 메소드와 다른 역할 수행을 위해.')

c2 = Child2()
c2.abcMethod()      # Child2 추상 메소드를 오버라이딩하여 일반 메소드 생성
                    # 다른 클래스의 abcMethod와 이름은 같으나 다른 기능을 수행.
c2.normalMethod()   # 부모의 normalMethod를 오버라이딩. 부모 메소드와 다른 역할 수행을 위해.
print()

다형성 구현

my = c1
my.abcMethod()      # 1
                    #Child1 추상 메소드를 오버라이딩하여 일반 메소드 생성
my = c2
my.abcMethod()      # 1과 동일한 명령문이나 기능은 다름.
                    #Child2 추상 메소드를 오버라이딩하여 일반 메소드 생성
                    #다른 클래스의 abcMethod와 이름은 같으나 다른 기능을 수행.

클래스 연습문제 24-4

class Employee(metaclass= ABCMeta):
    def __init__(self, irum, nai):
        self.irum = irum
        self.nai = nai
    
    @abstractmethod
    def pay(self):
        pass
    
    @abstractmethod
    def data_print(self):
        pass
    
    def irumnai_print(self):
        print('이름 : ' + self.irum + ', 나이 : '+ str(self.nai), end = ', ')                     
                    
class Temporary(Employee):
    def __init__(self, irum, nai, ilsu, ildang):
        Employee.__init__(self, irum, nai)
        self.ilsu = ilsu
        self.ildang = ildang
        
    def pay(self):
        return self.ilsu * self.ildang; 
    
    def data_print(self):
        self.irumnai_print()
        print('월급 : ' + str(self.pay()))

t = Temporary('홍길도', 25, 20, 15000)
t.data_print() # 이름 : 홍길도, 나이 : 25, 월급 : 300000
class Regular(Employee):
    def __init__(self, irum, nai, salary):
        Employee.__init__(self, irum, nai)
        self.salary = salary
    
    def pay(self): # 추상 메소드 오버라이딩
        return self.salary; 
    
    def data_print(self):
        self.irumnai_print()
        print('급여 : ' + str(self.pay()))

r = Regular('한국인', 27, 3500000) # 이름 : 한국인, 나이 : 27, 급여 : 3500000
r.data_print()
class Salseman(Regular):
    def __init__(self, irum, nai, salary, sales, commission):
        Regular.__init__(self, irum, nai, salary)
        self.sales = sales
        self.commission = commission
    
    def pay(self): # 일반 메소드 오버라이딩
        return super().pay() + self.sales * self.commission; 
    
    def data_print(self):
        self.irumnai_print()
        print('수령액 : ' + str(self.pay()))
        
s = Salseman('손오공', 29, 1200000, 5000000, 0.25)
s.data_print() # 이름 : 손오공, 나이 : 29, 수령액 : 2450000.0

22. 예외처리

 * test26_try

try ~ except - 예상치 않은 에러에 대응하기 위한 문법

def divide(a, b):
    return a / b

c = divide(5, 2)
#c = divide(5, 0) # ZeroDivisionError: division by zero
print(c)
print()

try:
    c = divide(5, 2)
    #c = divide(5, 0)
    print(c)
    
    aa = [1, 2]
    print(aa[0])
    print(aa[1])
    #print(aa[2]) # IndexError: list index out of range
    
    f = open('c:/abc.txt') # FileNotFoundError: [Errno 2] No such file or directory: 'c:/abc.txt'
    
except ZeroDivisionError:
    print('두번째 인자에 0을 주지마세요')

except IndexError as e:
    print('Index Error : ', e)
except Exception as err:
    print("error 발생 : ", err)
finally:
    print('에러 유무에 관계없이 반드시 수행됨')

print('프로그램 종료')

 


23. file i/o

import os
print(os.getcwd())

try:
    print('파일 읽기')
    f1 = open(r'ftest.txt', mode ='r', encoding ='utf-8')
    print(f1) # <_io.TextIOWrapper name='ftest.txt' mode='r' encoding='utf-8'>
    print(f1.read())
    f1.close() # 파일 처리 종료시 close() : 사용했던 자원을 해제
    
    print('파일로 저장')
    f2 = open('ftest2.txt', mode = 'w', encoding = 'utf-8')
    f2.write('내 친구들\n')
    f2.write('홍길동 고길동\n')
    f2.close()
    print('저장 성공')
    
    print('파일에 내용추가')
    f2 = open('ftest2.txt', mode = 'a', encoding = 'utf-8')
    f2.write('손오공\n')
    f2.write('조조\n')
    f2.close()
    print('추가 성공')
    
    print('파일 읽기')
    f3 = open(r'ftest2.txt', mode ='r', encoding ='utf-8')
    print(f3.read()) # 전체 행 읽기
    #print(f3.readline()) # 한 행씩 읽기
    f3.close()
    
except Exception as e:
    print('에러 : ', e)

 - with문 사용 - close() 자동 수행

try:
    # 저장
    with open('ftest3.txt', mode = 'w', encoding = 'utf-8') as ff1:
        ff1.write('파이썬 문서 저장\n')
        ff1.write('내용\n')
        ff1.write('with문 사용으로 close() 하지않음\n')
    # 읽기
    with open('ftest3.txt', mode = 'r', encoding = 'utf-8') as ff2:
        print(ff2.read())
except Exception as e2:
    print('에러 발생', e2)

 - 피클링  : 복합 개체 처리(i/o)

import pickle

try:
    dicData = {'tom':'111-1111', 'james':'222-2222'}
    listData = ['마우스', '키보드']
    tupleData = (dicData, listData) # 복합객체
    
    with open('hi.dat', 'wb') as fobj:
        pickle.dump(tupleData, fobj)
        pickle.dump(listData, fobj)
    print('객체를 파일로 저장하기 성공')
    print('객체 읽기')
    with open('hi.dat', 'rb') as fobj2:
        a, b = pickle.load(fobj2)
        print(a) # {'tom': '111-1111', 'james': '222-2222'}
        print(b) # ['마우스', '키보드']
        c = pickle.load(fobj2)
        print(c)
except Exception as e3:
    print('error : ' + e3)

 * test28_file

 - 동 이름으로 우편번호와 주소 출력

try:
    dong = input('동이름 입력 : ')
    print(dong)
    with open(r'zipcode.txt', mode = 'r', encoding = 'euc-kr') as f:
        #print(f.read())
        line = f.readline()
        while line:
            lines = line.split('\t') # tab으로 구분
            #print(lines)
            if lines[3].startswith(dong): # 입력된 동 이름으로 시작되는 주소만 처리
                print('[' + lines[0] + '] '+ lines[1] + ' '+ lines[2] + \
                      ' '+ lines[3] + ' '+ lines[4])
            line = f.readline() # readline이 없을 때 까지 수행
            
except Exception as e:
    print('err',e)

 


24. wxPython

 - 설치

1 사이트 접속

wxpython.org/Phoenix/snapshot-builds/

 

Index of /Phoenix/snapshot-builds

 

wxpython.org

2 " wxPython-4.1.2a1.dev5103+4ab028d7-cp38-cp38-win_amd64.whl " 다운로드

 

3 anaconda prompt 실행

" cd C:\Users\wonh\Downloads\ " 입력(다운로드 파일 경로)

" dir wx* " 입력 후 하기 파일명 복사

" pip install wxPython-4.1.2a1.dev5103+4ab028d7-cp38-cp38-win_amd64.whl "입력

 

 * test29_gui1

# GUI (윈도우 프로그래밍)
# wxPython

import wx
# app = wx.App(False)
# frame = wx.Frame(None, wx.ID_ANY, 'Hi')
# frame.Show(True)
# app.MainLoop()

class Ex(wx.Frame):
    def __init__(self, parent, title):
        super(Ex, self).__init__(parent, title = title, size =(300, 300))
        
        # textBox 추가
        #self.txtA = wx.TextCtrl(self)
        #self.txtA = wx.TextCtrl(self, style = wx.TE_MULTILINE)
        
        # Label, textBox 사용
        panel = wx.Panel(self)
        wx.StaticText(panel, label = 'i d : ', pos = (5, 5))
        wx.StaticText(panel, label = 'pwd : ', pos = (5, 40))
        self.txtId = wx.TextCtrl(panel, pos = (40, 5))
        self.txtPwd = wx.TextCtrl(panel, pos = (40, 40), size = (200, -1))
        
        # Button : 디자인
        btn1 = wx.Button(panel, label = '버튼1', pos = (5,100))
        btn2 = wx.Button(panel, label = '버튼2', pos = (100,100))
        btn3 = wx.Button(panel, label = '종료', pos = (200,100))
        
        # Button에  대한 이벤트 처리 작업1
#         btn1.Bind(wx.EVT_BUTTON, self.btn1Method)
#         btn2.Bind(wx.EVT_BUTTON, self.btn2Method)
#         btn3.Bind(wx.EVT_BUTTON, self.btn3Method)
        
        # Button에  대한 이벤트 처리 작업2
        btn1.id = 1 # 각 버튼의 구분을 위해 id를 준다
        btn2.id = 2
        btn3.id = 3
        btn1.Bind(wx.EVT_BUTTON, self.OnClickMethod)
        btn2.Bind(wx.EVT_BUTTON, self.OnClickMethod)
        btn3.Bind(wx.EVT_BUTTON, self.OnClickMethod)
        
        self.Center()
        self.Show()
    
    def abc(self):
        print('일반 메소드')
    
    def btn1Method(self, event): # 이벤트 처리 메소드. event handler
        #print('버튼 1을 누르셨습니다')
        temp = self.txtId.GetValue()
        self.txtPwd.SetLabelText(temp)
    
    def btn2Method(self, event): # 이벤트 처리 메소드. event handler
        #print('버튼 2를 누르셨습니다')
        msgDial = wx.MessageDialog(self, '메세지', '제목', wx.OK)
        msgDial.ShowModal()
        msgDial.Destroy()
        
    def btn3Method(self, event): # 이벤트 처리 메소드. event handler
        #print('종료')
        self.Close() # wx.App()를 종료
        
    def OnClickMethod(self, event):
        #print(event.GetEventObject().id)
        #print('aa')
        if event.GetEventObject().id == 1:
            self.txtId.SetLabelText('id');
        elif event.GetEventObject().id == 2:
            self.txtPwd.SetLabelText('password');
        else:
            self.Close() 
        
if __name__ == '__main__':
    app = wx.App()
    Ex(None, title = '연습')
    app.MainLoop()

 * test30_gui2

# 레이아웃 관리자 클래스 중 Boxsizer 연습
import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        super(MyFrame, self).__init__(parent, title=title, size =(300, 350))
        
        panel1 = wx.Panel(self, -1, style = wx.SUNKEN_BORDER)
        panel2 = wx.Panel(self, -1, style = wx.SUNKEN_BORDER)
        
        panel1.SetBackgroundColour("Blue")
        panel2.SetBackgroundColour("red")
        
        box = wx.BoxSizer(wx.HORIZONTAL) # VERTICAL 
        box.Add(panel1, 1, wx.EXPAND)
        box.Add(panel2, 2, wx.EXPAND)
        
        self.SetSizer(box)
        self.Center()
        self.Show()

if __name__ == '__main__':
    app = wx.App()
    MyFrame(None, title = '레이아웃')
    app.MainLoop()

 

 - wxformbuilder - UI 편집 도구

 * test31_gui3

sourceforge.net/projects/wxformbuilder/

 

wxFormBuilder

Download wxFormBuilder for free. ALL DEVELOPMENT MOVED TO GITHUB https://github.com/wxFormBuilder/wxFormBuilder wxFormBuilder - a RAD tool for wxWidgets GUI design.

sourceforge.net

import wx
import wx.xrc

class MyFrame1 ( wx.Frame ):
    
    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"연습", pos = wx.DefaultPosition, size = wx.Size( 288,154 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
        
        #self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
        self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_MENU ) )
        
        bSizer1 = wx.BoxSizer( wx.VERTICAL )
        
        self.m_panel1 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer2 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText1 = wx.StaticText( self.m_panel1, wx.ID_ANY, u"이름 : ", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText1.Wrap( -1 )
        bSizer2.Add( self.m_staticText1, 0, wx.ALL, 5 )
        
        self.txtName = wx.TextCtrl( self.m_panel1, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer2.Add( self.txtName, 0, wx.ALL, 5 )
        
        
        self.m_panel1.SetSizer( bSizer2 )
        self.m_panel1.Layout()
        bSizer2.Fit( self.m_panel1 )
        bSizer1.Add( self.m_panel1, 0, wx.ALL|wx.EXPAND, 5 )
        
        self.m_panel2 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer3 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText2 = wx.StaticText( self.m_panel2, wx.ID_ANY, u"나이 : ", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText2.Wrap( -1 )
        bSizer3.Add( self.m_staticText2, 0, wx.ALL, 5 )
        
        self.txtAge = wx.TextCtrl( self.m_panel2, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer3.Add( self.txtAge, 0, wx.ALL, 5 )
        
        self.btnOk = wx.Button( self.m_panel2, wx.ID_ANY, u"확인", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer3.Add( self.btnOk, 0, wx.ALL, 5 )
        
        
        self.m_panel2.SetSizer( bSizer3 )
        self.m_panel2.Layout()
        bSizer3.Fit( self.m_panel2 )
        bSizer1.Add( self.m_panel2, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel3 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer4 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText3 = wx.StaticText( self.m_panel3, wx.ID_ANY, u"결과 : ", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText3.Wrap( -1 )
        bSizer4.Add( self.m_staticText3, 0, wx.ALL, 5 )
        
        self.staShow = wx.StaticText( self.m_panel3, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        self.staShow.Wrap( -1 )
        bSizer4.Add( self.staShow, 0, wx.ALL, 5 )
        
        
        self.m_panel3.SetSizer( bSizer4 )
        self.m_panel3.Layout()
        bSizer4.Fit( self.m_panel3 )
        bSizer1.Add( self.m_panel3, 0, wx.EXPAND |wx.ALL, 5 )
        
        
        self.SetSizer( bSizer1 )
        self.Layout()
        
        self.Centre( wx.BOTH )
        
        # Connect Events
        self.btnOk.Bind( wx.EVT_BUTTON, self.OnClickMethod )
    
    def __del__( self ):
        pass
    
    
    # Virtual event handlers, overide them in your derived class
    def OnClickMethod( self, event ):
        #event.Skip()
        name = self.txtName.GetValue()
        if name == "":
            wx.MessageBox('이름 입력', '알림', wx.OK)
            return
        age = self.txtAge.GetValue()
        
        self.staShow.SetLabelText(name+" " + age)
    
if __name__ == '__main__':
    app = wx.App()
    MyFrame1(None).Show()
    app.MainLoop()
    

 

 * test32_gui_calc

import wx
import wx.xrc

class MyFrame1 ( wx.Frame ):
    
    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 308,303 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
        
        #self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
        self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_MENU ) )
        
        bSizer1 = wx.BoxSizer( wx.VERTICAL )
        
        self.m_panel1 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer2 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText1 = wx.StaticText( self.m_panel1, wx.ID_ANY, u"숫자1", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText1.Wrap( -1 )
        bSizer2.Add( self.m_staticText1, 0, wx.ALL, 5 )
        
        self.txtNum1 = wx.TextCtrl( self.m_panel1, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer2.Add( self.txtNum1, 0, wx.ALL, 5 )
        
        
        self.m_panel1.SetSizer( bSizer2 )
        self.m_panel1.Layout()
        bSizer2.Fit( self.m_panel1 )
        bSizer1.Add( self.m_panel1, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel2 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer3 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText2 = wx.StaticText( self.m_panel2, wx.ID_ANY, u"숫자2", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText2.Wrap( -1 )
        bSizer3.Add( self.m_staticText2, 0, wx.ALL, 5 )
        
        self.txtNum2 = wx.TextCtrl( self.m_panel2, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer3.Add( self.txtNum2, 0, wx.ALL, 5 )
        
        
        self.m_panel2.SetSizer( bSizer3 )
        self.m_panel2.Layout()
        bSizer3.Fit( self.m_panel2 )
        bSizer1.Add( self.m_panel2, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel3 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer4 = wx.BoxSizer( wx.VERTICAL )
        
        rdoOpChoices = [ u"+", u"-", u"*", u"/" ]
        self.rdoOp = wx.RadioBox( self.m_panel3, wx.ID_ANY, u"연산자 선택", wx.DefaultPosition, wx.DefaultSize, rdoOpChoices, 1, wx.RA_SPECIFY_ROWS )
        self.rdoOp.SetSelection( 2 )
        bSizer4.Add( self.rdoOp, 0, wx.ALL|wx.EXPAND, 5 )
        
        
        self.m_panel3.SetSizer( bSizer4 )
        self.m_panel3.Layout()
        bSizer4.Fit( self.m_panel3 )
        bSizer1.Add( self.m_panel3, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel4 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer5 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText3 = wx.StaticText( self.m_panel4, wx.ID_ANY, u"연산결과 : ", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText3.Wrap( -1 )
        bSizer5.Add( self.m_staticText3, 0, wx.ALL, 5 )
        
        self.staResult = wx.StaticText( self.m_panel4, wx.ID_ANY, u"0", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.staResult.Wrap( -1 )
        bSizer5.Add( self.staResult, 0, wx.ALL, 5 )
        
        
        self.m_panel4.SetSizer( bSizer5 )
        self.m_panel4.Layout()
        bSizer5.Fit( self.m_panel4 )
        bSizer1.Add( self.m_panel4, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel5 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer6 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.btnCalc = wx.Button( self.m_panel5, wx.ID_ANY, u"계산", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer6.Add( self.btnCalc, 0, wx.ALL, 5 )
        
        self.btnClear = wx.Button( self.m_panel5, wx.ID_ANY, u"초기화", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer6.Add( self.btnClear, 0, wx.ALL, 5 )
        
        self.btnExit = wx.Button( self.m_panel5, wx.ID_ANY, u"종료", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer6.Add( self.btnExit, 0, wx.ALL, 5 )
        
        
        self.m_panel5.SetSizer( bSizer6 )
        self.m_panel5.Layout()
        bSizer6.Fit( self.m_panel5 )
        bSizer1.Add( self.m_panel5, 1, wx.EXPAND |wx.ALL, 5 )
        
        
        self.SetSizer( bSizer1 )
        self.Layout()
        
        self.Centre( wx.BOTH )
        # Connect Events
        self.btnCalc.id  = 1 # id 부여
        self.btnClear.id = 2
        self.btnExit.id  = 3
        self.btnCalc.Bind( wx.EVT_BUTTON, self.OnCalcProcess )
        self.btnClear.Bind( wx.EVT_BUTTON, self.OnCalcProcess )
        self.btnExit.Bind( wx.EVT_BUTTON, self.OnCalcProcess )
    
    def __del__( self ):
        pass
    
    
    # Virtual event handlers, overide them in your derived class
    def OnCalcProcess( self, event ):
        sel_id = event.GetEventObject().id # event 발생 객체의 id를 get
        #print(sel_id)
        if sel_id == 1: # 계산 버튼을 누를 경우
            op = self.rdoOp.GetStringSelection() # 선택된 라디오 버튼의 문자열 get  
            #print(op)
            num1 = self.txtNum1.GetValue()
            num2 = self.txtNum2.GetValue()
            
            if num1 == '' or num2 == '':
                wx.MessageBox('값을 입력하시오', '알림', wx.OK)
                return
            try:
                result = eval(num1 + op + num2)
            except Exception as e:
                wx.MessageBox('연산오류', '알림', wx.OK)
                return
            
            self.staResult.SetLabel(str(result))
        elif sel_id == 2: # 초기화
            self.txtNum1.SetLabel('')
            self.txtNum2.SetLabel('')
            self.staResult.SetLabel('')
            self.rdoOp.SetSelection(0)
            self.txtNum1.SetFocus()     # UX/UI
        elif sel_id == 3:
            dlg = wx.MessageDialog(self, '정말 종료할까요?', '알림', wx.YES_NO) # MessageDialog style 입력
            temp = dlg.ShowModal() # MessageDialog 창 발생 
            if temp == wx.ID_YES:  # YES 버튼을 누를 경우
                dlg.Destroy()      # MessageDialog창 닫기 
                self.Close()       # Frame 닫기
        
if __name__ == '__main__':
    app = wx.App()
    MyFrame1(None).Show()
    app.MainLoop()


25. SQLite

 : 개인용 DB SQLite3 : Python에 기본 설치됨

 : 환경변수 path에 추가 : C:\anaconda3\Library\bin

 * test33_sqlite

import sqlite3
print(sqlite3.version_info)

#conn = sqlite3.connect('example.db')
conn = sqlite3.connect(':memory:') # ram에 DB 생성 - 테스트용으로 연습할 때

try:
    cur = conn.cursor()
    
    cur.execute("create table if not exists friends(name text, phone text)")
    
    cur.execute("insert into friends values('홍길동', '111-1111')")
    cur.execute("insert into friends values(?, ?)", ('tom', '222-2222'))
    conn.commit()
    cur.execute("select * from friends")
    for f in cur:
        print(f[0] + " " + f[1])
    
except Exception as e:
    print(e)
    conn.rollback()
finally:
    conn.close()

26. 원격 DB 연동

 : maria db

 : anaconda prompt : pip install mysqlclient 입력

 * test34_db

import MySQLdb

conn = MySQLdb.connect(host = '127.0.0.1', user = 'root', password='123', database='test')
print(conn)
conn.close

sangdata table 자료 읽기

import MySQLdb

config = {
    'host':'127.0.0.1',
    'user':'root',
    'password':'123',
    'database':'test',
    'port':3306,
    'charset':'utf8',
    'use_unicode':True
}
try:
    conn = MySQLdb.connect(**config)
    cursor = conn.cursor() # sql문 처리용
    
    #자료추가1
    sql = "insert into sangdata(code, sang, su, dan) values(10, '새우깡', 5, 1200)" 
    cursor.execute(sql)
    conn.commit()
    sql = "insert into sangdata values(%s, %s, %s, %s)"
    #sql_data = ('12', '감자깡', 10, 2000)
    sql_data = '12', '감자깡', 10, 2000
    re = cursor.execute(sql, sql_data) # 성공하면 1, 실패시 0
    print(cursor)
    print(re)
    conn.commit()
    # 자료 수정
    sql = "update sangdata set sang=%s, su=%s, dan=%s where code=%s"
    sql_data = '깡', 7, 1000, 12
    cou = cursor.execute(sql, sql_data) # 성공하면 n, 실패시 0
    print('성공건수 ',cou)
    conn.commit()
    # 자료삭제
    code = '10'
    sql = "delete from sangdata where code =" + code # 비권장
    cursor.execute(sql)
    sql = "delete from sangdata where code = %s" # 권장 1
    cursor.execute(sql, (code,)) # 튜플
    sql = "delete from sangdata where code = '{0}'".format(code) # 권장 2
    cou = cursor.execute(sql)
    print('성공건수 ',cou)
    conn.commit()
    # 자료읽기 1
    sql = "select code, sang, su, dan from sangdata"
    cursor.execute(sql)    # DB의 자료를 읽어 cursor 객체가 그 결과를 기억
    
    for data in cursor.fetchall():
        #print(data)
        print('%s %s %s %s'%data)
    # 자료읽기 2
    for r in cursor:
        print(r[0], r[1], r[2], r[3])
    # 자료읽기 3
    for (code, sang, su, dan) in cursor:
        print(code, sang, su, dan)
    
    for (a, b, c, d) in cursor:
        print(a, b, c, d)
except MySQLdb.connections.Error as err:
    print('db err' + str(err))
except Exception as e:
    print('err' + str(e))
finally:
    cursor.close()
    conn.close()

 

 - 키보드로 부서번호를 입력받아 해당 부서에 근무하는 직원 출력

 * test35_db

import MySQLdb
import sys

config = {
    'host':'127.0.0.1',
    'user':'root',
    'password':'123',
    'database':'test',
    'port':3306,
    'charset':'utf8',
    'use_unicode':True
}

try:
    conn = MySQLdb.connect(**config)
    cursor = conn.cursor()
    
    buser_no = input('부서번호 입력 : ')
    sql = """
    select jikwon_no, jikwon_name, buser_num, jikwon_jik, jikwon_pay
    from jikwon
    where buser_num ={0}
    """.format(buser_no)
    
    cursor.execute(sql)
    datas = cursor.fetchall()
    
    if len(datas) == 0:
        print(str(buser_no)+ '번 부서는 없습니다.')
        sys.exit()
        
    for d in datas:
        print(d[0], d[1], d[2], d[3])
        
    print('인원수 : ' + str(len(datas)))
    
except Exception as e:
    print('err', e)
    
finally:
    cursor.close()
    conn.close()

 * test36_db_gui

config = {
    'host':'127.0.0.1',
    'user':'root',
    'password':'123',
    'database':'test',
    'port':3306,
    'charset':'utf8',
    'use_unicode':True
}

 - 파일 분리

import ast

with open('mariadb.txt', mode = 'r') as f:
    #print(f.read())
    aa = f.read()
    config = ast.literal_eval(aa)
import wx
import wx.xrc
import MySQLdb

class MyGogek ( wx.Frame ):
    
    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"고객자료 보기", pos = wx.DefaultPosition, size = wx.Size( 500,336 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
        
        #self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
        self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_MENU ) )
        
        bSizer1 = wx.BoxSizer( wx.VERTICAL )
        
        self.m_panel1 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer2 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText1 = wx.StaticText( self.m_panel1, wx.ID_ANY, u"사번 : ", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText1.Wrap( -1 )
        bSizer2.Add( self.m_staticText1, 0, wx.ALL, 5 )
        
        self.txtNo = wx.TextCtrl( self.m_panel1, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer2.Add( self.txtNo, 0, wx.ALL, 5 )
        
        self.m_staticText2 = wx.StaticText( self.m_panel1, wx.ID_ANY, u"직원명", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText2.Wrap( -1 )
        bSizer2.Add( self.m_staticText2, 0, wx.ALL, 5 )
        
        self.txtName = wx.TextCtrl( self.m_panel1, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer2.Add( self.txtName, 0, wx.ALL, 5 )
        
        self.btnLogin = wx.Button( self.m_panel1, wx.ID_ANY, u"로그인", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer2.Add( self.btnLogin, 0, wx.ALL, 5 )
        
        
        self.m_panel1.SetSizer( bSizer2 )
        self.m_panel1.Layout()
        bSizer2.Fit( self.m_panel1 )
        bSizer1.Add( self.m_panel1, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel2 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer3 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.staMsg = wx.StaticText( self.m_panel2, wx.ID_ANY, u"고객목록", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.staMsg.Wrap( -1 )
        bSizer3.Add( self.staMsg, 0, wx.ALL, 5 )
        
        
        self.m_panel2.SetSizer( bSizer3 )
        self.m_panel2.Layout()
        bSizer3.Fit( self.m_panel2 )
        bSizer1.Add( self.m_panel2, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel3 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer4 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.lstGogek = wx.ListCtrl( self.m_panel3, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LC_REPORT )
        bSizer4.Add( self.lstGogek, 1, wx.ALL|wx.EXPAND, 5 )
        
        
        self.m_panel3.SetSizer( bSizer4 )
        self.m_panel3.Layout()
        bSizer4.Fit( self.m_panel3 )
        bSizer1.Add( self.m_panel3, 1, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel4 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer5 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.staCount = wx.StaticText( self.m_panel4, wx.ID_ANY, u"인원수", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.staCount.Wrap( -1 )
        bSizer5.Add( self.staCount, 0, wx.ALL, 5 )
        
        
        self.m_panel4.SetSizer( bSizer5 )
        self.m_panel4.Layout()
        bSizer5.Fit( self.m_panel4 )
        bSizer1.Add( self.m_panel4, 1, wx.EXPAND |wx.ALL, 5 )
        
        
        self.SetSizer( bSizer1 )
        self.Layout()
        
        self.Centre( wx.BOTH )
        
        # lstGogek 객체에 제목 작성
        self.lstGogek.InsertColumn(0, '고객번호', width=100)
        self.lstGogek.InsertColumn(1, '고객명', width=150)
        self.lstGogek.InsertColumn(2, '고객전화', width=200)
        
        # Connect Events
        self.btnLogin.Bind( wx.EVT_BUTTON, self.OnLogin )
    
    def __del__( self ):
        pass
    # Virtual event handlers, overide them in your derived class
    def OnLogin( self, event ):
        if self.txtNo.GetValue() == '': # 사번을 입력안할 경우 팝업 발생
            wx.MessageBox('사번입력', '알림', wx.OK)
            self.txtNo.SetFocus()
            return
        
        if self.txtName.GetValue() == '': # 사번을 입력안할 경우 팝업 발생
            wx.MessageBox('직원명 입력', '알림', wx.OK)
            self.txtNo.SetFocus()
            return
        
        self.LoginCheck()
    def LoginCheck(self):
        try:
            conn = MySQLdb.connect(**config)
            cursor = conn.cursor()
            no = self.txtNo.GetValue()
            name = self.txtName.GetValue()
            #print(no, name)
            
            sql ="""
            select count(*) from jikwon
            where jikwon_no ='{0}' and jikwon_name ='{1}'
            """.format(no, name)
            
            cou = cursor.execute(sql)
            count = cursor.fetchone()[0]
            #print(count) # 1
            if count == 0:
                wx.MessageBox('로그인 실패', '알림', wx.OK)
                return
            else:
                self.staMsg.SetLabelText(no + '번 직원의 관리 고객목록')
                self.DisplayData(no) # 직원자료 출력 메소드 호출
            
        except Exception as e:
            print('LoginCheck err',e)
        finally:
            cursor.close()
            conn.close()
    def DisplayData(self, no):
        try:
            conn = MySQLdb.connect(**config)
            cursor = conn.cursor()
            
            sql = """
            select gogek_no, gogek_name, gogek_tel
            from gogek
            where gogek_damsano = {}
            """.format(no)
            
            cou = cursor.execute(sql)
            datas = cursor.fetchall()
            #print(datas)
            self.lstGogek.DeleteAllItems() # list control 초기화
            for d in datas:
                i = self.lstGogek.InsertItem(1000, 0) # List Control 최대 행수 입력
                self.lstGogek.SetItem(i, 0, str(d[0]))
                self.lstGogek.SetItem(i, 1, d[1])
                self.lstGogek.SetItem(i, 2, d[2])
            self.staCount.SetLabelText('인원수 : ' + str(len(datas)))
        except Exception as e:
            print('DisplayData err',e)
        finally:
            cursor.close()
            conn.close()
            
            
if __name__ == '__main__':
    app = wx.App()
    MyGogek(None).Show()
    app.MainLoop()
    

 - mariadb.txt

{
    'host':'127.0.0.1',
    'user':'root',
    'password':'123',
    'database':'test',
    'port':3306,
    'charset':'utf8',
    'use_unicode':True
}

27. socket

 - Socket : TCP/IP Protocol(통신규약)의 프로그래머 인터페이스를 모듈로 지원

 

 * socket_test

import socket

print(socket.getservbyname('http','tcp'))   # http port 80
print(socket.getservbyname('telnet','tcp')) # http port 23
print(socket.getservbyname('ftp','tcp'))    # http port 21
print(socket.getservbyname('smtp','tcp'))   # http port 25
print(socket.getservbyname('pop3','tcp'))   # http port 110

print()
print(socket.getaddrinfo('www.naver.com', 80, proto=socket.SOL_TCP))
# [(<AddressFamily.AF_INET: 2>, 0, 6, '', ('125.209.222.142', 80)), (<AddressFamily.AF_INET: 2>, 0, 6, '', ('223.130.195.200', 80))]
print(socket.getaddrinfo('www.daum.net', 80, proto=socket.SOL_TCP))

 

 * soc1_server

# 접속상태 확인을 위한 단순 Echo Server - client의 요청에 1회만 반응

from socket import *

serverSock = socket(AF_INET, SOCK_STREAM) # socket(socket 종류, socket 유형)
serverSock.bind(('127.0.0.1', 9999))
serverSock.listen(1)                      # TCP 리스너 설정

print('server start')

conn, addr = serverSock.accept()
print('client addr :', addr)
print('from client message : ', conn.recv(1024).decode())
# 클라이언트로 부터 바이트 단위 문자열로 수신된 내용 출력
conn.close()
serverSock.close()

 

 

 * soc1_client

# 1회 접속용 클라이언트
from socket import *

clientSock = socket(AF_INET, SOCK_STREAM)
clientSock.connect(('127.0.0.1', 9999))
clientSock.sendall('안녕 반가워'.encode(encoding='utf_8', errors='strict'))
clientSock.close()

 * soc2_server

# 서버 서비스 계속 유지
import socket
import sys

HOST = ''
PORT = 8888

serverSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
    serverSock.bind((HOST, PORT))
    print('server start')
    serverSock.listen(5) # 클라이언트 접속 대기. 최대 동시 접속수는 1 ~ 5
    
    while True:
        conn,addr = serverSock.accept() # 클라이언트 접속 승인
        print('client info : ', addr[0], addr[1])
        print(conn.recv(1024).decode()) # 클라이언트가 전송한 메세지 수신 후 출력
        
        # 전송
        conn.send('from server : ' + str(addr[1]) + 'ㅁㅁㅁ'.encode('utf_8'))
except socket.error as err:
    print('socket error : ', err)
except Exception as e:
    print('error : ', e)
finally:
    serverSock.close()
    

 

 * soc2_client

# 1회 접속용 클라이언트
from socket import *

clientSock = socket(AF_INET, SOCK_STREAM)
clientSock.connect(('127.0.0.1', 8888))
clientSock.sendall('안녕 반가워'.encode(encoding='utf_8'))
re_msg = clientSock.recv(1024).decode()
print('수신자료', re_msg)
clientSock.close()

28. Thread

 - process : 실행 중인 응용프로그램을 의미, 프로세스 단위로 별도의 메모리를 사용

from subprocess import *

Popen('calc.exe')
Popen('notepad.exe')

 - thread : Light weight process 라고도 함. 메인 프로세스(스레드)와 병렬적으로 수행되는 단위 프로그램. 스레드 단위로 함수나 메소드를 수행 가능.

 

 * th1

import time

def run(id):
    for i in range(1, 11):
        print('id:{} -> {}'.format(id, i))
        time.sleep(0.5)

  1. thread를 사용하지 않은 경우

run(1) # 순차적으로 호출되므로 순차적으로 처리됨
run(2)

  2. thread를 사용한 경우 : 스레드 스케쥴러에 의해 랜덤하게 스레드 처리가 됨

import threading

th1 = threading.Thread(target=run, args = ('일')) # 사용자 정의 스레드 생성
th2 = threading.Thread(target=run, args = ('이'))
th1.start() # 스레드 수행 시작
th2.start()
th1.join()  # 사용자 정의 스레드가 종료될때까지 메인 스레드 대기 시킴 
th2.join()

print('메인 프로그램 종료') # 메인 스레드에 의해 메인 모듈이 실행(기본 값)

 * th2

스레드를 이용하여 날짜 및 시간 출력

import time
import threading

now = time.localtime()
#print(now)
print('현재는 {0}년 {1}월 {2} 일 {3} 시 {4} 분 {5} 초'.format(now.tm_year, now.tm_mon, \
                                                     now.tm_mday ,now.tm_hour,now.tm_min,now.tm_sec))

def cal_show():
        now = time.localtime()
        print('현재는 {0}년 {1}월 {2} 일 {3} 시 {4} 분 {5} 초'.format(now.tm_year, now.tm_mon, \
                                                     now.tm_mday ,now.tm_hour,now.tm_min,now.tm_sec))

def myRun():
    while True:
        now2 = time.localtime()
        if now2.tm_min == 57:
            break
        cal_show()
        time.sleep(1)
        
th = threading.Thread(target=myRun)
th.start()
th.join()
class MyThread(threading.Thread):
    def run(self):
        for i in range(1, 10):
            print('id{} --> {}'.format(self.getName(), i))
            time.sleep(0.1)
            
ths = []
for i in range(2):
    th = MyThread()
    th.start()
    ths.append(th)
    
for th in ths:
    th.join()
    
print('프로그램 종료')

 - 스레드간 공유자원 값 충돌 방지 - 동기화

 * th3

import threading, time
g_count = 0 # 전역변수는 자동으로 스레드의 공유자원이 됨

lock = threading.Lock()

def threadCount(id, count):
    global g_count
    for i in range(count):
        lock.acquire() # 두 개 이상의 스레드 공유 자원 충돌방지. lock을 걸어 다른 스레드 수행대기.
        print('id %s => count : %s, g_count : %s'%(id, i, g_count))
        g_count += 1
        lock.release() # lock을 해제

for i in range(1, 6):
    threading.Thread(target=threadCount, args =(i, 5)).start()

time.sleep(2)
print('final g_count : ', g_count)
print('finish process')

 - 스레드의 활성화/비활성화

 * th4

import threading, time
bread_plate = 0 # 빵 접시 - 공유자원
lock = threading.Condition()

class Maker(threading.Thread): # 빵 생성자
    def run(self):
        global bread_plate
        
        for i in range(30):
            lock.acquire() # 공유자운 충동방지
            
            while bread_plate >=10:
                print('빵 생산 초과로 대기')
                lock.wait() # 쓰레드 비활성화
                
            bread_plate += 1
            print('빵 생산 후 접시에 담기 : ', bread_plate)
            
            lock.notify() # 쓰레드 활성화
            lock.release()
            time.sleep(0.05)
            
class Eater(threading.Thread): # 빵 소비자
    def run(self):
        global bread_plate
        
        for i in range(30):
            lock.acquire() # 공유자원 충동방지
            
            while bread_plate <1:
                print('빵이 없어 대기')
                lock.wait() # 쓰레드 비활성화
                
            bread_plate -= 1
            print('빵 소비 후 접시의 빵 수 : ', bread_plate)
            
            lock.notify() # 쓰레드 활성화
            lock.release()
            time.sleep(0.07)
mak = []
con = []
for i in range(5): # 빵 생산자 수
    mak.append(Maker())
    
for i in range(5): # 빵 소비자 수
    con.append(Eater())
    
for th1 in mak:
    th1.start()
    
for th2 in con:
    th2.start()
    
for th1 in mak:
    th1.join()
    
for th2 in con:
    th2.join()
    
print('process 끝')

29. 멀티 쓰레드 채팅 프로그램

 : socket, thread 사용

 * chatServer (서버)

import socket
import threading

ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 서버 소켓 생성
ss.bind(('127.0.0.1', 5000))                           # ip에 연결
ss.listen(5)                                           # 동접속자 수 최대 5로 리스너 설정
print('Chatting start')
users = []

def ChatUser(conn):
    name = conn.recv(1024)
    data = '[알림]' + name.decode('utf_8') + '님이 접속하셨습니다.'
    print(data)
    
    try:
        for p in users:                                # 다른 클라이언트에도 접속 메시지 send
            p.send(data.encode('utf_8'))
            
        while True:                                    # 채팅 진행
            msg = conn.recv(1024)                      # 수신한 메세지
            data = '('+name.decode('utf_8') + ') : ' + msg.decode() # 송부자 + 메세지
            print('[R] '+data)
            for p in users:                            # 다른 클라이언트에도 메시지 send
                p.send(data.encode('utf_8'))
    except Exception as e:                             # 접속 종료 시
        users.remove(conn)                             # 접속 종료 시 list에 conn 제거
        data = '[알림]' + name.decode('utf_8') + '님이 접속을 종료하셨습니다.'
        print(data)
        print(e)
        if users:                                      # 다른 클라이언트에도 접속 종료 메시지 send
            for p in users:
                p.send(data.encode('utf_8'))
        else:
            print('exit')
    
while True:
    conn, addr = ss.accept()                           # 소켓 접속 및 대기. 클라이언트 접속 시 값 리턴
    users.append(conn)                                 # 접속 시 list에 conn 추가
    th = threading.Thread(target=ChatUser, args = (conn, )) # 접속자 수 만큼 쓰레드 생성
    th.start()

 

 * chatClient (클라이언트)

import socket
import threading
import sys
def Handle(socket):
    while True:
        data = socket.recv(1024)
        if not data: continue
        print(data.decode('utf_8'))                    # 파이썬 표준 출력은 버퍼링 된다.
        #print(data.decode('utf_8', flush=true))
        
sys.stdout.flush()                                     # 표준 입출력 버퍼 비움

cs = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 클라이언트 소켓 생성
cs.connect(('127.0.0.1', 5000))                        # 해당 ip에 접속

name = input('채팅 아이디 입력 : ')
cs.send(name.encode('utf_8'))                          # 접속 id send

th = threading.Thread(target=Handle, args = (cs,))     # 쓰레드 생성
th.start()

while True:
    msg = input()                                      # 채팅 메세지 입력
    sys.stdout.flush()
    
    if not msg:continue
    cs.send(msg.encode('utf_8'))                       # msg가 있을 경우 msg send

cs.close()

 


30. pool

GIL(Global Interpreter Lock) 파이썬 인터프리터가 한 스레드만 하나의 바이트코드를 실행 시킬 수 있도록 해주는 Lock
하나의 스레드에 모든 자원을 허락하고 그 후에는 Lock을 걸어 다른 스레드는 실행할 수 없게 막아버린다.
그런 이유로 구조적으로 충돌이 발생하는 경우가 발생한다.
이에 개선사항으로 멀티 프로세싱 모듈 지원한다.

Pool : 압력 값에 대해 process들을 건너건너 분배하여 함수 실행을 병렬하는 방법
PID : process id

 

 * 07_multi_pool

from multiprocessing import Pool
import time 
import os
def f(x):
    print('값', x, '에 대한 작업 pid', os.getpid()) # 현재 진행 중인 process의 processId를 반환
    time.sleep(1)
    return x * x

if __name__ == '__main__':
    p = Pool(3) # pool 객체 생성. 프로세스 수 3 ~ 5 권장
    startTime = int(time.time())
    
    
    for i in range(0, 10): # 0 ~ 9
        print(f(i)) # 10
    
    # 값 0 에 대한 작업 pid 75580
    # 0
    # 값 1 에 대한 작업 pid 75580
    # 1
    # 값 2 에 대한 작업 pid 75580
    # 4
    # 값 3 에 대한 작업 pid 75580
    # 9
    # 값 4 에 대한 작업 pid 75580
    # 16
    # 값 5 에 대한 작업 pid 75580
    # 25
    # 값 6 에 대한 작업 pid 75580
    # 36
    # 값 7 에 대한 작업 pid 75580
    # 49
    # 값 8 에 대한 작업 pid 75580
    # 64
    # 값 9 에 대한 작업 pid 75580
    # 81
    # 총 작업 시간 :  10
    
    print(p.map(f, range(0, 10))) # 함수와 인자값을 매핑하면서 데이터를 분배처리
    # 값 0 에 대한 작업 pid 75712
    # 값 1 에 대한 작업 pid 75604
    # 값 2 에 대한 작업 pid 75540
    # 값 3 에 대한 작업 pid 75712
    # 값 4 에 대한 작업 pid 75604
    # 값 5 에 대한 작업 pid 75540
    # 값 6 에 대한 작업 pid 75712
    # 값 7 에 대한 작업 pid 75604
    # 값 8 에 대한 작업 pid 75540
    # 값 9 에 대한 작업 pid 75712
    # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    # 총 작업 시간 :  5
    endTime = int(time.time())
    print('총 작업 시간 : ', (endTime - startTime))

 


31. process

멀티 프로세실을 위한 Process 클래스
하나의 프로세스를 하나의 함수에 적당한 인자값을 할당해주고 (없을 수도 있음) 진행

 

 * 08_multi_process

import time
import os
from multiprocessing import Process

def func():
    print('연속 진행하고자 하는 어떤 작업')
    #time.sleep(1)

def doubler(number):
    result = number + 10
    func()
    proc = os.getpid()
    print('number : {0}, number : {1},  process id : {2}'.format(number, result, proc))
    
if __name__ == '__main__':
    numbers = [1, 2, 3, 4, 5]
    procs = []
    
    for index, number in enumerate(numbers):
        proc = Process(target = doubler, args = (number, ))
        procs.append(proc) # Process에 join() 추가할 의도
        proc.start() # doubler 함수가 호출
        
    for proc in procs:
        proc.join()
# 연속 진행하고자 하는 어떤 작업
# number : 1, number : 11,  process id : 11880
# 연속 진행하고자 하는 어떤 작업
# number : 2, number : 12,  process id : 59068
# 연속 진행하고자 하는 어떤 작업
# number : 3, number : 13,  process id : 55000
# 연속 진행하고자 하는 어떤 작업
# number : 4, number : 14,  process id : 74932
# 연속 진행하고자 하는 어떤 작업
# number : 5, number : 15,  process id : 55096

32. 웹 크롤링

멀티 프로세싱을 통한 웹 크롤링 연습 1 - 멀티 프로세싱 없이 작업

 * 09_multi_web1

import requests
from bs4 import BeautifulSoup as bs
# html, xml 지원, json 지원x
import time

def get_links(): # 해당 컨텐츠의 a tag 얻기
    data = requests.get("https://beomi.github.io/beomi.github.io_old/").text
    soup = bs(data, 'html.parser')
    my_titles = soup.select('h3 > a')
    data = []
    
    for title in my_titles:
        data.append(title.get('href')) # a tag의 속성 중 href 값 반환
    
    return data

def get_content(link):
    abs_link = "https://beomi.github.io" + link
    req = requests.get(abs_link)
    html = req.text
    soup = bs(html, 'html.parser')
    print(soup.select('h1')[0].text) # 첫번째 h1 tag의 문자열 출력    
    
if __name__ == '__main__':
    #print(get_links())
    #print(len(get_links())) # 26
    start_time = time.time()
    for link in get_links():
        get_content(link)
        
    end_time = time.time()
    print('소요시간 : %s 초'%(end_time- start_time))
    
# 나만의 웹 크롤러 만들기(4): Django로 크롤링한 데이터 저장하기
# 나만의 웹 크롤러 만들기(3): Selenium으로 무적 크롤러 만들기
# Django에 Social Login 붙이기: Django세팅부터 Facebook/Google 개발 설정까지
# Django에 Custom인증 붙이기
# 나만의 웹 크롤러 만들기(2): Login with Session
# 나만의 웹 크롤러 만들기 with Requests/BeautifulSoup
# Celery로 TelegramBot 알림 보내기
# Virtualenv/VirtualenvWrapper OS별 설치&이용법
# [DjangoTDDStudy] #02: UnitTest 이용해 기능 테스트 하기
# [DjangoTDDStudy] #01: 개발환경 세팅하기(Selenium / ChromeDriver)
# [DjangoTDDStudy] #00: 스터디를 시작하며
# Fabric Put 커맨드가 No Such File Exception을 반환할 때 해결법
# CKEditor의 라이센스와 오픈소스 라이센스
# ReactNative The Basis 번역을 끝냈습니다.
# [React Native 번역]#01: 시작하기
# [번역] 장고(Django)와 함께하는 Celery 첫걸음
# Chrome Native Adblockr 대체하기
# CustoMac 설치 분투기
# Ubuntu14.04에 OhMyZsh 설치
# Ubuntu14.04에서 pip로 mysqlclient 설치 실패시
# Ubuntu14.04에서 Python3기반 virtualenvwrapper 설치
# mac OS X에서 pip virtualenvwrapper 설치 시 uninstalling six 에서 Exception 발생 시
# Fabric for Python3 (Fabric3)
# Windows에서 pip로 mysqlclient 설치 실패시(python3.4/3.5)
# 맥에서 윈도RDP로 접속시 한영전환하기.
# pip로 mysqlclient설치 중 mac os x에서 egg_info / OSError 발생시 대처방법
# 소요시간 : 7.727251768112183 초

 

멀티 프로세싱을 통한 웹 크롤링 연습 2 - 멀티 프로세싱 사용

 * 10_multi_web2

import requests
from bs4 import BeautifulSoup as bs
import time
from multiprocessing import Pool

def get_links(): # 해당 컨텐츠의 a tag 얻기
    data = requests.get("https://beomi.github.io/beomi.github.io_old/").text
    soup = bs(data, 'html.parser')
    my_titles = soup.select('h3 > a')
    data = []
    
    for title in my_titles:
        data.append(title.get('href')) # a tag의 속성 중 href 값 반환
    
    return data

def get_content(link):
    abs_link = "https://beomi.github.io" + link
    req = requests.get(abs_link)
    html = req.text
    soup = bs(html, 'html.parser')
    print(soup.select('h1')[0].text) # 첫번째 h1 tag의 문자열 출력    
    
if __name__ == '__main__':
    start_time = time.time()
#     for link in get_links():
#         get_content(link)
    
    pool = Pool(processes = 4)
    pool.map(get_content, get_links())
        
    end_time = time.time()
    print('소요시간 : %s 초'%(end_time- start_time))
    
# Django에 Social Login 붙이기: Django세팅부터 Facebook/Google 개발 설정까지
# 나만의 웹 크롤러 만들기(4): Django로 크롤링한 데이터 저장하기
# Celery로 TelegramBot 알림 보내기
# 나만의 웹 크롤러 만들기(2): Login with Session
# 나만의 웹 크롤러 만들기(3): Selenium으로 무적 크롤러 만들기
# Django에 Custom인증 붙이기
# 나만의 웹 크롤러 만들기 with Requests/BeautifulSoup
# Virtualenv/VirtualenvWrapper OS별 설치&이용법
# [DjangoTDDStudy] #00: 스터디를 시작하며
# [DjangoTDDStudy] #02: UnitTest 이용해 기능 테스트 하기
# CKEditor의 라이센스와 오픈소스 라이센스
# [React Native 번역]#01: 시작하기
# Fabric Put 커맨드가 No Such File Exception을 반환할 때 해결법
# [DjangoTDDStudy] #01: 개발환경 세팅하기(Selenium / ChromeDriver)
# ReactNative The Basis 번역을 끝냈습니다.
# [번역] 장고(Django)와 함께하는 Celery 첫걸음
# Ubuntu14.04에 OhMyZsh 설치
# Chrome Native Adblockr 대체하기
# Ubuntu14.04에서 Python3기반 virtualenvwrapper 설치
# Fabric for Python3 (Fabric3)
# Ubuntu14.04에서 pip로 mysqlclient 설치 실패시
# CustoMac 설치 분투기
# mac OS X에서 pip virtualenvwrapper 설치 시 uninstalling six 에서 Exception 발생 시
# Windows에서 pip로 mysqlclient 설치 실패시(python3.4/3.5)
# 맥에서 윈도RDP로 접속시 한영전환하기.
# pip로 mysqlclient설치 중 mac os x에서 egg_info / OSError 발생시 대처방법
# 소요시간 : 3.3195197582244873 초

33. HttpServer

HttpServer 구축용 클래스를 이용해 웹서버 서비스 하기
HTTPServer : 기본적인 socket 연결을 관리하는 클래스
SimpleHTTPRequestHandler : get, head 요청만 처리가능

 * 01_httpServer1

from http.server import SimpleHTTPRequestHandler, HTTPServer

PORT = 7777

handler = SimpleHTTPRequestHandler
serv = HTTPServer(('127.0.0.1', PORT), handler) # HTTPServer 서버 객체 생성
print('HTTPServer 서비스 시작')
serv.serve_forever()                            # HTTPServer 서비스 시작

 * index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>파이썬</h2>
<a href="https://daum.net">DAUM 접속</a>
<br>
<a href="bbb.html">bbb 문서</a>
<hr>
바닥글. 작성자 : <b style="font-family : 궁서">홍길동</b>
</body>
</html>

* bbb.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
단순웹 운영중<br>
<input type = "button" value = "이전으로" onclick="history.back()">
</body>
</html>


34. CGI

CGI(Common Gateway Interface)란 웹서버(정보제공측)와 클라이언트(정보이용측)간에 필요한 정보교환을 가능하게 해주는 일종의 웹인터페이스라고(일종의 프로그램) 할 수 있습니다.
PHP, ASP, ASP.NET, JSP...
CGI를 지원하는 CGIHTTPRequestHandler를 사용하면 클라이언트와 서버 사이에 자료를 주고 받을 수 있다. py 문서를 처리가능
get, post 요청처리 모두 지원

 

 * 01_httpServer2

from http.server import CGIHTTPRequestHandler, HTTPServer

PORT = 8888

class HandlerClass(CGIHTTPRequestHandler):
    cgi_directories = ['/cgi-bin']

serv = HTTPServer(('127.0.0.1', PORT), HandlerClass) # HTTPServer 서버 객체 생성

print('HTTPServer 서비스 시작')
serv.serve_forever()                            # HTTPServer 서비스 시작

 

 * main.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>메인 페이지</h1>
<ul>
	<li><a href="https://www.naver.com">네이버</a></li>
	<li><a href="cgi-bin/hello.py">hello.py</a></li>
	<li><a href="cgi-bin/world.py">world.py</a></li>
	<li><a href="cgi-bin/my.py?name=tom&age=23">my.py - get방식으로 자료 전달</a></li>
	<li><a href="friend.html">friend</a></li>
	<li><a href="cgi-bin/sangpum.py">상품자료 확인</a></li>
</ul>
</body>
</html>

 * hello

# 웹 서비스가 가능한 파이썬 파일 작성
ss = '파이썬 변수'
kbs = 9
mbc = 10 + 1.0
print('Content-Type:text/html;charset=utf-8\n')
print('<html>')
print('<body>')
print('<h2>파이썬 문서로 정보 전달</h2>')
print('<b><i>hi</i></b>')
print('<br>파이썬 변수 출력 : %s, %d, %f'%(ss, kbs, mbc))
print('</body>')
print('</html>')

 

 * world

s1 = "자료1"
s2 = "자료2"
print('Content-Type:text/html;charset=utf-8\n')
print("""
<html>
<body>
<h2>html문서 좀더 쉽게 작성</h2>
자료 출력 : {0}, {1}
<br>
<img src='../images/pic.png' width='60%' />
<br>
<a href='../main.html'>메인</a>
</body>
</html>
""".format(s1, s2))

 

 * my

#client가 server로 자료 전달
import cgi

# 사용자(client)가 입력한 자료 받기 - get
form = cgi.FieldStorage()
name = form['name'].value
age = form['age'].value

print('Content-Type:text/html;charset=utf-8\n')
print("""
<html>
<body>
사용자가 입력한 자료 <br>
이름 : {0},
나이 : {1}
</body>
</html>
""".format(name, age))

 * friend.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
친구 자료 입력<p/>
<form action="cgi-bin/friend.py" method="post">
이름 : <input type="text" name ="name" value="홍길동"/><br>
전화 : <input type="text" name ="phone"/><br>
성별 : 
<input type="radio" name="gen" value="남" checked="checked"/>남자
<input type="radio" name="gen" value="여"/>여자<br>
<br>
<input type="submit" value="전송">
</form>
</body>
</html>

 

 * friend.py

import cgi

# 사용자(client)가 입력한 자료 받기 - post
form = cgi.FieldStorage()
name = form['name'].value
phone = form['phone'].value
gen = form['gen'].value

# 값으로 DB저장, 연산에 참여 작업 진행필요.
# 단순 출력 진행.
print('Content-Type:text/html;charset=utf-8\n')
print("""
<html>
<body>
이름 : {}<br>
전화번호 : {}<br>
성별 : {}<br>
</body>
</html>
""".format(name, phone, gen))

 * sangpum

# Maria DB의 sangpum table 자료를 웹으로 출력

import MySQLdb
import ast

with open('cgi-bin/mariadb.txt', mode='r') as f:
    config = ast.literal_eval(f.read())
print('Content-Type:text/html;charset=utf-8\n')
print('<html><body><h2>상품자료 (Python 서버이용)</h2>')
print('<table border="1">')
print('<tr><th>코드</th><th>품명</th><th>수량</th><th>단가</th></tr>')
try:
    conn = MySQLdb.connect(**config)
    cursor = conn.cursor()
    cursor.execute("select * from sangdata")
    datas = cursor.fetchall()
    
    for code, sang, su, dan in datas:
        print("""<tr>
        <td>{0}</td>
        <td>{1}</td>
        <td>{2}</td>
        <td>{3}</td>
        </tr>""".format(code, sang, su, dan)) 
except Exception as e:
    print('error',e)
finally:
    cursor.close()
    conn.close()

print('</table></html></body>')

 


35. 챗봇(chatbot)

 

① 사이트 접속 후 파일 다운로드

www.lfd.uci.edu/~gohlke/pythonlibs/#jpype

 

Python Extension Packages for Windows - Christoph Gohlke

by Christoph Gohlke, Laboratory for Fluorescence Dynamics, University of California, Irvine. Updated on 14 February 2021 at 04:31 UTC. This page provides 32- and 64-bit Windows binaries of many scientific open-source extension packages for the official CPy

www.lfd.uci.edu

[JPype1-1.2.0-cp38-cp38-win_amd64.whl] Download

 

② anaconda prompt 접속 후 명령어 입력
cd C:\Users\wonh\Downloads
pip install JPype1-1.2.0-cp38-cp38-win_amd64.whl

pip install --upgrade pip
pip install konlpy

 

 

 * main.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>메인 페이지</h1>
<ul>
	<li>인사관리</li>
	<li>영업관리</li>
	<li>게시판</li>
	<li><a href="cgi-bin/chatbot.py">챗봇</a></li>
</ul>
<pre>
본문
</pre>
<hr>
<footer>바닥글</footer>
</body>
</html>

 * httpServer

# 챗봇용 서버
from http.server import CGIHTTPRequestHandler, HTTPServer

PORT = 8080

class HandlerClass(CGIHTTPRequestHandler):
    cgi_directories = ['/cgi-bin']

serv = HTTPServer(('127.0.0.1', PORT), HandlerClass) # HTTPServer 서버 객체 생성

print('챗봇용 HTTPServer 서비스 시작')
serv.serve_forever()                            # HTTPServer 서비스 시작

 

 * chatbot

import cgi
from botengine import make_reply

# 입력 양식의 글자 추출하기 --- 
form = cgi.FieldStorage()

# 메인 처리 --- 
def go_main():
    m = form.getvalue("m", default="")
    if m == "" : 
        show_form()
    elif m == "say" : 
        api_say()

# 사용자의 입력에 응답하기 --- 
def api_say():
    print("Content-Type: text/plain; charset=utf-8")
    print("")
    txt = form.getvalue("txt", default="")
    if txt == "": 
        return
    res = make_reply(txt)
    print(res)

# 입력 양식 출력하기 --- 
def show_form():
    print("Content-Type: text/html; charset=utf-8")
    print("")
    print("""
    <html><meta charset="utf-8"><body>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <style>
        h1{ background-color: #ffe0e0; }
        div{ padding:10px; }
        span{ border-radius: 10px; background-color: #ffe0e0; padding:8px; }
        .bot{ text-align: left; }
        .usr{ text-align: right; }
    </style>
    <h1>* 대화하기 *</h1>
    <div id="chat"></div>
    <div class='usr'>
      <input id="txt" size="40">
      <button onclick="say()">전송</button>
    </div>
    <script>
    var url = "./chatbot.py";
    function say() {
      var txt = $('#txt').val();
      $.get(url, {"m":"say","txt":txt},
        function(res) {
          var html = "<div class='usr'><span>" + esc(txt) +
            "</span>: 나</div><div class='bot'> 봇:<span>" + esc(res) + "</span></div>";
          $('#chat').html($('#chat').html()+html);
          $('#txt').val('').focus();
        });
    }
    function esc(s) {
        return s.replace('&', '&amp;').replace('<','&lt;').replace('>', '&gt;');
    }
    </script></body></html>
    """)

go_main()

 

 * botengine

import codecs
from bs4 import BeautifulSoup
import urllib.request
from konlpy.tag import Okt
import os, re, json, random

dict_file = "chatbot-data.json"
dic = {}
twitter = Okt()

# 딕셔너리에 단어 등록하기 --- 
def register_dic(words):
    global dic
    if len(words) == 0: return
    tmp = ["@"]
    for i in words:
        word = i[0]
        if word == "" or word == "\r\n" or word == "\n": continue
        tmp.append(word)
        if len(tmp) < 3: continue
        if len(tmp) > 3: tmp = tmp[1:]
        set_word3(dic, tmp)
        if word == "." or word == "?":
            tmp = ["@"]
            continue
    # 딕셔너리가 변경될 때마다 저장하기
    json.dump(dic, open(dict_file,"w", encoding="utf-8"))

# 딕셔너리에 글 등록하기
def set_word3(dic, s3):
    w1, w2, w3 = s3
    if not w1 in dic: dic[w1] = {}
    if not w2 in dic[w1]: dic[w1][w2] = {}
    if not w3 in dic[w1][w2]: dic[w1][w2][w3] = 0
    dic[w1][w2][w3] += 1

# 문장 만들기 --- 
def make_sentence(head):
    if not head in dic: return ""
    ret = []
    if head != "@": 
        ret.append(head)        
    top = dic[head]
    w1 = word_choice(top)
    w2 = word_choice(top[w1])
    ret.append(w1)
    ret.append(w2)
    while True:
        if w1 in dic and w2 in dic[w1]:
            w3 = word_choice(dic[w1][w2])
        else:
            w3 = ""
        ret.append(w3)
        if w3 == "." or w3 == "? " or w3 == "": 
            break
        w1, w2 = w2, w3
        
    ret = "".join(ret)
    
    # 띄어쓰기
    params = urllib.parse.urlencode({
        "_callback": "",
        "q": ret
    })
    
    # 네이버의 맞춤법 검사기 api를 사용
    data = urllib.request.urlopen("https://m.search.naver.com/p/csearch/ocontent/spellchecker.nhn?" + params)
    data = data.read().decode("utf-8")[1:-2]
    data = json.loads(data)
    data = data["message"]["result"]["html"]
    data = soup = BeautifulSoup(data, "html.parser").getText()
    return data

def word_choice(sel):
    keys = sel.keys()
    return random.choice(list(keys))

# 챗봇 응답 만들기 --- 
def make_reply(text):
    # 단어 학습 시키기
    if not text[-1] in [".", "?"]: text += "."
    words = twitter.pos(text)
    register_dic(words)
    # 사전에 단어가 있다면 그것을 기반으로 문장 만들기
    for word in words:
        face = word[0]
        if face in dic: 
            return make_sentence(face)
    return make_sentence("@")

# 딕셔너리가 있다면 읽어 들이기
if os.path.exists(dict_file):
    dic = json.load(open(dict_file, "r"))


 

 

8. 함수(function)

9. 변수의 생존 범위

10. closure(클로저)

11. 일급함수

12. Module

13. 사용자 정의 모듈

14. turtle

15. 외부 모듈 사용

16. Class

17. 포함관계 (has a 관계)

18. 상속

19. 메소드 오버라이딩


8. 함수(function)

 : 여러개의 명령문을 하나의 묶음으로 만든 실행단위.

* test07_func

 - 내장함수

 - sum(a), bin(a), int(a), float(a), str(a)

print(sum([3, 5, 7]))
print(bin(8))
print(int(1.7), float(7), str(5) + '오')

 

eval(문자열) : 문자열을 계산 

a = 10
b = eval('a + 5')
print(b)

 

zip(a, b) : tuple로 묶어준다.

x = [10, 20, 30]
y = ['a', 'b']
for i in zip(x, y):
    print(i)
# (10, 'a')
# (20, 'b')

 

 

- 사용자 정의 함수

def DoFunc1():
    print('사용자정의 함수 1')
    
print("do1")
DoFunc1()
print("do2")
DoFunc1()
print(DoFunc1)       # 함수 이름은 객체(함수 본체)의 주소를 기억함수
print(type(DoFunc1)) # function
otherFunc = DoFunc1  # 주소 치환
otherFunc()

globals() : 모든 전역 변수 출력

print(globals()) # 모든 전역 변수 출력

 

def DoFunc2(name):
    print('hi', name)
    
DoFunc2('tom')
#DoFunc2('tom', 'tom2') # error
DoFunc2(100)

 

def DoFunc3(ar1, ar2):
    temp = ar1 + ar2
    print('temp', temp)
    # return None # default : None
    #return temp
    a = 2
    if a % 2 ==1:
        return
    else:
        return a
    print('dead')

    
DoFunc3(10, 20)
DoFunc3('kbs', 'mbc')
print(DoFunc3('kbs', 'mbc'))

 

def area_tri(a, b):
    c = a * b / 2
    if a == 0:
        return # 함수 탈출
    area_print(c) # 함수는 함수 호출가능
    
def area_print(c):
    print('삼각형의 넓이는 ',c)

area_tri(20, 30) # 삼각형의 넓이는  300.0

 

def abc():
    pass

 

def exam(a, b):
    ss = str(a) + '+' + str(b) + '=의 답은 : '
    ans = input(ss)
    return a + b == int(ans)

if(exam(5, 2)):
    print('good')
else:
    print('sad')

 

def swap(a, b):
    return b, a

a = 10; b = 20
print(swap(a, b)) # (20, 10)

 

def isOdd(arg):
    return arg % 2 == 1

print(isOdd(3)) # True
print(isOdd(4)) # False

myDict = {x:x*x for x in range(11) if isOdd(x)}
print(myDict) # {1: 1, 3: 9, 5: 25, 7: 49, 9: 81}

9. 변수의 생존 범위

 Local < Enclosing function > Global

* test08_func

player = '전국대표'        # Global Variable

def funcSoccer():
    player = '지역대표'    # Local Variable
    name = '한국인'       # Local Variable
    print(name, player)

funcSoccer()
# print(name, player) # 지역변수는 해당 블록에서만 사용 가능. Error

global a : 블록 내의 지역변수가 아닌 전역변수를 사용하도록 한다.
nonlocal a : 블록 내의 지역변수가 아닌 가까운 함수의 변수를 사용하도록 한다.

a = 10; b = 20; c = 30
print('1) a:{}, b:{}, c:{}'.format(a,b,c))

def Foo():
    a = 40
    b = 50
    def Bar():
        #c = 60
        global c # 블록 내의 지역변수가 아닌 전역변수를 사용하도록 한다.
        nonlocal b # 블록 내의 지역변수가 아닌 가까운 함수의 변수를 사용하도록 한다.
        print('2) a:{}, b:{}, c:{}'.format(a,b,c)) # Enclosing function
        c = 60   # UnboundLocalError: local variable 'c' referenced before assignment
        b = 70
    Bar()

Foo()
#Foo().Bar()
print('3) a:{}, b:{}, c:{}'.format(a,b,c))
print()

 

 - argument 키워드로 매칭

def ShowGugu(start = 1, end = 5):
    print(start, end)

ShowGugu(2, 8)      # 2 8
ShowGugu()          # 1 5
ShowGugu(2)         # 2 5
ShowGugu(start = 2) # 2 5
ShowGugu(end = 10)  # 1 10
ShowGugu(start = 2, end = 7)
ShowGugu(end = 7, start = 2)
#ShowGugu(start = 2, 7) # SyntaxError: positional argument follows keyword argument
ShowGugu(2, end = 7)

 

 - 가변인수 : 인수의 개수가 부정확한 경우

def func1(*ar):
    print(ar)
    for i in ar:
        print('음식 : ' + i)

func1('비비비')
func1('비비비','이이이','트트트트')

 

def func2(a, *ar):
#def func2(*ar, a): # TypeError
    print(a)
    print(ar)
    for i in ar:
        print('음식 : ' + i)

func2('비비비')
func2('비비비','이이이','트트트트')

 

re = 0
def selectProcess(choice, *ar):
    if choice == '+':
        re = 0
        for i in ar:
            re += i
    elif choice == '*':
        re = 1
        for i in ar:
            re *= i
    return re

print(selectProcess('+',1,2,3,4,5))
print(selectProcess('*',1,2,3,4,5))

 

def func3(w, h, **ect):
    print('몸무게 {}, 키 {}'.format(w, h))
    print(ect)
    
func3(65, 175, name = '홍길동')
func3(65, 178, name = '고길동', age = 22)
func3(w=80, h=175, name = '김길동')

 

def func4(a, b, *v1, **v2):
    print(a, b)
    print(v1)
    print(v2)
    
func4(1, 2)
func4(1, 2, 3, 4, 5)
func4(1, 2, 3, 4, 5, k=9, s=5)

10. closure(클로저)

 : 내부 함수의 주소를 반환해서 함수의 멤버를 계속적으로 참조

* test09_closure

def out():
    count = 0
    def inn():
        nonlocal count
        count += 1
        return count
    print(inn())

#print(count)
out() # 1
out() # 1
def outer():
    count = 0
    def inner():
        nonlocal count
        count += 1
        return count
    return inner     # 클로저(내부 함수의 주소를 반환)

obj1 = outer() # inner의 주소를 치환
print(obj1)
print(obj1()) # 1

result = obj1()
print(result) # 2

print(obj1()) # 3
print()

 

 - 수량 * 단가 * 세급 결과 출력

def outer2(tax):
    def inner2(su, dan):
        amount = su * dan * tax
        return amount
    return inner2 # 클로저

q1 = outer2(0.1)  # tax = 0.1
print(q1)
result1 = q1(5, 10000)
print(result1)    # 5000.0

result2 = q1(10, 20000)
print(result2)    # 20000.0

q2 = outer2(0.05) # tax = 0.05
result3 = q2(5, 10000)
print(result3)    # 2500.0

result4 = q2(10, 20000)
print(result4)    # 10000.0

 

 - 재귀함수 - 반복처리

def CountDown(n):
    if n == 0:
        print('처리완료')
    else:
        print(n, end = ' ')
        CountDown(n - 1) # 함수가 자신을 호출
        
CountDown(5) # 5 4 3 2 1 처리완료
def totFunc(su):
    if su == 1:
        print('처리 끝')
        return 1
    return su + totFunc(su - 1)

re = totFunc(10)
print('10까지의 합은 : ', re) # 10까지의 합은 :  55

11. 일급함수

 : 함수 안에 함수 선언 가능, 인자로 함수 사용, 반환값이 함수 가능

def func1(a, b):
    return a + b

func2 = func1      # 함수의 주소를 치환
print(func1(2,3))  # 5
print(func2(2,3))  # 5

def func3(func):   # 인자로 함수 사용
    def func4():   # 함수 안에 함수 선언 가능
        print('내부함수')
    func4()
    return func    # 반환값이 함수 가능

mbc = func3(func1) # func1
print(mbc(3, 4))   # 내부함수 7

 

 - Lambda : 이름이 없는 한 줄짜리 함수
형식 : lambda arg, ... :표현식   => return문 없이 결과 반환

def hap(x, y):
    return x + y
print(hap(2, 4))   # 6

aa = lambda x, y: x + y
print(aa(2, 4))    # 6

kbs = lambda a, su = 10: a + su
print(kbs(5))      # 15
print(kbs(5, 6))   # 11

sbs = lambda a, *tu, **di : print(a, tu, di)
sbs(1,2,3,tvn=3, ytn=24) # 1 (2, 3) {'tvn': 3, 'ytn': 24}

li = [lambda a, b:a+b, lambda a, b:a*b]
print(li[0](3,4))  # 7
print(li[1](3,4))  # 12

 

 - 다른 함수에서 인자 값으로 람다를 사용
filter(함수, 집합형 자료) : 자료의 요소 하나씩를 함수에 입력하여 결과값을 집합형으로 출력

print(list(filter(lambda a: a < 5, range(10))))  # [0, 1, 2, 3, 4]
print(tuple(filter(lambda a: a % 2, range(10)))) # (1, 3, 5, 7, 9)

 

 - 함수 장식자 - meta 기능을 가짐. @함수명

def make2(fn):
    return lambda : 'hi '+ fn()

def make1(fn):
    return lambda : 'hello '+ fn()

def hello():
    return '이이이'

hi = make2(make1(hello))
print(hi()) # hi hello 이이이
print()

@make2
@make1
def hello2():
    return '리리리'

print(hello2()) # hi hello 리리리

hi2 = hello2()
print(hi2)

hi3 = hello2
print(hi3)
print(hi3())

12. Module

 : 소스 코드의 재사용을 가능하게 하며, 소스 코드를 하나의 이름 공간으로 구분하고 관리할 수 있다.
멤버 : 일반 명령문, 함수, 모듈, 클래스
하나의 파일로 처리된다.
내장된 표준 모듈, 사용자 정의 모듈, 제 3자 모듈(third party)

 

* test11_module

 -  내장된 표준 모듈(로딩 필요 없음) 일부 사용해 보기
 작업 중 외부모듈이 필요한 경우 import 모듈명하여 사용

print(sum([2, 3])) # 내장된 표준모듈

import sys
print('모듈 경로 : ',sys.path)
sys.exit() # 프로그램 강제 종료
print('프로그램  종료')
import math
print(math.pi)# 3.141592653589793
print(math.sin(math.radians(30))) # 0.49999999999999994
import calendar
calendar.setfirstweekday(6) # 첫주 시작을 일요일로 변경
calendar.prmonth(2021,2)    # 달력 출력
#    February 2021
# 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

 

 - 난수 출력

import random
print(random.random())       # 난수 출력 
print(random.randint(1, 10)) # 1~10 사이의 난수

from random import random
print(random())

from random import randint
from random import *
print(randint(1, 10))

13. 사용자 정의 모듈

* test12_my (동일 패키지)

# 사용자 정의 모듈
tot = 123 # 전역변수

def ListHap(*ar):
    print(ar)
    
    if __name__ == "__main__":
        print('응용프로그램이 시작되는 모듈')
    
    
def kbs():
    ch = 9
    print('공영방송', ch)
    
def mbc():
    print('문화방송')

 

* test12_our (다른 패키지)

# 사용자 정의 모듈
def Hap(a, b):
    return a + b

def Cha(a, b):
    return a - b

* test12_our2 (lib폴더 경로)

# 사용자 정의 모듈
def Gop(a, b):
    return a * b

def Nanugi(a, b):
    return a / b

* test12_module

# 사용자 정의 모듈
a = 10
print(a)

def aa():
    print('aa 출력')
    
# 외부 모듈의 멤버 사용하기1
import pack2.test12_my  # 경로

print('tot : ', pack2.test12_my.tot) # tot :  123

li1 =[1, 2]
li2 =[3, 4]
pack2.test12_my.ListHap(li1, li2)


def abc():
    if __name__ == "__main__":
        print('응용프로그램이 시작되는 모듈')
        
abc()

pack2.test12_my.kbs()
print()

# 외부 모듈의 멤버 사용하기2
from pack2 import test12_my
test12_my.mbc() 

from pack2.test12_my import mbc
mbc() 

from pack2.test12_my import mbc, kbs, tot
mbc()
kbs()
print(tot)
print()

# 외부 모듈의 멤버 사용하기3 - package가 다른 경우
from other.test12_our import Hap, Cha
print(Hap(5, 3)) # 8
print(Cha(5, 3)) # 2

# C:\anaconda3\Lib 경로의 모듈 사용
import test12_our2
print(test12_our2.Gop(5, 3))
print(test12_our2.Nanugi(5, 3))

import math
print(math.pi)

from test12_our2 import Gop
print(Gop(5, 3))

from math import pi
print(pi)

window - Preferences - PyDev - Interpreters - Python Interpreters - Libraries Tab 선택 안의 경로에 추가시 import 할 수 있다. 


14. turtle

 : Graphic 지원 모듈 사용 - turtle

* test13_graphic

import turtle
from turtle import *
pen = Pen()
pen.color('red', 'yellow')
pen.begin_fill()
while True:
    pen.forward(200)
    pen.left(170)
    if abs(pen.pos()) < 1:
        break
pen.end_fill()
done()

15. 외부 모듈 사용

* test14

① http://www.lfd.uci.edu/~gohlke/pythonlibs/ 사이트에서 모듈 다운로드하여 lib경로에 설치 

② 시작  - anconda prompt - pip install pygame

import pygame

16. Class

: OOP 기법 구사
: 클래스는 새로운 이름 공간을 지원하는 단위. 멤버는 변수, 메소드, 생성자로 구성. 접근 지정자X, 메소드 오버로딩X

 

* test15_class

print('do')

def func():
    print('함수')
class TestClass: # 원형 클래스  - prototype (객체가 실행과 동시에 생성. new 미사용)
    abc = 1 # 멤버변수(전역변수)
    
    def __init__(self):
        print('생성자')
        
    def __del__(self):
        print('소멸자')
        
    def printMsg(self): # 메소드
        name = '홍길동'
        print(name)
        print(self.abc)
        self.show()
        
    def show(self):
        print('show')
print(TestClass.abc) # 원형 클래스의 멤버 변수 호출
TestClass.printMsg(self) # NameError: name 'self' is not defined
test = TestClass() # 생성자 호출된 후 객체 생성(instance)
# 생성자
print(test.abc) # 1
test.printMsg()          # 1. Bound method call
# 홍길동 1 show
TestClass.printMsg(test) # 2. UnBound Method call
# 홍길동 1 show
print('클래스 타입확인 : ', type(1))    # int
print('클래스 타입확인 : ', type(test)) # __main__.TestClass
print(id(test))      # 2502643056496
print(id(TestClass)) # 2502639316704

 

 * test16_class

class Car:
    handle = 0 # 멤버 변수(필드). 클래스 내 전역
    speed = 0
    
    def __init__(self, name, speed): # 생성자 오버로딩 불가
        self.name = name
        self.speed = speed
        
    def showData(self): # 메소드 오버로딩 불가
        km = ' 킬로미터' # 지역변수
        msg = '속도 : ' + str(self.speed) + km
        return msg
# car1    
car1  = Car('tom', 10)
print(car1.handle, car1.name, car1.speed) # 0 tom 10
car1.color = '핑크'
print('car1.color : ', car1.color)
# car2
car2 = Car('james', 30)
print(car2.handle, car2.name, car2.speed) # 0 james 30
print('car2.color : ', car2.color) # AttributeError: 'Car' object has no attribute 'color'
# __dict__ : 해당 인스턴스의 멤버변수 dict
print(car1.__dict__) # {'name': 'tom', 'speed': 10, 'color': '핑크'}
print(car2.__dict__) # {'name': 'james', 'speed': 30}
# method
print('car1 - ', car1.showData()) # car1 -  속도 : 10 킬로미터
print('car2 - ', car2.showData()) # car2 -  속도 : 30 킬로미터
car1.speed = 100
car2.speed = 200
print('car1 - ', car1.showData()) # car1 -  속도 : 100 킬로미터
print('car2 - ', car2.showData()) # car2 -  속도 : 200 킬로미터
print(Car.speed)  # 0
print(car1.speed) # 100
print(car2.speed) # 200

print(Car.color)  # AttributeError: type object 'Car' has no attribute 'color'
print(car1.color)  # 핑크
print(car2.color) # AttributeError: type object 'Car' has no attribute 'color'

 

* test17_class

kor = 100 # 모듈의 전역변수

def abc():
    print('모듈의 멤버 함수')
    
class MyClass:
    kor = 88
    """
    def __init__(self): # 기본 생성
        pass
    """
    def abc(self):
        print('클래스의 멤버 메소드')
       
    def showData(self):
        print(kor) # 메소드 내에서 없을 경우 모듈의 전역변수를 찾는다. 
        print(self.kor) 
        self.abc() # 현재 클래스 내의 메소드 콜
        abc()      # 모듈의 함수 콜
obj = MyClass()
obj.showData()
# 100
# 88
# 클래스의 멤버 메소드
# 모듈의 멤버 함수
class My:
    a = 1
print(My.a) # 1

my1 = My # 주소
print(my1.a) # 1

my2 = My() # 인스턴스 생성
my2.a = 100
print(my2.a) # 100

my3 = My() # 인스턴스 생성
my3.a = 200
print(my3.a) # 200
my3.b = 123
print(my3.b) # 123

print(My.b)  # Error
print(my1.b) # Error
print(my2.b) # Error

* test18_class

# 클래스 = 설계도
# Singer가 갖추어야 할 기본 속성, 행위를 설계도(원형클래스)로 만든 후 모든 가수들은 Singer type으로 존재하면 됨

class Singer:
    title_song ='노래제목' # 멤버 변수
    
    def __init__(self):
        pass
    
    def sing(self):
        msg = '노래는'
        print(msg, self.title_song)
        
# 편의 상 아래에서 객체를 만들지만 별도의 모듈에서 Singer를 호출하여 사용하는 것이 일반적        
bts = Singer()
bts.sing()              # 노래는 노래제목
bts.title_song = '다이너마이트'
bts.sing()              # 노래는 다이너마이트
bts.co = '빅히트'
print('소속사 :', bts.co) # 소속사 : 빅히트

* test18_class2

# 클래스 연습
print('do')
a = 10
def aa():
    print(a)
    
# 새로운 가수 타입의 객체 필요
import pack2.test18_class

print('-----------------')
twice = pack2.test18_class.Singer()
twice.sing() # 노래는 노래제목
twice.title_song = '우아하게'
twice.sing() # 노래는 우아하게
print('소속사 :', twice.co) # error

17. 포함관계 (has a 관계)

 * test19_handle

# 움직이는 기계에 사용할 부품 클래스

class PohamHandle:
    quantity = 0 # 회전량
    
    def LeftTurn(self, quantify):
        self.quantity = quantify
        return '좌회전'
    
    def RightTurn(self, quantify):
        self.quantity = quantify
        return '우회전'

 

 * test19_car

# Car 클래스 : 여러개의 부품(클래스)을 조립해서 완성된 차를 생성
class PohamCar:
    speed = 0
    turnShow = '정지'
    
    def __init__(self, ownerName):  # ownerName 인스턴트에만 존재. 원형클래스에는 없음
        self.owerName = ownerName
        self.handle = PohamHandle() # 클래스의 포함 관계
        
    def TurnHandle(self, q):        # PohamCar 메소드로 핸들을 움직이는 행위
        if q > 0:
            self.turnShow = self.handle.RightTurn(q)
        elif q < 0:
            self.turnShow = self.handle.LeftTurn(q)
        elif q == 0:
            self.turnShow = '직진'
            
if __name__ == '__main__':
    tom = PohamCar('톰')
    tom.TurnHandle(10)
    print(tom.owerName+'의 회전량은 ' + tom.turnShow + str(tom.handle.quantity)) # 톰의 회전량은 우회전10
    tom.TurnHandle(0)
    print(tom.owerName+'의 회전량은 ' + tom.turnShow) # 톰의 회전량은 우회전10
    print()
    
    oscar = PohamCar('오스카')
    oscar.TurnHandle(-5)
    print(oscar.owerName+'의 회전량은 ' + oscar.turnShow + str(oscar.handle.quantity))
    # 오스카의 회전량은 좌회전-5
    

 * test20_has_a

 - 냉장고(class)에 음식(class)을 저장

class FoodData:
    def __init__(self, name, expiry):
        self.name = name
        self.expiry = expiry
class Fridge:
    isOpend = False # 냉장고 문 개폐 여부
    foods = []      # 리스트
    
    def open(self):
        self.isOpend = True
        print('냉장고 문이 열렸습니다.')
        
    def close(self):
        self.isOpend = False
        print('냉장고 문이 닫혔습니다.')
        
    def put(self, thing):
        if self.isOpend == True:
            self.foods.append(thing) # 클래스의 포함
            print('냉장고에 음식을 저장하였습니다.')
            self.listFood()
        else:
            print('냉장고 문이 닫혀있어 음식을 담을 수 없습니다.')
        
    def listFood(self):
        for f in self.foods:
            print('-', f.name, f.expiry)
f = Fridge()
apple = FoodData('사과', '2021-3-5')
f.put(apple)    # 냉장고 문이 닫혀있어 음식을 담을 수 없습니다.
f.open()        # 냉장고 문이 열렸습니다.
f.put(apple)    # 냉장고에 음식을 저장하였습니다.
                # - 사과 2021-3-5
f.close()       # 냉장고 문이 닫혔습니다.
cola = FoodData('콜라', '2022-12-5')
f.open()        # 냉장고 문이 열렸습니다.
f.put(cola)     # 냉장고에 음식을 저장하였습니다.
                # - 사과 2021-3-5
                # - 콜라 2022-12-5
f.close()       # 냉장고 문이 닫혔습니다.

18. 상속

: 클래스가 다른 클래스의 멤버를 활용 - 상속 : 다형성을 구사

* test21_inherit

class Animal: # 별도의 모듈에서 작성하고 호출하였다고 가정
    age = 0
    
    def __init__(self):
        print('Animal 생성자')
    
    def move(self):
        print('움직이는 생물')
class Dog(Animal): # 상속
    age = 10
    
    def __init__(self):
        print('Dog 생성자')
    
    def dogShow(self):
        age = 2
        print('개')
        print('age :', age)         # 지역변수
        print('age :', self.age)    # 클래스 -> 부모
        print('age :', super().age) # 부모
dog1 = Dog()    # 자식 생성자가 있을 경우 자식 생성자만 수행
                # 자식 생성자가 없을 경우 부모 생성자가 수행
print('dog1.age :',dog1.age) # dog1.age : 0
dog1.move()                  # 움직이는 생물
dog1.dogShow()
# 개
# age : 2
# age : 10
# age : 0
class Horse(Animal):
    pass

horse = Horse()
horse.move()

 클래스 상속 연습

* test22_inherit

class Person:
    say = '사람'
    age = 20
    __kbs = '공영방송' # __변수명 : private 멤버 - 현재 클래스에서만 호출 가능
    
    def __init__(self, age):
        print('Person 생성자')
        self.age = age
        
    def printInfo(self):
        print('나이 :{}, 이야기:{}'.format(self.age, self.say))
    
    def hello(self):
        print('hello')
        print('hello : ', self.say, self.__kbs)
        
        
pe = Person(22) # Person 생성자
pe.printInfo()  # 나이 :22, 이야기:사람
pe.hello()
# hello
# hello :  사람 공영방송
class Employee(Person):
    say = "직원"          # 자식과 동일한 멤버변수에 의해 부모의 say가 숨겨짐
    subject = '근로자'     # Employee 고유 멤버 변수
    
    def __init__(self):
        print("Employee 생성자")
        
    def printInfo(self): # 자식과 동일한 메소드에 의해 부모의 메소드가 숨겨짐. 메소드 오버라이드
        print('Employee printInfo 메소드')
        
    def empShow(self):
        say = "empShow"
        print(say)
        print(self.say)
        self.printInfo()    # 자식 -> 부모
        super().printInfo() # 부모
        

emp = Employee()         # Employee 생성자
print(emp.say, emp.age)  # 직원 20
print(emp.subject)       # 근로자
emp.printInfo()          
# 나이 :20, 이야기:직원
# Employee printInfo 메소드
emp.empShow()
# empShow
# 직원
# Employee printInfo 메소드
# 나이 :20, 이야기:직원
class Worker(Person):
    pass

wo = Worker(33)       # Person 생성자
print(wo.say, wo.age) # 사람 33
wo.printInfo()        # 나이 :33, 이야기:사람
class Worker(Person):
    hobby = '코딩'
    
    def __init__(self, age):
        print('Worker 생성자')
        #super().__init__(age) # 부모의 생성자 호출. Bound call
        Person.__init__(self, age) # UnBound call
    
    def woShow(self):
        self.printInfo()
        super().printInfo()
        
wo = Worker(27)
# Worker 생성자
# Person 생성자
wo.woShow()
# 나이 :27, 이야기:사람
# 나이 :27, 이야기:사람
class Programmer(Worker):
    def __init__(self, age):
        print('Programmer 생성자')
        Worker.__init__(self, age)
        
    def prShow(self):
        self.printInfo()
        super().printInfo()
        
    def kbsShow(self):
        print(self.say)
        #print(self.__kbs) # AttributeError: 'Programmer' object has no attribute '_Programmer__kbs'

pr = Programmer(25)
# Programmer 생성자
# Worker 생성자
# Person 생성자
print(pr.say, pr.age) # 사람 25
pr.prShow()
# 나이 :25, 이야기:사람
# 나이 :25, 이야기:사람
pr.hello()
# hello
# hello :  사람 공영방송
pr.kbsShow()
# 클래스 타입확인
a = 3
print(type(a)) # int
print(type(pr)) # __main__.Programmer
print(Programmer.__bases__) # 부모클래스 확인. __main__.Worker
print(Worker.__bases__) # __main__.Person
print(Person.__bases__) # object

19. 메소드 오버라이딩

: 부모 클래스의 메소드와 동일한 이름의 메소드를 자식 클래스에서 만듦(재정의)
다형성의 근거를 제시

* test23_override

class Parent:
    def printData(self): # 추상 메소드와 유사. 강제하지않음.
        pass
    
    def displayData(self):
        print('Parent의 displayData')
class Child1(Parent):
    def printData(self): # 메소드 오버라이딩
        a = 10
        b = 20
        print(str(a + b) + " 출력")
class Child2(Parent):
    def printData(self):   # override
        print('Child2 printData')
        
    def displayData(self): # override 부모 메소드를 재정의
        print('Child2 displayData')
        
    def c2method(self):    # Child2 고유 메소드
        print('Child2 c2method')
c1 = Child1()
c1.printData()   # 30 출력
c1.displayData() # Parent의 displayData
c2 = Child2()
print()
c2.printData()   # Child2 printData
c2.displayData() # Child2 displayData
print()
# 다형성
par = Parent()
par = c1          # 자식객체의 주소를 치환
par.printData()   # 30 출력
par.displayData() # Parent의 displayData
print()

par = c2          # 자식객체의 주소를 치환
par.printData()   # Child2 printData
par.displayData() # Child2 displayData
par.c2method()    # 오버라이딩 하지않은 메소드도 호출 가능
print()
# 자바와 파이썬 차이
sbs = c1          # 주소 치환시 같은 타입이 아니더라도 객체 및 메소드 사용가능
sbs.printData()
sbs.displayData()
print()
sbs = c2
sbs.printData()
sbs.displayData()
sbs.c2method()
print()

plist = [c1, c2]
for i in plist:
    i.printData()

1. 변수

2. 연산자

3. 집합형 자료

4. 정규 표현식

5. 조건 판단문 if문

6. 반복문 while

7. 반복문 for

 


1. 변수 : 기본형 X, 참조형 O

id(a) : 주소확인 함수

is : 주소 비교, == : 값 비교

a=1
b=1.2
c=b
print(a,b,c)
print(id(a), id(1), id(b), id(c)) # id(a) : 주소확인 함수,
# 140710866855712 140710866855712 2553731934640 2553731934640

print(a is b, a==b) # is : 주소 비교, == : 값 비교  
#False False

print(b is c, b==c) 
#True True

 - 주석

#한줄 주석
"""
여러줄 주석
"""
'''
여러줄 주석
'''

 - 출력

print('hello')
var1 = 'hi'
var1 = 10
print(var1)

대소문자 구분

A = 1;
a = 2;
print(A, a, A==a) # 1 2 False

변수명으로 키워드 사용 불가

for = 5 # error

import : 외부모듈 읽기 - 설치된 모듈 로딩

import keyword
# keyword.kwlist : 키워드 리스트 출력
print(keyword.kwlist)
# ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue',
#'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 
#'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

oct(a) : 8진수,  hex(a) : 16진수, bin(a) : 2진수

print(10, oct(10), hex(10), bin(10)) # 10 0o12 0xa 0b1010
print(10,0o12, 0xa, 0b1010) # 10 10 10 10

type(a) : type 확인

print(3, type(3))         # int
print(3.4, type(3.4))     # float
print(3+4j, type(3+4j))   # complex
print(True, type(True))   # bool
print('aa', type('aa'))   # str
print("abc", type("abc")) # str

isinstance(a, b) : 객체 type 확인 함수

print(isinstance(1, int))   # True
print(isinstance(1.2, int)) # False

집합형 자료형

print((1), type((1)))          # int. 집합형 자료형X
print((1,), type((1,)))        # tuple
print([1], type([1]))          # list
print({1}, type({1}))          # set
print({'k':1}, type({'k':1}))  # dict

2. 연산자

print(a, end=' ')

v1 = 123
v3 = v2 = v1      # 치환
print(v1, v2, v3) # 123 123 123
print('입니다') # 자동 줄바꿈
print(v1, v2, v3, end='---')  # 자동 줄바꿈X
print('입니다') # 123 123 123---입니다
v4 = 1,2,3
print(v4, type(v4)) # (1, 2, 3) <class 'tuple'>
print(v4, \
      type(v4)) # \ : 명령이 이어짐.

swap

v1, v2 = 100, 200
print(v1, v2) # 100 200
v2, v1 = v1, v2
print(v1, v2) # 200 100

packing - 값할당 연산

v1, v2 = [1, 2, 3, 4, 5] # 불가
v1, *v2 = [1, 2, 3, 4, 5]
print(v1, v2)

*v1, v2 = [1, 2, 3, 4, 5]
print(v1, v2)

*v1, v2, v3 = [1, 2, 3, 4, 5]
*v1, *v2, v3 = [1, 2, 3, 4, 5] # 불가
print(v1, v2, v3)

산술, 관계, 논리

print(5 + 3, 5 - 3, 5 * 3, 5 / 3)

// : 몫 , % : 나머지, divmod() : 몫/나머지

print(5 / 3, 5 // 3, 5 % 3, divmod(5, 3)) # 1.6666666666666667 1 2 (1, 2)

 ( ) > 산술(*,/ > +,-) > 관계 > 논리> 치환

print(3 + 4 * 5, (3 + 4) * 5) # 23 35.

관계 연산자

print(5 > 3, 5 == 3, 5 != 3, 5 <= 5)

논리 연산자 and, or, not(a)

print(5 > 3 and 4 <=3, 5 > 3 or 4 < 3 , not(5 >= 3))
print('강남' + '거리' + 2021) # TypeError

str(a) : 문자로 형변환, int(a) : 숫자로 현변환

print('강남' + '거리' + str(2021) + ' ' + '2000' + '21' + str(int('2000') + int('21')))

문자열 연산

print('답' * 10)
print('----------' * 10)
a = 5
a = a + 1
a += 1 # a++, ++a, a--, --a 증감연산자 사용 불가.
print('a : ' + str(a))

부호 변경

print(a, a * -1, -a, --a, +a, ++a) # 7 -7 -7 7 7 7

False

print('boolean : ', bool(False), bool(0), bool(0.0), bool(''), bool(None), bool([]), bool({}), bool(set()))

True

print('boolean : ', bool(True), bool(1), bool(-12), bool(1.5), bool('aa')) #  True True True True True

이스케이프 문자 : \n, \b, \t ...

print('aa\tbb')
print('aa\nbb')
print('c:\aa\nbc\cc.txt')
print(r'c:\aa\nbc\cc.txt') # r'' : 이스케이프 문자로 해석하지않음. 

format()

print(format(1.5678, '10.3f'))
print('나는 나이가 %d 이다.'%23)
print('나는 나이가 %s 이다.'%'스물셋')
print('나는 나이가 %d 이고 이름은 %s이다.'%(23, '홍길동'))
print('나는 나이가 %s 이고 이름은 %s이다.'%(23, '홍길동'))
print('나는 키가 %f이고, 에너지가 %d%%.'%(177.7, 100))
print('이름은 {0}, 나이는 {1}'.format('한국인', 33))
print('이름은 {}, 나이는 {}'.format('신선해', 33))
print('이름은 {1}, 나이는 {0}'.format(34, '강나루'))

3. 집합형 자료

 - 문자열 자료형 - 순서 존재, 수정 불가X

 len(a) : a의 길이

 s1.count('a') : s1에서 a 개수

s = 'sequence' # "sequence" 동일. """sequence""""
print(s)
print(len(s), s.count('e')) # 8 3

 

 - 문자열 관련 함수

 s1.find('a') : s1에서 앞에서 부터 가장 앞의 a의 index

 s1.find('a', 3) : s1에서 앞에서 부터 3번째 a의 index

 s1.rfind('a') : s1에서 뒤에서 부터 a의 index

print(s.find('e'), s.find('e', 3), s.rfind('e')) # 1 4 7
ss = 'kbs'
print(ss, id(ss)) # 1847323654896
ss = 'sbs' # 변수의 값이 변경되는 것이 아닌, 새로운 객체 생성.
print(ss, id(ss)) # 1847326686384

 

 - 슬라이싱 : 집합형 자료의 일부 요소만 참조

s[1:6:2] : 1번부터 5번까지 2간격 문자

print(s, s[0], s[2:4], s[3:]) # sequence s qu uence
print(s[-1], s[-4:-1], s[1:6:2]) # e enc eun
s[0] = 'k' # TypeError: 'str' object does not support item assignment

 

s.split(sep=' ') : 구분자를 기준으로 나눠 리스트로 리턴

ss2 = 'kbs mbc'
ss3 = ss2.split(sep=' ')  # ['kbs', 'mbc']

 

s1.join(s2) : s2의 리스트 사이에 s1을 넣어 결합하여 리턴

print(":".join(ss3)) # kbs:mbc

 

s1.replace(s2, s3) : s1에서 s2를 s3로 변경하여 리턴

a = 'life is too short'
b = a.replace("life", "java") # java is too short

 

 - list 타입 : 순서 O, 변경O, 여러종류의 값을 기억, [요소1, 요소2, ...], 배열과 유사

family = ['mother', 'father', 'me', 123, 12.345]
print(type(family)) # list

str1.append(str2) : str1에 str2 추가

str1.insert(a, str2) : str1의 a번째에 str2 삽입

str1.remove(str2) : str1에서 str2 제거

str1.index(str2) : str1에 str2 index

str1[0] = str2 : str1의 0번째 index값 str2로 변경

 

family.append(['삼촌', '고모']) # ['mother', 'father', 'me', 123, 12.345, ['삼촌', '고모']]
family.append('이모')          # ['mother', 'father', 'me', 123, 12.345, ['삼촌', '고모'], '이모']
family.insert(0, '할머니')     # ['할머니', 'mother', 'father', 'me', 123, 12.345, ['삼촌', '고모'], '이모'] 
family += ['아저씨']           
# ['할머니', 'mother', 'father', 'me', 123, 12.345, ['삼촌', '고모'], '이모', '아저씨']
family.remove('이모')
print(family, len(family), family.index('father'))
# ['할머니', 'mother', 'father', 'me', 123, 12.345, ['삼촌', '고모'], '아저씨'] 8 2
print(family[0], family[1:4])  # 할머니 ['mother', 'father', 'me']
print(family[6], family[6][1]) # ['삼촌', '고모'] 고모
family[0] = '할아버지' # ['할아버지', 'mother', 'father', 'me', 123, 12.345, ['삼촌', '고모'], '아저씨']

 

 - Tuple 타입 : 순서 O, 변경X, 읽기 전용, (요소1, 요소2, ...), 속도가 빠름, 리스트와 유사

t =('a', 'b', 'c', 'd', 'a')
t ='a', 'b', 'c', 'd', 'a'
print(t, type(t), len(t), t.count('a'))
# ('a', 'b', 'c', 'd', 'a') <class 'tuple'> 5 2
print(t[1], t[2:5])
# b ('c', 'd', 'a')
t[1] = 'k' # TypeError: 'tuple' object does not support item assignment

list(a) : list타입으로 변경

tuple(a) : tuple타입으로 변경

temp = list(t) # 형변환 후 값 변경 가능.
print(temp) 
temp[1] = 'k'
t = tuple(temp)
print(t, type(t))
# ('a', 'k', 'c', 'd', 'a') <class 'tuple'>

swap

t1 = (10,)
t1 = (10,20)
a, b = t1
b, a = a, b
t2 = a, b
print(t2)
# (20, 10)

 - Set 타입 : 순서X, 변경 X, 중복X, {요소1, 요소2, ...}

a.union(b) : 합집합( | )

a.intersection(b) : 교집합( & )

a.update({6, 7}) : a에 합집합하여 a에 반영

a.discard(b) : a에서 b 제거(없어도 정상진행)
a.remove(b) : a에서 b 제거(a에서 b 없으면 error)

a.clear() : a 집합 비움

a = {1, 2, 3, 1}
print(a, type(a), len(a))
#print(a[0]) # TypeError: 'set' object is not subscriptable
b = {3, 4}
print(a.union(b), a.intersection(b)) # {1, 2, 3, 4} {3}
print(a | b, a & b, a - b)           # {1, 2, 3, 4} {3} {1, 2}

b.update({6, 7})
# {3, 4, 6, 7}
b.update([8, 9])
# {3, 4, 6, 7, 8, 9}

b.discard(b)
b.remove(7) # 없으면 Error

b.clear() # set()

중복제거

set(a) : set타입으로 변경

li =[1,2,3,3,4,5,5,5,3,2,1]
print(li)
temp = set(li)
li = list(temp) # [1, 2, 3, 4, 5]

 

 - Dict 타입 : 순서X, {key1 : value1, key2 : value2, ... }

dic['key'] = 'value'

del dic['key']

dic.keys()

dic.get('key)

mydic = dict(k1=1, k2='kbs', k3=1.23)
print(mydic, type(mydic)) # {'k1': 1, 'k2': 'kbs', 'k3': 1.23} <class 'dict'>

dic = {'파이썬':'뱀', '자바':'커피', '스프링':'봄'}
print(dic, type(dic)) # {'k1': 1, 'k2': 'kbs', 'k3': 1.23} <class 'dict'>
print(dic['자바']) # 키로 값을 참조
print(dic['커피']) # 값으로 참조 불가

dic['겨울'] = '눈' # 값 추가
# {'파이썬': '뱀', '자바': '커피', '스프링': '봄', '겨울': '눈'}

del dic['겨울'] # 값 제거
# {'파이썬': '뱀', '자바': '커피', '스프링': '봄'}

dic.clear()
# {}
dic = {'파이썬':'뱀', '자바':'커피', '스프링':'봄'}
print(dic.keys())     # dict_keys(['파이썬', '자바', '스프링'])
print(dic['자바'])     # 커피
print(dic.get('자바')) # 커피

4. 정규 표현식

: 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어

* test4

import re
from re import IGNORECASE

ss = '1234 abc가나다ABC_555_6_789_555kbs가나 다라 가나 정규 표현식 특정한 규칙'
print(ss)
print(re.findall(r'123', ss))      # ['123']
print(re.findall(r'가나', ss))      # ['가나', '가나', '가나']
print(re.findall(r'[0,1,3]', ss))  # ['1', '3']
print(re.findall(r'[0,1,5]', ss))  # ['1', '5', '5', '5', '5', '5', '5']
print(re.findall(r'[0-9]', ss))    # ['1', '2', '3', '4', '5', '5', '5', '6', '7', '8', '9', '5', '5', '5']
print(re.findall(r'[0-9]+', ss))   # ['1234', '555', '6', '789', '555']
print(re.findall(r'[0-9]?', ss))   # ['1', '2', '3', '4', '', '', '', '', '', '', '', '', '', '', '', '5', '5', '5', '', '6', '', '7', '8', '9', '', '5', '5', '5', '', '', '', '', '', '', '', '', '', '', '', '']
print(re.findall(r'[a-z, A-Z]+', ss)) # [' abc', 'ABC', 'kbs', ' ', ' ', ' ', ' ']
print(re.findall(r'[가-힣]+', ss)) # ['가나다', '가나', '다라', '가나', '정규', '표현식']
print(re.findall(r'[가-힣]{2}', ss)) # ['가나', '가나', '다라', '가나', '정규', '표현']
print(re.findall(r'[가-힣]{2,3}', ss)) # ['가나다', '가나', '다라', '가나', '정규', '표현식', '특정한', '규칙']

print(re.findall(r'[^0-9]+', ss))
print(re.findall(r'^1', ss)) # 첫글자가 1
print(re.findall(r'^2', ss))
print(re.findall(r'칙$', ss)) # 마지막 글자가 칙

print(re.findall(r'\d', ss)) # 숫자
print(re.findall(r'\d{2}', ss))
print(re.findall(r'\d{2,3}', ss))

5. 조건 판단문 if문

* test5_if

 - if

var = 4
if var >=3:
    print('큼')

 

 - if else

if var >=3:
    print('큼')
else:
    print('거짓')

 

 - 다중 if

money = 1000
age = 22
if money >= 500:
    item = '사과'
    if age <= 30:
        msg = 'yong'
    else:
        msg = 'old'
else:
    item = '한라봉'
    if age <= 20:
        msg = 'YB 한라봉'
    else:
        msg = 'OB 한라봉'
print(item, msg)

 

 - elif

score = 85
if score >= 90:
    print('우수')
else:
    if score >= 70:
        print('일반')
    else:
        print('노력')
if score >= 90:
    print('우수')
elif score >= 70:
    print('일반')
else:
    print('노력')

 

 - input

score = int(input('점수입력:'))

if 90 <= score <= 100:
    print('우수')
elif 70 <= score <90:
    print('일반')
else:
    print('노력')

 

- if in

if a in str:
   str에 a가 있을경우 실행

name = ['홍길동', '김길동', '이길동']
if '홍길동2' in name:
    print('freind')
else:
    print('dont know')

 

 - 한줄 if else

(참일때 출력문) if (조건) else (거짓일때 출력문)

a = 'kbs'
b = 9 if a == 'kbs' else 11
print(b)

a = 11
b = 'mbc' if a == 9 else 'kbs'
print(b)

(참일때 출력문, 거짓일때 출력문) [조건]

a = 3
result = 0
if a > 5:
    result = a * 2
else :
    result = a + 2
print(result) # 5


result = a * 2 if a > 5 else a + 2
print(result) # 5


print((a + 2, a* 2)[a > 5]) # 5

 

print(int(True), int(False)) # 1 0

6. 반복문 while

* test5_while

a = 1

while a <= 5:
    print(a, end = ' ')
    a += 1
# 1 2 3 4 5 

print('\na: ', a) # a:  6

 

i = 1
while i <= 3:
    j = 1
    while j <= 4:
        print('i:'+str(i)+'/j:'+ str(j))
        
        j = j + 1
    print('-----')
    i += 1
# i:1/j:1
# i:1/j:2
# i:1/j:3
# i:1/j:4
# -----
# i:2/j:1
# i:2/j:2
# i:2/j:3
# i:2/j:4
# -----
# i:3/j:1
# i:3/j:2
# i:3/j:3
# i:3/j:4

 

 - 1 ~100 사이의 3의 배수의 합

i = 1; sum = 0;
while i <= 100:
    if i % 3 == 0:
        sum += i
    i += 1
print('합은 '+str(sum)) # 합은 1683

str1.pop() : str1에서 가장 마지막 값 방출

colors = ['r', 'g', 'b']
print(colors)
print(colors[1])
a = 0
while a < len(colors):
    print(colors[a], end = ' ') # r g b
    a += 1
    
while colors:
    print(colors.pop(), end = ' ') # b g r. LIFO

 

- 별찍기

i = 0
while i <= 10:
    j = 1
    re = ' '
    while j <= i:
        re = re + '*'
        j = j + 1
    print(re)
    i = i + 1
#  *
#  **
#  ***
#  ****
#  *****
#  ******
#  *******
#  ********
#  *********
#  **********
i = 0
while i <= 10:
    j = 1
    re = ' '
    while j <= i:
        re = re + ' '
        j = j + 1
    k = 1
    while k <= 11 - j:
        re = re + '*'
        k = k + 1
    print(re)
    i = i + 1
#  **********
#   *********
#    ********
#     *******
#      ******
#       *****
#        ****
#         ***
#          **
#           *

 

 - if 블럭 내에 while 블럭 사용

import time

time.sleep(1) : sleep

import time
sw = input('폭탄 스위치를 누를까요?[y/n]')
if sw == 'Y' or sw == 'y':
    count = 5
    while 1 <= count:
        print('%d 초 남음'%count)
        time.sleep(1)
        count -= 1
    print('boom!')
elif sw == 'N' or sw == 'n':
    print('작업취소')
else:
    print('y 또는  n을 누르시오')

 

* test5_while2

 - continue, break

a = 0

while a < 10:
    a += 1
    if a == 5:continue
    if a == 7:break
    print(a, end=' ')
else: # phython만 존재
    print('while 정상 수행') # while문 정상 완료 후 1회 수행. break 실행시 출력되지않음
# 1 2 3 4 6 
print('while 수행 후 %d'%a) # while 수행 후 7

 

 - 홀수, 짝수 확인

while True:
    a = int(input('숫자입력:'))
    if a == 0:
        print('while문을 빠져나갑니다.')
        break
    elif a % 2 == 0: # 짝수
        print('%d는 짝수'%a)
    elif a % 2 == 1: # 홀수
        print('%d는 홀수'%a)

7. 반복문 for

* test6_for

for i in [1, 2, 3, 4, 5]: # list : 
    print(i, end = ' ')
# 1 2 3 4 5
print()

for i in (1, 2, 3, 4, 5): # tuple
    print(i, end = ' ')
# 1 2 3 4 5
print()

for i in {1, 2, 3, 4, 5, 5, 5}: # set
    print(i, end = ' ')
# 1 2 3 4 5

 

str.items() : tuple로 key, value 리턴

sort = {'java':'웹용', 'python':'만능언어','java script':'컨텐츠 제작용'}
for i in sort.items(): # str.items() : tuple로 리턴
    print(i)
    print(i[0] + '- '+i[1])
# ('java', '웹용')
# java- 웹용
# ...
for k, v in sort.items():
    print(k)
    print(v)
# java
# 웹용
# python
# 만능언어
# java script
# 컨텐츠 제작용

 

 - str.values() : value값 리턴

for k in sort.values():
    print(k, end = ' ')
# 웹용 만능언어 컨텐츠 제작용

 

 - 2, 3단 출력

for n in [2 ,3]:
    print('--{}단--'.format(n))
    for su in [1,2,3,4,5,6,7,8,9]:
        print('{0} * {1} = {2}'.format(n, su, n*su), end = '\t')
    print()    

 

enumerate(a) : index와 요소값 리턴

li = ['a', 'b', 'c']
li = ('a', 'b', 'c')
li = {'a', 'b', 'c'} # 순서 없음. 무작위
for ind, data in enumerate(li):
    print(ind, data)
# 0 a
# 1 b
# 2 c

 - continue, break

datas = [1,2,3,4,5]
for i in datas:
    if i == 3:
        continue
    if i == 5:
        break
    print(i, end = ' ')
else:
    print('정상 처리') # break 실행시 출력되지않음 

 

 - for문 내부에 if문 사용

score = [95,70,60,50,100]
num = 0

for j in score:
    num += 1
    if j < 70: continue
    print('%d번째  점수는 합격'%num)
# 1번째  점수는 합격
# 2번째  점수는 합격
# 5번째  점수는 합격

 

 - 이중 for문

li1 = [3,4,5]
li2 = [0.5,1,2]
for a in li1:
    for b in li2:
        print(a + b, end = ' ') # 3.5 4 5 4.5 5 6 5.5 6 7

 

[실행문 for 변수1 in list1 for 변수2 in list2]  : list1의 첫번째 요소와 list2의 첫번째 요소 실행문 실행 -> list1의 두번째 요소와 list2의 첫번째 요소 실행문 실행 -> ...

print([a + b for a in li1 for b in li2])
datas = [a + b for a in li1 for b in li2]
for d in datas:
    print(d, end = ' ') # 3.5 4 5 4.5 5 6 5.5 6 7 

 

 - 정규 표현식

re.sub(r"[^가-힣\s]", "", ss) : ss에서 패턴과 일치는 값을 ""로 대체

import re
ss = '''
이재명 경기도지사는 8일 일각에서 제기되는 탈당설에 대해 “민주당 지지자들이 압도적으로 응원하는데 왜 나가느냐”고 강력 부인했다.
이 지사는 이날 OBS 방송에 출연해 ‘일부에서 탈당설이 제기되고 있다’는 질문에 “2005년부터 16년간 민주당 당원인데 왜 탈당하느냐”면서 이같이 반문했다.
이 지사는 이날 OBS 방송에 출연해 ‘일부에서 탈당설이 제기되고 있다’는 질문에 “2005년부터 16년간 민주당 당원인데 왜 탈당하느냐”면서 이같이 반문했다.
이 지사는 이날 OBS 방송에 출연해 ‘일부에서 탈당설이 제기되고 있다’는 질문에 “2005년부터 16년간 민주당 당원인데 왜 탈당하느냐”면서 이같이 반문했다.
아울러 이 지사는 ‘정세균 총리 이외에도 당내 제3후보론이 나오는데 섭섭하지 않으냐’는 질문에는 “저는 안 섭섭하다. 섭섭할 사람은 (대선주자 선호도) 2등 하시는 분일 것”이라며
이 지사는 이날 OBS 방송에 출연해 ‘일부에서 탈당설이 제기되고 있다’는 질문에 “2005년부터 16년간 민주당 당원인데 왜 탈당하느냐”면서 이같이 반문했다.
이 지사는 이날 OBS 방송에 출연해 ‘일부에서 탈당설이 제기되고 있다’는 질문에 “2005년부터 16년간 민주당 당원인데 왜 탈당하느냐”면서 이같이 반문했다. 
“저는 누군가는 상대해야 하는데, 저보다는 대체 당할 수 있는 분이 억울할 것”이라고 했다.
'''
ss2 = re.sub(r"[^가-힣\s]", "", ss) # 한글만 parsing
print(ss2)
ss3 = ss2.split(' ') # 공백 기준 단어를 나눔 
print(ss3)
cnt = {} # 단어의 발생횟수를 dict로 저장
for n in ss3:
    if n in cnt: # count있을 경우 ++
        cnt[n] += 1
    else:# 없을 경우 1
        cnt[n] = 1
print(cnt)
# {'\n이재명': 1, '경기도지사는': 1, '일': 1, '일각에서': 1, '제기되는': 1, '탈당설에': 1, '대해': 1, '민주당': 6, '지지자들이': 1, '압도적으로': 1, '응원하는데': 1, '왜': 6, '나가느냐고': 1, '강력': 1, '부인했다\n이': 1, '지사는': 6, '이날': 5, '': 5, '방송에': 5, '출연해': 5, '일부에서': 5, '탈당설이': 5, '제기되고': 5, '있다는': 5, '질문에': 5, '년부터': 5, '년간': 5, '당원인데': 5, '탈당하느냐면서': 5, '이같이': 5, '반문했다\n이': 3, '반문했다\n아울러': 1, '이': 1, '정세균': 1, '총리': 1, '이외에도': 1, '당내': 1, '제후보론이': 1, '나오는데': 1, '섭섭하지': 1, '않으냐는': 1, '질문에는': 1, '저는': 1, '안': 1, '섭섭하다': 1, '섭섭할': 1, '사람은': 1, '대선주자': 1, '선호도': 1, '등': 1, '하시는': 1, '분일': 1, '것이라며\n이': 1, '반문했다': 1, '\n저는': 1, '누군가는': 1, '상대해야': 1, '하는데': 1, '저보다는': 1, '대체': 1, '당할': 1, '수': 1, '있는': 1, '분이': 1, '억울할': 1, '것이라고': 1, '했다\n': 1}

re.match(r'^\d{3}-\d{4}$', str1) : str1에서 패턴과 일치하면 true

for ss in ['111-1234', '일이삼-사오육칠', '123-1234']:
    if re.match(r'^\d{3}-\d{4}$', ss):
        print(ss, '전화번호 일치')
    else:
        print(ss, '전화번호 불일치')

 

str1 = sorted(str2) : 정렬값 리턴

str1.sort() : 정렬하여 str1에 반영

from time import localtime
print(localtime())
# time.struct_time(tm_year=2021, tm_mon=2, tm_mday=9, tm_hour=11, tm_min=12, tm_sec=1, tm_wday=1, tm_yday=40, tm_isdst=0)
act = {6:'잠', 9:'준비', 18:'공부', 24:'휴식'}
print(act)
hour = localtime().tm_hour

for act_time in sorted(act.keys()):
    if hour < act_time:
        print(act[act_time])
        break
    #else:
        #print('알수없음')

 

 - 과일값 계산하기

price = {'사과':3000, '감':500, '한라봉':1000}
guest = {'사과':2, '감':3}
bill = sum(price[f]* guest[f] for f in guest)
print('손님이 구매한 과일의 총액은 {}원'.format(bill)) # 손님이 구매한 과일의 총액은 7500원
datas = [1, 2, 'kbs', True, 3]
li = [i * i for i in datas if type(i) == int]
print(li) # [1, 4, 9]
datas = {1,1,2,2,3}
se = {i * i for i in datas}
print(se) # {1, 4, 9}

 

 - key-value swap

id_name = {1:'tom', 2:'jonh'}
name_id = {val:key for key, val in id_name.items()}
print(name_id) # {'tom': 1, 'jonh': 2}

 

aa = [(1,2), (3,4), (5,6)]
for a, b in aa:
    print(a + b, end = ' ') # 3 7 11

 

temp = [1,2,3]
temp2 = [i + 10 for i in temp]
print(temp2) # [11, 12, 13]

 

-  range() : 수열 생성

print(list(range(1,6)))    # [1, 2, 3, 4, 5]
print(set(range(1,6)))     # {1, 2, 3, 4, 5}
print(tuple(range(1,6)))   # (1, 2, 3, 4, 5)
print(list(range(1,11,3))) # [1, 4, 7, 10]
print(list(range(-10,-200,-30))) # [-10, -40, -70, -100, -130, -160, -190]
for i in range(6):
    print(i, end = ' ') # 0 1 2 3 4 5 
print()
tot = 0
for i in range(1, 50, 2):
    print(i, end = ' ') # 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49
    tot += i 
print()
print('결과는 ' + str(tot))
print('결과는 ' + str(sum(range(1, 50, 2))))

 

 - 구구단 2~5단

for i in range(2, 5):
    for j in range(1, 9):
        print('{0} * {1} = {2}'.format(i,j,i*j), end = '\t')
    print()

 

 - 1 ~ 100 사이의 숫자 중 3의 배수이면서 5의 배수인 수들의 합 출력

tot = 0
for i in range(1, 101):
    #print(i, end = ' ')
    if i % 3 == 0 and i % 5 == 0:
        tot = tot + i
print('합은', tot) # 합은 315

 

 - N - gram : 문자열에서 n개의 연속된 요소를 추출하는 방법
 - 글자별 n-gram : 2- gram

ss = 'hello'

for i in range(len(ss) -1):
    print(ss[i], ss[i+ 1], sep = ' ')
# h e
# e l
# l l
# l o

 

 - 단어별 n-gram : 2- gram

ss2 = 'this is python script'
words = ss2.split()

for i in range(len(words) -1):
    print(words[i], words[i+ 1], sep = ' ')
# this is
# is python
# python script

 

1. 파이썬 종료

1) ctrl+d
2) ctrl+Z Enter
3) 

import sys
sys.exit()


2. 사칙연산

1) + - * /
   2.7 버전 이하는 실수 자동형변환 하지않음
   a/(b*1.0)
   
2) 제곱 : x**y => x의 y제곱
3) 나머지 : %
4) 몫 : //

 

3. 변수
: 타입지정 없어도 가능.
: ';' 없음

 

print(변수) : 변수 출력

 

 

4. 조건문 if

if 조건문:
    실행문

 

5. 반복문 for

for a in [1,2,3]:
    a관련 실행문

 

6. 함수

def 함수명(매개변수1, ..):
실행문
    return 반환값

 

7. 주석
1) 한줄 주석 : #
2) 여러줄 주석: """,  '''
            """,  '''

 

8. 확장자
.py

 

9. 도스창 실행

	cd 경로 설정
	python 파일명.py

 

10. 숫자형
1) 정수
2) 실수
4.1E9
4.1E-9
4.1e-9
3) 8진수
0o
0O
4) 16진수
0x
0X
5) 복소수
a = 2+3j
2+3J

 

* real : 실수부 리턴 
ex) a.real

* image : 허수부 리턴
ex) a.image

* conjugate() : 켤레 복소수 리턴
ex) a.conjugate()

* abc(복소수) : 복소수 절대값 리턴
ex) abs(a) -> 루트(실수부 제곱 + 허수부 제곱)

 

11. 문자열 : "", '', """ """, ''' ''',
1) 큰따옴표 출력 : '"', \"
2) 작은 따옴표 출력 : "'", \'
3) 줄바꾸기 : \n
4) 여러줄 문자열 출력
'''
''',
"""
""",
5) 문자열 더하기 
문자열1+문자열2 =>문자열1문자열2

6) 문자열 곱하기
문자열*2 => 문자열문자열

7) 문자열 인덱싱

a="문자열"
a[index] : index번째 문자 추출. 0부터 시작
a[0] : 첫번째 문자
a[-1] : 마지막 문자



8) 문자열 슬라이싱

a="문자열"
a[index1:index2] : index1번째 문자부터 index2-1까지 문자열 추출.
a[0:4] : 0~3까지 문자열
a[index1:] : 끝문자까지
a[:index2] : 첫문자부터
a[:] : 전체문자
a[1] = 2 : error. 문자열을 바꿀수 없다.



9) formating
1)
"문자열%d" %숫자 =>"문자열숫자"
"문자열1%s" %"문자열2" =>"문자열1문자열2"
%d %s %c %f %o %x %%

"%2s" %a => " a"
"%-2s" %a => "a "

"%6.2f" %1.122 => "  1.12"

2)

"{0}{1}".format(a,b) => "ab"
"{0}{a}".format(c,a=1) => "c1"
"{0:<3}".format(a) => "a  " 왼쪽 정렬 및 공백추가
"{0:>3}".format(a) => "  a" 오른쪽 정렬 및 공백추가
"{0:^3}".format(a) => " a " 가운데 정렬 및 공백추가
"{0:=^3".format(a) => "=a=" 공백 =로 채우기
"{0:!^3".format(a) => "=a=" 공백 !로 채우기
"{0:6.2f}.format(1.23) => "  1.23" 
"{{}}".format() => "{}"

 

 

10) 함수

a.count('b') # 문자열 a에서 'b' 문자 개수 리턴

a.find('b') => a문자열에서 처음 나온 'b'문자 위치 리턴. 0부터 시작. 없으면 -1 리턴

a.index('b') => a문자열에서 처음 나온 'b'문자 위치 리턴. 0부터 시작. 없으면 error

a.join('abcd') => a=.이면 'abcd'문자 사이에 . 포함하여 리턴. 'a.b.c.d'

a.upper() => a문자열 대문자로 변경하여 리턴.

a.lower() => a문자열 소문자로 변경하여 리턴.

a.lstrip() => a문자열에서 왼쪽 공백 제거하여 리턴.

a.rstrip() => a문자열에서 오른쪽 공백 제거하여 리턴.

a.strip() => a문자열에서 양쪽 공백 제거하여 리턴.

a.replace(바뀌게 될 문자열b, 바꿀 문자열c) => a문자열에 존재하는 b문자열을 c문자열로 변경하여 리턴.

a.split() => a문자열에 공백 기준으로 문자를 나눠 리스트로 반환. a="a b c" => a.split() => ['a','b','c']

a.split('기준문자') => a문자열에 '기준문자'를 기준으로 문자를 나눠 리스트로 반환. a="a;b;c" => a.split(';') => ['a','b','c']

 

 

12. 리스트(=배열)
1) a=[1,2,[3,4]]

2) a[index] : 인덱싱
a[0] => 1
a[-1] => [3,4]
a[-1][0] => [3]

3) 슬라이싱
a[2:5]
a[2][:3]
4) 연산
a=[1,2]
b=[3,4]
a+b=[1,2,3,4]
a*2=[1,2,1,2]
a[1]+"1" => Type error
str(a[1]) + "1"=> "21"

* str(a) => 정수 or 실수인 a를 형변환 하여 문자열로 변경한다.["1","2"]

5) 값 변경
a=[1,2,3]
a[1]=4 => a=[1,4,3]

a=[1,2,3]
a[1:2]=[4,5,6] => a=[1,4,5,6,3]

a=[1,2,3]
a[1]=[4,5,6] => a=[1,[4,5,6],3]

6) 값 삭제
a[1:2] = []

del a[1]

* del 객체 : 객체 삭제

7) 함수

a.append(b) : a의 마지막에 b 추가. a에 변경 값을 넣는다.
a=[1,2,3]
a.append(4) => a=[1,2,3,4]
a=[1,2,3]
a.append([4,5]) => a=[1,2,3,[4,5]]

a.sort() => a를 오름 차순 정렬하여 a에 변경 값을 넣는다.

a = sorted(a, reverse=True)

a.reverse() => a의 순서를 반대로 뒤집어 a에 변경 값을 넣는다.

a.index(3) => a의 3의 위치를 리턴. 0부터 시작. 값이 없으면 error 발생.

a.insert(b,c) => a의 b번째 위치에 c를 삽입하여 리턴.

a.remove(b) => a에서 첫번째 나오는 b 삭제하여 리턴.

a.pop() => a의 마지막 요소 리턴. 마지막 요소 삭제하여 그 값을 a에 넣는다.

a.pop(b) => a의 b위치의 값 리턴. b위치 값 삭제하여 그 값을 a에 넣는다.

a.count(b) => a에서 b 개수 리턴.

a.expend(리스트) => a에 리스트를 더한다.

 

13. 튜플 : 값 수정 불가. 시도시 error.
1) ()
   (1,)
   (1,2)
   1,2,3
   (1,2,(3,4))

2) 인덱싱, 슬라이싱, 더하기, 곱하기

 

14. 딕셔너리( = map) : 순서 없음
                  : 중복 시 하나를 제외한 나머지 무시. 어떤것이 될지 알수없음.
  : key에 리스트 사용불가.
1) {'key':'value','key2':'value2'}
a={1:a,2:b}
a[3]=c => {1:a, 2:b, 3:c}

del a[3]

a[3] => c

a.key() => dict_keys([key1,key2]) => a에서 key만 추출하여 dict_keys객체 리턴.

a.value() => dict_values([key1,key2]) => a에서 key만 추출하여 dict_values객체 리턴.

list(dict_keys()) => 리스트로 변환

a.items() => dict_items([(key1:value2),(key2:value2)]) => a에서 key만 추출하여 dict_items객체 리턴.

a.clear()

a.get(key) => 없으면 none 리턴.

a.get(key,default) => 없으면 none 리턴.

key in a => 딕셔너리 안에 key값이 있는 지확인. true, false 리턴.

 

 

15. 집합(set) : 중복 허용 X, 순서 X, 인덱싱X
* set() : 집합 생성
set(list) => {1,2,3}
set("문자열") => {'문','자','열'}
* tuple() : 튜플로 변환.

1) 교집합 : s1&s2

s1.intersection(s2) : 교집합



2) 합집합 : s1|s2

* s1.union(s2) : 합집합

 

3) 차집합 : s1-s2

s1.difference(s2) : s1-s2

s1.add(4) : s1집합에 4를 추가.

s1.update([4,5,6]) : s1집합에 여러 값 추가.

s1.remove(4) : s1집합에 4 제거.

 

16. 객체 : 모든것
변수 : 메모리 위치, 레퍼런스

type(a) : 타입 반환
	
a is b : 동일한 객체인지 확인

 

17. 레퍼런스 카운트

import sys
sys.getrefcount(3)
a,b = ('c', 'd')
(a,b) = 'c', 'd'
[a,b] = ['c', 'd']
a,b = b,a
레퍼런스 카운트가 0이 되면 가비지 컬렉터가 객체 제거
b = a[:] # 다른객체
b = copy(a)
b is a # False

 

18. if

if 조건문:
elseif 실행문:
else:

연산자

x or y
x and y
not x
x in s
x not in s
pass

19. while

while 조건문:
	실행문
input()
raw_input()
#-*-coding:utf-8-*-
break
continue

20. for

for 변수 in 리스트:
range(10) : 0 ~ 9
range(1, 10) : 1~10
len(a)
result = [num * 3 for num in a if num%2 ==0]

21. 함수

def sum(a, b):
	return a+b
	return a,b # (a,b)

def sum(a, b = 1) # 맨마지막 자리만 가능

global a = 0

a = input("~")
print(,) # 띄어쓰기
print(i, end = ' ')

f = open("name.txt",'w') # 'r', 'a'
f.close

line = f.readline()   # 첫줄 출력
lines = f.readlines() # 리스트 리턴
data = f.read()       # 전체 내용
with open("a.txt", "w") as f:
f.write("")

 

22. 클래스

class Service:
	def sum(self, a, b):
		self.a = a
	def __init__(self, name):
		self.name = name
# 인스턴스 생성 시 실행
pey = Service('0')
매서드 오버라이딩 : 이름은 같으나 인자 타입이나 개수가 다른 함수를 생성
상속 : class 자식(부모):
연산자 오버로딩 : def __add__(self, other):
				__sub__
				__mul__
				__truediv__

 

23. 모듈

import mod1
mod1.sum(1,2)
from mod1 import sum, div
sum(1,2)

from mod1 import*
if __name__ == "__main__" # import시 실행안됨

python mod1.py # 직접 실행시 실행됨

set PYTHONPATH = C:\Python\aa

 

24. 패키지

__init__.py : 해당 디렉터리가 패키지 일부임 알려줌
__all__ : __all__ = ['파일명']
from  .. graphic.render import render_test

 

25. 예외처리

FileNotFoundError, ZeroDivisionError, IndexError

try:
	except FileNotFoundError as e:
	except FileNotFoundError, e:
finally:
	f.close
else:

raise error명

 

26. 내장함수

abs(x) : x의 절대값
all(x) : 반복가능 x에 bool 리턴. 모두 참 T
any(x) : 반복가능 x에 bool 리턴. 모두 거짓 F
chr(i) : 아스키코드 -> 문자열
dir(x) : 변수, 함수 출력(내장)
divmode(a, b) : a/b = (몫, 나머지)
enumerate(x) : index 및 value 반환
eval('') : 실행. 동적실행을 원할 경우
filter(함수, x) : x -> 함수 실행 후 참값 모음
hex(x) : 정수 -> 16진수
id(객체) : 주소값 리턴
input()
int(x) : 문자열(실수) -> 정수
int(x, 진수)
isinstance(객체, 클래스) : 객체가 클래스의 객체 인지 확인
lambda 인수1...:인수를 이용한 식
# def와 유사. 한줄함수
list = [lambda, lambda]
list[0](1,2)
len(x) : 길이
list(x) : 리스트
map(함수, 반복가능) : 함수 실행결과 모음
max(반복가능) : 최대값
min(반복가능) : 최소값
oct(x) : 정수 -> 8진수
open('파일이름', 읽기방법) : w, r, a, b, default = r
ord(x) : 문자 -> 아스키코드
pow(x,y) : 제곱
range(m,n) : 인자 1 0에서 시작, 인자 3 간격 명시
sorted(반복) : 정렬 후 리스트 리턴
a.sort() : 정렬
str(객체) : 문자열로 변경
tuple(반복) : 튜플로 변경
type(객체) : 자료형
zip(반복) : n번째 인자끼리

27. 외장함수

import sys
sys.argv
cmd -> python 파일명 argument
sys.exit()
sys.path
import pickle
pickle.dump(data, f)
data = pickle.load(f)
import os
os.environ
os.chdir("경로") : 디렉토리 변경
os.getcwd() : 현재 디렉토리
os.system("명령어") : 시스템 명령어 실행
os.popen("명령어") : 읽기모드로 파일객체 리턴
os.mkdir(디렉토리) : 디렉 생성
os.rmdir(디렉토리) : 디렉 삭제
os.unlink(파일이름) : 파일삭제
os.rename(src, dst) : 파일명 src -> dst로 변경
import shutil
shutil.copy("src 파일명", "dst 파일명") : 파일복사
import glob
glob.glob("경로/q*) : q이름 리스트 출력
import temp file
filename = tempfile.mktemp() : 임시파일이름 생성
f = tempfile.TemporaryFile() : 임시 공간 파일객체 리턴
import time : 1970.1.1 ~
time.time() : 지난 시간
time.localtime(time.time()) : 로컬시간
time.asctime() : 알기쉽게
time.ctime() : time.asctime(time.localtime(time.time()))
time.strftime('', time.localtime(time.time())
time.sleep(초)
import calender
calender.calender(연도)
calender.prcal(연도)
calender.prmonth(연도, 월)
calender.weekday(연도, 월, 일) : 요일, 월 = 0
calender.monthrange(연도, 월) : 1일의 요일, 마지막 일
import random
random.random() : 0 ~ 1 사이 난수
random.randint(1, 10) : 1 ~ 10 사이 정수 난수
random.choise(data) : 리스트 무작위
random.shuttle(data) : 섞기
import webbrowser
webbrowser.open('사이트 주소')
webbrowser.open_new('사이트 주소') : 새창
import threading
t = threading.Thread(targer = 함수명, args = 입력변수(리스트))
t.deamon = True : 메인 종료시 스레드도 종료
t.start() : 스레드 실행
class MyThread(threading.Thread):
	def __init__(self,msg):
		threading.Thread.__init__(self)
	
	def run(self):
os.listdir('경로') : 경로 포함 리스트
os.path.join('경로', '파일명') : 경로 + 파일명
os.path.splitext('파일명') : 확장자와 파일명 분리
os.path.isdir('파일명') : 디렉토리인지 파일인지 구분
os.walk("c:/) : (경로, 디렉, 파일) 검색
import re
p = re.compile('ab*')

28. 정규식

[abc]
\d
\D
\s
\S
\w
\W
a.b
a[.]b
a*b
a+b
a{m,n}
a?
m = p.match("") : none or m
m = p.search("") : 아닌게 있어도
result = p.findall("") : List 리턴
result = p.finditer("") : 반복가능 객체
m.group() : 문자열
m.start() : 시작위치
m.end() : 끝위치
m.span() : 시작 끝, 튜플
m = re.match('형식', "문자열")
re.DOTALL		S	\n
re.IGNORECASE 	I	각 라인 ^p, p$, space 가능, 주석 가능
re.MUKTILINE	M
re.VERBOSE		X
p = re.complie('형식', re.option)
^p : 처음 p
p$ : 마지막 p
\\ : \
\\\\ : \\
r'\\' : \\
소모가 없는 메타문자
|	or
^	처음
$	끝
\A	^
\z	$
\b	구분자(space) 있어야함
\B	구분자(space) 없어야함
[^]	\^
re.M 적용X

29. Group : 문자열이 계속 반복되는 지 조사

(ABC)+	(\w+)	(\d+)
group(0) : 전체
group(n) : n번째
\1 : 동일단어 연속
\2 : 두번째 그룹
(?P<name>  ) (?p=name)
(?=...)
(?!...)
p = re.compile('a')
p.sub('b', 'c' count=n) : c에서 a를 b로 변경
p.subn(    )
      ('결과', n번 바꿈)
     \g<그룹명> 정규식 그룹명 참조
	 \g<|>
	 Greedy

30. Element Tree

from xml.etree.ElementTree import parse, ElementTree, SubElement, Element, dump
Tag = Element("Tag") => <Tag></Tag>
Tag.text = "내용1"
SubElement(Tag, "subTag").text = "내용2"
<Tag>내용1
	<subTag>내용2</subTag>
</Tag>
Tag.insert(1, sub2Tag)
Tag.remove(1, sub2Tag)
Tag.attrib["속성"] = "속성내용"
Tag.Element("Tag", 속성명 = "속성내용")
indent(Tag)
ElementTree(Tag).write("파일명")
tree = parse("파일명")
note = tree.getroot()
note.get("검색어", "default")
note.keys()
note.item()
note.find("subTag") : 첫번째 태그
note.findall("subTag") : 모든 태그
note.findtext("subTag") : 모든 태그의 Text
note.getiterator()
note.getchildren()
# 알고리즘 수행시간 측정 (보통 1초 128MB)
import time
start_time=time.time()
end_time=time.time()
print("수행시간: ",end_time-start_time)

#단축키
ctrl +/ => 주석

pypy3

* ord('문자') : 아스키코드값 리턴

* stack : pop(), append() 사용
* queue : queue = deque() / queue.popleft(), append()

* array[::-1] : 처음 부터 끝까지 역순으로 한칸씩
* array[A:B:C] : A부터 B까지 C 간격으로 

1. 그리디 greedy
2. 구현 implementation
3. 탐색
4. 정렬 sorting
	1) 선택 정렬
	
* swap
	array[i],array[j] = array[j],array[i]
	
	2) 삽입 정렬
* range(a,b,1)  : a ~ (b-1)까지 1간격
* range(a,b,-1) : a ~(b+1)까지 -1간격
	3) 퀵 정렬
	
* print(a,end=' ') :  a 끝에 ' '문자 출력

1. 이클립스에서 파이썬 설치

① 아나콘다 다운로드(파이썬 라이브러리)

www.anaconda.com/

 

Anaconda | The World's Most Popular Data Science Platform

Anaconda is the birthplace of Python data science. We are a movement of data scientists, data-driven enterprises, and open source communities.

www.anaconda.com

product - individual Edition

 

Python 3.8 : 64-Bit Graphical Installer (457 MB) Download

 

Anaconda3-2020.11-Windows-x86_64.exe 관리자 권한으로 실행

 

C:\anaconda3 경로에 설치

 

Add Anaconda3 to my PATH environment variable Uncheck

 

 

② PyDev 설치

 

eclipse - help - eclipse market place - PyDev 검색 - install

 

general - workspace / Web - CSS/HTML/JSP에서 UTF-8로 변경

 

Window - Preferences - PyDev - Interpreters - Phython InterPreter - Browse for python/pypy.exe - C:\anaconda3\Phython.exe 선택 - apply

 

③ 가상환경 설치
시작 - anaconda - anaconda prompt 실행
conda create --name test python=3.7 anaconda 입력
가상환경 활성화 명령 : activate test
가상환경 비활성화 명령 : conda deactivate test

 

④ 주피터 실행 (웹상에 실행)
cd C:\work\psou
python aa.py

jupyter notebook
new - python3

 

⑤ colab

colab.research.google.com/notebooks/intro.ipynb

 

Google Colaboratory

 

colab.research.google.com

 

⑥ 프로젝트 시작

File - New - PyDev - 프로젝트명 입력, 3.8, Python 선택

14. Thread

    1) Thread 클래스

        1. 쓰레드 프로그래밍을 적용하고 싶은 클래스를 작성시 Thread라는 클래스를 상속하도록 작성.(extends Thread)
        2. 쓰레드가 실행될때 run메소드가 호출되므로 실제 쓰레드 구현하고 싶은 처리흐름을 run에 작성.
        => void run()을 오버라이딩
        3. run메소드를 직접 호출하지않고 Thread클래스이 내부에서 제공하는 start메소드를 호출하여 run을 실행.

        (t1.start())

        => start 메소드를 호출하면 JVM내부의 스케쥴러에 의해서 적절한 시점에 run이 호출.

        (정확한 호출시점 알 수 없음)

class ThreadClass extends Thread{
	public void run() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
//main
ThreadClass t1 = new ThreadClass("t1");
t1.start();

 

    2) Runnable : 이미 다른 상위클래스를 상속하는 클래스를 쓰레드 프로그래밍을 적용하기 위해서 Runnable타입으로

    클래스를 작성.

        1. Runnable 인터페이스를 상속.(implements Runnable)
        2. run 메소드를 오버라이딩해서 쓰레드 프로그래밍으로 처리하고 싶은 내용을 구현.
        3. Runnable 객체를 이용해서 Thread클래스를 생성.

        (Thread t1 = new Thread(new Runnable을 상속한 클래스명()))
        4. 생성한 Thread객체의 start를 호출
        => Thread클래스에 오버라이딩한 run이 있으면 run을 실행. 
        => target객체(Runnable타입의 객체)의 run을 실행.

class Parent{
}
class 클래스명 extends Parent implements Runnable{
	public void run() {
		
			System.out.print(i+"("+Thread.currentThread().getName()+")");
			// 현재 실행중인 쓰레드의 getName()을 호출
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
	}
}
// main
// 1. Runnable을 상속해서 작성한 객체를 생성
Runnable obj1 = new RunnableDemo01();
// 2. 생성한 Runnable 객체를 이용해서 Thread객체를 생성
Thread t1 = new Thread(obj1);
Thread t2 = new Thread(new RunnableDemo01());

//3. 생성한 Thread객체의 start를 호출
t1.start();
t2.start();

 

    3) priority : JVM의 스케쥴러에 의해서 실행시킬 쓰레드가 여러 개 있다면 우선순위가 높은 쓰레드 부터 먼저 실행.

    1부터 10까지 우선수위를 지정가능 (default : 5)

t1.setPriority(6); // 우선순위 set
t1.getPriority(); // 우선순위 get
Thread.MAX_PRIORITY; // 10 return
Thread.MIN_PRIORITY; // 1 return

 

    4) yeild : yield 우선권이 동일한 쓰레드에게 실행을 양보하여 start()부터 재시작.

Thread.yield();

 

    5) join : 연결된 쓰레드 종료 후 메인 쓰레드가 종료하도록 하는 메소드.

try {
	t5.join();
} catch (InterruptedException e) {
	e.printStackTrace();
}

 

    6) thread 종료
        1. 임의의 변수(flag 변수)를 선언해서 종료하는 방법
        - 변수값에 따라서 작업을 처리할 수 있도록 구현

class testClass extends Thread{
	private boolean state = true;// 현재 상태값을 저장할 수 있는 변수
	
	public void run() {
		while(state) {
			// 실행문
		}
	}
	
	//쓰레드의 상태를 조절할 수 있도록 변수를 변경하는 메소드
	public void stopThread() {
		state = false;
	}
}
public class StopThreadTest01{
	public static void main(String[] args) {
		testClass t1 = new testClass();
		t1.start();
		t1.stopThread();
	}
}

 

        2. 인터럽트를 발생시키고 현재상태를 확인한 후 작업

class StopThread02 extends Thread{
	public void run() {
		try { // interupt이 발생해도 sleep문의 예외처리에 걸리지 않도록 try로 묶어준다.
		while(false == Thread.currentThread().isInterrupted()) { 
		// 현재상태가 인터럽트 상태면 종료하도록 구현.
			// 실행문
			Thread.sleep(500);
		}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		finally {
		}
	}
}

StopThread02 t1 = new StopThread02();
t1.start();
System.out.println("쓰레드 이름 : "+t1.getName());
System.out.println("인터럽트 상태 : "+t1.isInterrupted());
try {
	Thread.sleep(3000);
} catch (InterruptedException e) {
	e.printStackTrace();
}
t1.interrupt();
System.out.println("쓰레드 이름 : "+t1.getName());
System.out.println("인터럽트 상태 : "+t1.isInterrupted());

 

    7) 동기화

        1. synchronized 지정자

public class Shared {
	public synchronized void method() {
	// 한 쓰레드가 method 사용이 끝나기 전까지 다른 쓰레드가 method를 사용하지 못하도록 lock
	}
}
public class threadClass extends Thread{ // Thread
	Shared sh;
	threadClass(Shared sh){
		this.sh = sh
	}
	public void run() {
		Shared.method();
	}
}
// main
//쓰레드에서 공유할 객체 생성
Shared sh = new Shared();

//공유객체를 사용하는 쓰레드 생성
threadClass t1 = new threadClass(sh);
threadClass t2 = new threadClass(sh);

//쓰레드
t1.start(); // 한 쓰레드가 synchronized된 메소드를 사용중이면 사용이 끝난 후 사용할 수 있다.
t2.start();

 

        2. synchronized 블록

//공유객체
public class SharedObj {
	Account acc1;
	Account acc2;
}

// 기능1의 쓰레드
public class Thread1 extends Thread{
	SharedObj obj;
	public AccountSumThread(SharedObj obj) {
		this.obj = obj;
	}
	public void run() {
		for(int i=1;i<=5;i++) {
			long total = obj.acc1.getBalance()+obj.acc2.getBalance();
		}
	}
}

//기능2의 쓰레드
public class Thread2 extends Thread{
	SharedObj obj;
	public AccountTransferThread(SharedObj obj) {
		this.obj = obj;
	}
	public void run() {
		for(int i=1;i<=20;i++) {
			synchronized (obj) { // 메소드 전체가 아니라 명령문 일부에 lock을 적용할때 사용하는 synchronized블럭
								// ()안에 공유객체 명시.
				obj.acc1.withdraw(1000000);
				obj.acc2.deposit(1000000);
				
			}
		}
	}
}
// main
// 공유객체 생성
SharedObj obj = new SharedObj();
obj.acc1 = new Account();
obj.acc2 = new Account();

//쓰레드 생성
Thread1 t1 = new Thread1(obj); 
Thread2 t2 = new Thread2(obj);// 기능 2의 쓰레드의 동기화 블록이 실행 중에는 다른 쓰레드를 실행할 수 없다.

//쓰레드 start
t1.start();
t2.start();

 

 

 

15. Network

    1) InetAddress클래스 : IP주소를 모델링한 클래스. 로컬, 호스트네임을 통해서 IP주소를 가져올 수 있는 기능제공.

try {
	//InetAddress ia = InetAddress.getByName("www.naver.com");
	InetAddress ia = InetAddress.getByName(args[0]);
	ia.getHostName(); // Name 리턴
	ia.getHostAddress(); // ip주소 리턴
	InetAddress.getLocalHost(); // 로컬 ip 리턴
	
	InetAddress[] iaArr = InetAddress.getAllByName(args[0]); // 연결된 모든 ip 리턴
	for(int i=0;i<iaArr.length;i++) {
		iaArr[i].getHostName();
		iaArr[i].getHostAddress();
	}
} catch (UnknownHostException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

    2) URL클래스 : 웹상의 주소를 나타내는 클래스고 이를 통해서 네트워크 연결도 가능.
    웹상의 리소스를 가져올 수 있다. 웹페이지, 이미지, 동영상..

try {
	URL url = new URL("https://www.naver.com/");
	url.toString();
	url.getHost();
	url.getPath();
	url.getPort(); // 프로토콜에 등록되어 있는 기본 port로 접속 할 경우 -1 return
					// http프로토콜의 기본포트는 80번
	url.getProtocol(); // https
	url.getFile();
	
	// URL에 접속해서 자원정보를 읽는 작업을 수행
	InputStream is = url.openStream();
	InputStreamReader isr = new InputStreamReader(is);
	BufferedReader br = new BufferedReader(isr); 
	
	while(true) {
		String data = br.readLine();
		if(data == null) {
			break;
		}
		System.out.println(data);
	}
}catch (MalformedURLException e) {
	e.printStackTrace();
}catch (IOException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

 

    3) URL 이미지 출력
    - BufferedInputStream : byte단위 입력
    - FileOutputStream : byte단위 파일 출력

BufferedInputStream bis =null;
FileOutputStream fos=null;

try {
	URL url = new URL("url 경로");
	bis = new BufferedInputStream(url.openStream());
	fos = new FileOutputStream("src/data/image.jpg");
	while(true) {
		int data = bis.read();
		if(-1 == data) {
			break;
		}
		fos.write(data);
	}
} catch (MalformedURLException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}
finally {
	try {
		if(bis != null)
			bis.close();
		if(fos != null)
			fos.close();
	} catch (IOException e) {
		e.printStackTrace();
	}
}

 

    4) Socket 통신 - Server

try {
	
	ServerSocket server = new ServerSocket(50000);
	// 클라이언트와 통신하기 위해서 ServerSocket을 생성
	while(true) {
		Socket client = server.accept();
		// 클라이언트가 접속할때까지 대기하다가 (Litsen) 클라이언트가 접속하면 클라이언트와 통신
        // 할 수 있도록 클라이언트의 정보를 Socket객체로 만들어서 리턴
		InetAddress clientIp = client.getInetAddress();
		System.out.println("접속한 클라이언트 => "+clientIp.getHostAddress());
	}
	
} catch (UnknownHostException e){
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}

 

    5) Socket 통신

try {
	//서버와 통신할 수 있는 소켓객체 생성
	//Socket 객체를 생성하면 서버에 접속한다.
	Socket serverInfo = new Socket("192.168.0.3",50000); // 서버 ip 및 port
} catch (IOException e) {
	e.printStackTrace();
}

 

    6) DataInputStream : 파일의 데이터를 읽는 클래스

DataInputStream dis = new DataInputStream(new FileInputStream("src/data/dos.txt"));
// IO작업 직접하는 것이 아니라 추가된 기능을 표현해 놓은 스트림 클래스로
// 직접 원시데이터와 연결하지 못한다.
int data1 = dis.readInt();
double data2 = dis.readDouble();
String data3 = dis.readUTF();
System.out.println(data1);
System.out.println(data2);
System.out.println(data3);
dis.close();

 

    7) DataOutputStream : 파일의 데이터를 쓰는 클래스

FileOutputStream fos = new FileOutputStream("src/data/dos.txt");
DataOutputStream dos = new DataOutputStream(fos);
// FileOutputStream과 같은 스트림객체를 먼저 생성한 후 작업해야한다.
dos.writeInt(100);
dos.writeDouble(10.5);
dos.writeUTF("문자열");
fos.close();
dos.close();

 

    8) Echo Server : 클라이언트가 전송한 데이터를 받아서 그대로 클라이언트에게 전송

public static void main(String[] args) {
Socket client = null;
BufferedReader in = null;
PrintWriter out = null;
// InputStream is =null; // 클라이언트와 input통신을 할 수 있는 스트림
// DataInputStream dis = null; // 최종적으로 클라이언트와 DataInputStream을 통해서 통신
// OutputStream os =null; // 클라이언트와 output통신을 할 수 있는 스트림
// DataOutputStream dos = null; // 최종적으로 클라이언트와 DataOutputStream을 통해서 통신
try {
	ServerSocket server = new ServerSocket(7777);//서버소켓을 열고 대기
	while (true) { // 클라이언트와 통신할 수 있는 input/output스트림을 소켓으로 부터 생성
		client = server.accept(); // 클라이언트 접속을 기다리다가 클라이언트가 접속하면 이용해서 Socket객체를 생성
		
		// 클라이언트와 통신할 수 있는 input/output스트림을 소켓으로 부터 생성
		in = new BufferedReader(new InputStreamReader(client.getInputStream()));
		out = new PrintWriter(client.getOutputStream(), true);
		// autoflush속성을 true로 설정하면 println메소드가 호출될때 자동으로 flush호출.
		out.println("문자열");
		String msg = in.readLine();
		
		//클라이언트가 전송하는 데이터를 읽기 위한 스트림 객체를 소켓으로 부터 생성한다.(accept 했을 때 만든 소켓)
		//is = client.getInputStream();
		//dis = new DataInputStream(is);
		// 클라이언트로 전송할 데이터를 출력하기 위한 스트림 객체를 소켓으로 부터 생성
		//os = client.getOutputStream();
		//dos = new DataOutputStream(os);
		//dos.writeUTF("문자열");
		//dos.writeInt(20000);
		//dis.readUTF()
		//dis.readint()
		
		/*
		out = new PrintWriter(client.getOutputStream());
		out.println("문자열");
		out.flush();// flush는 버퍼를 비우는 명령 - 출력버퍼의 내용을 실제로 출력하라는 의미
		// 출력버퍼에 임시로 보관되어 스트림으로 출력될때까지 대기중인 데이터를 스트릠으로 내보내는 작업을 하는 것이 flush
		*/
		
		//클라이언트가 보내오는 데이터를 지속적으로 읽어서 클라이언트로 다시 보내주는 작업 - 예측불가
		String reMsg = "";
		while(true) {//한 클라이언트와 지속으로 대화하기 위해서 사용하는 while
			//1. 서버<-클라이언트(클라이언트가 보내는 데이터를 지속적으로 읽기)
			reMsg = in.readLine();
			if(reMsg == null) {
				break;
			}
			//2. 서버 -> 클라이언트
			out.println(reMsg");
		}
	}
} catch (IOException e) {
	e.printStackTrace();
}

 

    9) Echo Client

Socket server = null;
BufferedReader in =null;//소켓통신
PrintWriter out =null;//소켓통신
BufferedReader keyin = null; // 서버에게 데이터를 내보내기 위해서 키로브로 입력하는 것을 읽기 위한 입력 스트림

try {
	server = new Socket("192.168.0.3",7777);
	System.out.println("Client Accept to server.");
	while(true) {
		in = new BufferedReader(new InputStreamReader(server.getInputStream()));
		keyin = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(server.getOutputStream(), true);
		
		//키보드로 입력하는 내용이 지속적으로 서버에 전달되도록 구현
		String sendMsg=""; // 서버로 보낼 메시지
		String reMsg=""; // 서버에서 받는 메시지
		while(true){
			//1. 클라이언트 -> 서버 (키보드로 입력하는 데이터 서버로 보내기)
			sendMsg = keyin.readLine();
			out.println(sendMsg);
			//2. 클라이언트 <- 서버
			reMsg = in.readLine(); // 네트워크로 입력되어 들어오는 데이터 읽기
			System.out.println("서버에서 전송된 메시지 : "+reMsg);
		}
	}
} catch (UnknownHostException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}

10. 중요 메소드 
    ① toString() : 오버라이딩을 통한 사용자 정의 toString()

public String toString(){
	String 변수 = 출력하고 싶은 문자열+...
	return 변수;
}
Object obj1= new Object(); // 최상위 객체
System.out.println(obj1.getClass()); // 클래스 이름
System.out.println(obj1.hashCode()); // 객체가 갖는 고유한 값 - 주소(10진수)
System.out.println(obj1.toString()); // 클래스 이름 @ 16진수의 hash code
				     // java.lang.Object@123a439b
System.out.println(obj1);    // toString()과 동일


String s = new String("str");    // String과 Date는 toString()이 오버라이딩된 값이 출력됨
Date   d = new Date();
System.out.println(s);    // s.toString이 호출.(toString() 기본 메소드로 생략됨)
System.out.println(d);    // d.toString이 호출.(toString() 기본 메소드로 생략됨)

Random r = new Random();    // 그외 Random, 사용자 정의함수는 주소값을 리턴한다.
Person p = new Person();
System.out.println(r);
System.out.println(p);

 

    ② equals() : 오버라이딩을 통한 사용자 정의 equals(). 

                    사용자 정의 객체의 경우 주소값을 비교함으로 equals 비교시 false를 리턴

class Person{
	...
	public boolean equals(Object obj) { // Person객체끼리 비교
		if(obj != null & obj instanceof Person) {
			// obj가 Person이라고 하더라도 타입이 Object이므로 Object의 멤버만 사용할 수 있으므로
			// obj를 Person으로 캐스팅하여 Person.equals를 사용한다.
			Person p = (Person) obj;
			if(this.name.equals(p.getName()) & this.addr.equals(p.getAddr())) {
				return true;
			}
		}
		return false;
	}
}

Person obj1 = new Person();
Person obj2 = new Person();

if(obj1.equals(obj2)){ // 사용자 정의된 equals() 비교
}

 

 

 

11. 중요 클래스

    ① String : 문자열 생성은 2가지 방법 존재.
        1) String 생성

String str = new String("문자열"); // new 이용
String str = "문자열"; // 리터럴 이용

        - new를 이용 시 동일한 문자열이 존재하여도 새로 생성.
        - 리터럴을 이용 시 동일한 문자열이 존재할 경우 기존 문자열 재사용. 상수풀(constant pool)에 저장되어 불변성

          을 가짐.
        - String 객체의 문자열이 어떤 방법으로 할당되는지 상관없이 문자열을 비교하고 싶은 경우 equals()사용

 

        2) String 생성자

byte[] data = {65,66,67,69,70};
		char[] data2 = new char[] {'0','1','0','-','1','2','3'};
		
		String str1 = new String(data); // ABCEF
		String str2 = new String(data2); // 010-123
		String str3 = new String(data2,2,2); // data2의 2번 index 부터 2개의 문자열. "1-"

        - String클래스를 사용하는 경우 다양한 타입의 입력데이터를 문장열로 만들 수 있도록 하기 위해

          다양한 형태의 생성자가 오버로딩 되어있음.

 

        3) String - final

class MyClass extends String{
}

        - String은 final class로 상속할 수 없음.

 

        4) String 메소드 : String 객체는 원본이 변경되지않고 메소드 실행결과로 새로운 String객체가 만들어짐.
                              : 문자열 조작이 많은 곳에서 String을 사용하는 것은 프로그램을 무겁게 함.

String str1 = new String("java programming");
String str2 = new String("입니다.");

str1.charAt(1); // str1에서 1번 index의 문자
str1.concat(str2); // str1과 str2를 연결
str1.indexOf('a'); // str1에서 가장 왼쪽의 'a'의 index
str1.indexOf("합"); // 문자가 없을 경우 -1 리턴
str1.lastIndexOf('a'); // str1에서 가장 오른쪽의 'a'의 index
str1.length(); // str1의 길이
str1.equalsIgnoreCase("java programming");
str1.equalsIgnoreCase("JAVA programming"); // 대소문자 구분하지않고 문자열 비교
str1.startsWith("java")); // str1이 "java"로 시작하면 true아니면 false 리턴
str1.endsWith("amming")); // str1이 "amming"로 끝나면 true아니면 false 리턴
str1.toUpperCase(); // 대문자 변환값 리턴
					// 원본 문자열 변화 없음. 새로운 객체를 생성하여 리턴.
str1.toLowerCase()); // 소문자 변환값 리턴
str1.substring(4); // 4번째 문자열부터 끝까지의 문자열 추출. programming
str1.substring(4,8); // 4번째 문자열부터 8-1번까지의 문자열 추출. pro
str1.replace('a','A')); // 'a' 문자를 'A'로 변경. jAvA progrAmming

 

        5) String 의 데이터 타입 변환과 관련된 메소드

String str1 = new String("java programming");
String str2 = new String("java servlet spring bigdata");

//1) getBytes() : String -> byte[] 변환
byte[] data1 = str1.getBytes();
for(int i=0;i<data1.length;i++) {
	System.out.print(data1[i]+" ");
}

//2) toCharArray() : String -> char[] 변환
char[] data2 = str1.toCharArray();
for(int i=0;i<data2.length;i++) {
	System.out.print(data2[i]+" ");
}

//3) split(" ") : String -> String[] 변환
String[] data3 = str2.split(" ");
for(int i=0;i<data3.length;i++) {
	System.out.print(data3[i]+" ");
}

//4) valueOf(x) : 기본형 -> String 변환
int i =1000;
double d = 10.5;
test(String.valueOf(i));
test(String.valueOf(d));

test(i+"");
test(d+"");

public static void test(String data) {
	System.out.println("변환된 데이터 "+data);
}

        6) StringBuffer : String의 불변성으로 메모리 사용이 많아 대안으로 원본 배열이 변경되는
                             StringBuffer사용하기도 함.

           StringBuffer와 StringBuilder의 차이

               StringBuffer  : thread 고려 무겁다 안전. JDK 1.0이상
              StringBuilder : thread 비고려 가볍다 웹서버에서 처리함으로 무관. JDK 5.0이상

 

           StringBuffer 사용

StringBuffer sb = new StringBuffer("java programming");

sb.append("입니다."); // 맨뒤에 추가
sb.insert(2, "자바"); // 지정한 위치에 문자열 삽입
sb.delete(2, 6); //start~end-1 위치의 문자열 삭제 
sb.reverse(); // 문자열 반전

           ③ String과 StringBuffer의 비교

public static void stringCheck(int count) {
	// 시작할때 현재 시간을 측정 - nano초
	long start = System.nanoTime();
	String str = new String("java");
	for(int i=1; i<=count;i++) {
		str+="java";
	}
	long end = System.nanoTime();
	System.out.print("str+='java' ");
	System.out.println("수행시간\t: "+(end-start)+" ns");

}
public static void stringBufferCheck(int count) {
	long start = System.nanoTime();
	StringBuffer sb = new StringBuffer("java");
	for(int i=1; i<=count;i++) {
		sb.append("java");
	}
	long end = System.nanoTime();
	System.out.print("sb.append('java') ");
	System.out.println("수행시간\t: "+(end-start)+" ns");
		
}
public static void main(String[] args) {
	int count = 10000;
	System.out.println("실행횟수 : "+count);
	stringCheck(count);
	stringBufferCheck(count);
}

 

    ② Math

Math.PI;          // PI
Math.abs(-1);     // 절대값
Math.ceil(10.5);  // 올림
Math.round(10.5); // 반올림
Math.floor(10.5); // 버림
Math.max(100,10); // 최대값
Math.min(100,10); // 최소값
Math.random();    // 난수

 

    ③ Wrapper 클래스

        1) 5.0 이전(기본형 -> 참조형)

int num =100; 
Integer obj = new Integer(num); // 기본형 -> 참조형 
run(obj); 

public static void run(Object obj) { // Integer -> Object 
Integer inObj = (Integer)obj;    // Object -> Integer 
int num = inObj.intValue();      // Interger -> int (참조형->기본형) 
} 


        2) 5.0 이후 (기본형 -> 참조형)

int num = 1000; // 5.0 이후 버전의 jdk에서는 컴파일러가 자동으로 변환해준다. 
run(num); // 참조형으로 매개변수가 정의되어 있어도 기본형을 전달하는 경우 자동으로  
// 컴파일러가 Integer in = new Integer(num) 이 코드를 실행해서  
// Integer타입으로 변환해준다. 이를 오토박싱이라 한다. 
public static void run(Object obj) { 
Integer inObj = (Integer)obj; 
int i = inObj; // (참조형->기본형) 

int j = (Integer)obj; // 오토 언박싱 
// int형 변수에 참조형 변수를 전달하는 경우 컴파일러가 자동으로 객체를  
// int로 바꾸는 코드를 만든다. 
// int j = obj.intValue(); 
}

 

    ④ Calendar 클래스 : 날짜 시간

//java.util.date : 시스템의 기본 날짜와 시간
//java.sql.date : DBMS(오라클)에서 date타입으로 전의한 칼럼값을 다루기 위해서 사용하는 타입

//Date 객체는 deplecate
//GregorianCalendar는 Calendar의 자식 클래스

import java.util.Calendar;

Calendar cal = new GregorianCalendar(); // 오늘 날짜기간 정보
cal.get(Calendar.YEAR);
cal.get(Calendar.MONTH)+1;
cal.get(Calendar.DATE);
cal.get(Calendar.HOUR);
cal.get(Calendar.MINUTE);
cal.get(Calendar.SECOND);
cal.getTimeInMillis();
cal.set(2020,11,30);

 

    ⑤ SimpleDateFormat 클래스 : 출력되는 데이터의 형식을 변경할 수 있는 API

SimpleDateFormat sdf = new SimpleDateFormat("yyyy년MM월dd일");
Calendar today = new GregorianCalendar();
sdf.format(today.getTime()); //getTime() : Calendar객체를 Date로 변환

 

    ⑥ DecimalFormat 클래스 : 출력되는 데이터의 형식을 변경할 수 있는 API

import java.text.DecimalFormat;

DecimalFormat df = new DecimalFormat("#,###.##");
df.format(1234567);
df.format(1234567.48);
String data = "25465.174";
df.format(Double.parseDouble(data);
try {
	double data3 = (double) df.parse(data);
	String num3 = df.format(data3);
}
catch(ParseException e) {
	
}

 

    ⑦ 어노테이션

@Override

 

     StringTokenizer : String클래스의 split()을 사용하는것과 비슷한 개념. token화.

import java.util.StringTokenizer;
StringTokenizer st = new StringTokenizer("java:servlet:jdbc:spring:hadoop",":");

System.out.println(st.countTokens());//토근의 개수 리턴
while(st.hasMoreTokens()) { // StringTokenizer 내부 저장소에 token이 있으면 true 없으면 false 리턴
	String token = st.nextToken(); // token을 리턴.
	System.out.println(token);
}

 

    Arrays

import java.util.Arrays;

int[] arr = {10,20,30,40,50};
Arrays.fill(arr,100); // 배열 요소를 특정 값으로 채우기
Arrays.equals(arr, arr2); // 배열값이 같은지 비교
Arrays.sort(arr); // 배열의 데이터 정렬(default : 오름차순)
Arrays.binarySearch(arr,50); // 배열에서 특정 값이 저장된 요소의 index

 

    향상된 for문

for(요소의 타입 요소를 저장할 변수:컬렉션을 참조하는 변수){
}

 

 

 

12. 컬렉션 : List, Map, Set을 생성하기 전에 저장될 요소의 타입을 미리정의
                컬렉션 클래스<요소의 타입> 변수 = new 컬렉션 클래스<요소의 타입>();
                 <요소의 타입> : Generic

    ① List : 배열과 동일한 구조, 중복 가능. 주로 ArrayList 사용.
        1) Vector : 무겁 Thread에 안전

import java.util.Vector;

Vector v = new Vector(); // 다른 타입도 저장가능. 5.0이전 사용
//=> Vector안에 저장되는 데이터의 타입을 제한(요소타입이 기본형인 경우 Wrapper타입으로 명시)

Vector<Integer> v = new Vector<Integer>(); // Generic으로 Vector의에 저장되는 요소의 타입을 명시
v.add(10); // 값 추가.
v.size(); // 현재벡터에 저장된 요소의 개수
v.capacity(); // 현재 벡터의 용량
v.get(0) // 값 read

Vector<String> v2 = new Vector<String>();
v2.add("aa");

for(String s:v2) {
	System.out.print(s+" ");
}

        2) ArrayList : 가볍 thread에 unsafe

import java.util.ArrayList;

ArrayList<Integer> list = new ArrayList<Integer>();
list.add(10); // 값 추가.
list.size(); // 저장된 요소의 개수
list.get(0) // 값 read

        3) 2차원 배열

import java.util.ArrayList;

ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> row = new ArrayList<Integer>();

for(int i=0;i<3;i++) {
	row.add(i);
}

ArrayList<Integer> row2 = new ArrayList<Integer>();
for(int i=3;i<7;i++) {
	row2.add(i);
}

ArrayList<Integer> row3 = new ArrayList<Integer>();
for(int i=7;i<9;i++) {
	row3.add(i);
}
list.add(row);
list.add(row2);
list.add(row3);

for(int i=0;i<list.size();i++) {
	for(int j=0;j<list.get(i).size();j++) {
		System.out.print(list.get(i).get(j)+"\t");
	}
}

    ② Set : 집합. 합집합, 교집합가능. 중복이 불가능. 주로 HashSet 사용.
        1) HashSet

import java.util.HashSet;

HashSet<String> set = new HashSet<String>(); // 생성
set.add("aa"); // 데이터 추가
set.add("bb");
set.add("cc");
set.add("dd");
set.add("ee");
set.add("aa"); // 중복불가
System.out.println("요소의 개수: " + set.size()); //5 

// 데이터 추출
// set은 선형구조가 아니라 순서대로 읽어올 수 없다.
// 여러종류의 자료구조에 저장된 데이터를 내부에서 Iterator로 변환해서 읽을 수 있도록 지원
// HashSet -> Iterator
Iterator<String> it = set.iterator();
while(it.hasNext()) { // iterator안에 데이터가 있는 지 확인. boolean리턴
	String element = it.next(); // Iterator에 저장된 요소 꺼내기
	System.out.println("set에 저장된 요소 : "+element);
}

 

        2) HashSet 교집합, 합집합

HashSet<String> set = new HashSet<String>();
set.add("aa");
set.add("bb");
set.add("cc");
set.add("dd");
set.add("ee");
set.add("ff");

//합집합 - Set을 생성할때 매개변수로 다른 Set을 전달
HashSet<String> set2 = new HashSet<String>(set);
set2.add("zz");
set2.add("yy");
set2.add("xx");
set2.add("aa");

//교집합
HashSet<String> set3 = new HashSet<String>();
set3.add("aa");
set3.add("dd");
set3.add("zz");
set.retainAll(set3); // 두 set의 교집합이 set에 새로 저장된다.


        3) SortedSet

    ③ Map : key와 value. 주로 HashMap사용.
        1) HashMap : Thread에 비안전, 빠름

HashMap<Integer,String> map1 = new HashMap<Integer, String>();
// key가 중복되면 마지막 작업한 내용으로 덮어쓴다.
map1.put(1, "aa");
map1.put(1, "bb");
map1.put(1, "cc");

System.out.println(map1.get(1)); //cc 마지막 값 리턴.
System.out.println(map1.size()); //1

HashMap<String, String> map2 = new HashMap<String, String>();
map2.put("a001", "aa");
map2.put("a002", "bb");
map2.put("a003", "cc");
map2.put("a004", "dd");
map2.put("a005", "ee");
map2.put("a006", "ff");
map2.put("a007", "gg");
map2.put("a008", "hh");

System.out.println(map2.size());
System.out.println(map2.get("2"));

//map에 저장된 데이터를 꺼내기
//1. map이 갖고 있는 키들을 set으로 변환
Set<String> keyList = map2.keySet();

//2. set에 저장된 key목록을 iterator로 변환하고
Iterator<String> it = keyList.iterator();

//3. iterator에서 key를 하나씩 꺼내서 get
while(it.hasNext()) {
	String key = it.next();
	String value = map2.get(key);
	System.out.println(key+":"+value);
}

 

        2) HashTable : Thread에 안전, 느림
        3) Properties

 

 

 

13. I/O

    Input용클래스  - _____InputStream     (byte단위)
                          _____Reader            (문자단위)
    Output용클래스 - _____OutputStream (byte단위)
                            _____Writer           (문자단위)

 

    1) InputStream, PrintStream : byte 단위 입출력 처리

class System{
	public static final InputStream in;
	public static final PrintStream out;
}
InputStream myin = System.in;
PrintStream myout = System.out;
try {
	while(true) {
		int data = myin.read(); // 키보드로 입력한 단어를 읽어서 리턴.
		myout.print((char)data+" "); // 입력받은 데이터는 int로 문자로 변환하여 출력.
		//System.out.print((char)data+" "); // System.out = myout
		if(data==13) // 개행문자가 오면 종료.
			break;
		
	}
}
catch(IOException e) { // read()는 예외처리가 필요.
	e.printStackTrace();
}

 

    2) InputStreamReader : 문자 단위 입출력 처리. 사용방법이 InputStream와 동일

InputStreamReader myin = new InputStreamReader(System.in); // 객체 생성만 다르다.
PrintStream myout = System.out;

try {
	while(true) {
		int data = myin.read();
		myout.print((char)data);
		if(data==13)
			break;
	}
}
catch(IOException e) {
	e.printStackTrace();
}

 

    3) File 클래스

File dir = new File("C:/java/test"); //액세스 하고 싶은 폴더나 파일의 경로 - 절대경로, 상대경로
//File dir = new File("C:\\java\\test");
File file = new File("test.txt"); // ROOT

System.out.println(file1); // toString()
System.out.println(file2); // 생성자에 입력값 출력.
file.canRead(); // 해당 파일을 읽을 수 있으면 true, 아니면 false 리턴.
file.canWrite(); // 해당 파일을 쓸 수 있으면 true, 아니면 false 리턴.
file.getAbsolutePath(); // 절대 경로 리턴
file.getName(); // 파일의 확장자를 포함한 이름 리턴
file.getParent(); // 파일 또는 폴더의 상위 경로 리턴
file.getPath(); // 상대경로 리턴
dir.isDirectory(); // 디렉토리이면 true, 아니면 false 리턴.
file.isDirectory();
dir.isFile(); // 파일이면 true, 아니면 false 리턴.
file.isFile();
dir.lastModified(); // 마지막 수정일자 리턴
// 폴더의 기본사이즈 : 4096
dir.length(); // 폴더 or 파일 크기 리턴
file.length();
file.setReadOnly(); // 읽기전용으로 변경.
file.setWritable(true); // 쓰기가능으로 변경.

File[] fileArr = file.listFiles(); // 파일객체 내부의 파일에 대한 파일객체 배열을 리턴
String[] fileName = file.list; // 파일객체 내부의 파일이름 배열 리턴

 

    4) FileInputStream : byte 단위 파일 액세스

FileInputStream fis = null; // 인스턴스를 try안에서 생성 시 {}안에서만 사용할 수 있어
							// 인스턴스만 생성 후 파일열기는 try 내부에서 진행. 
try {
	fis = new FileInputStream("src/data/test.txt");//1. 파일 열기 - FileNotFoundException 처리 필요
	while(true) {
		int data = fis.read(); // IOException 처리 필요
		if(data == -1) { // 파일읽기가 끝나면 -1을 리턴한다.
			break;
		}
		System.out.print((char)data);
	}
} catch (FileNotFoundException e) {
	e.printStackTrace();
}
catch(IOException e) {
	e.printStackTrace();
}
finally {
	// 3. 파일 닫기 - 자원반납
	//IO 작업을 하다가 오류가 발생하거나 정상적으로 처리된다고 하더라도 모두 자원을 반납해야하므로 finally 블럭에서 처리.
	// input은 오류가 없는 output은 close를 안하면 파일에 output한 데이터가 write되기 전에 파일을 내부에서 종료한다.
	try {
		if(fis!=null) // 파일이 null로 파일열기에 실패할 경우 file close를 진행하면 안되므로 예외처리 진행.
			fis.close(); // IO Exception 처리 필요.
	}
	catch(IOException e) {
		e.printStackTrace();
	}	
}

 

    5) FileReader : 문자 단위 파일 액세스. FileInputStream과 동일.

FileReader fr = null;
try {
	fr = new FileReader("src/data/test.txt");
	
	while(true) {
		int data = fr.read();
		if(data == -1) {
			break;
		}
		System.out.print((char)data);
	}
} catch (FileNotFoundException e) {
	e.printStackTrace();
}
catch(IOException e) {
	e.printStackTrace();
}
finally {
	try {
		if(fr!=null)
			fr.close();
	}
	catch(IOException e) {
		e.printStackTrace();
	}
	
}

 

    6) FileWriter : 문자 단위 파일 쓰기. 파일이 존재하지 않으면 새로 만들어서 출력한다.

FileWriter fw = new FileWriter("src/data/output.txt");
// 두번째 매개변수가 없을 경우 default로 덮어쓰기을 진행한다.
FileWriter fw = new FileWriter("src/data/output.txt",true);
// 생성자에 두번째 매개변수가 true를 두면 apped모드 활성화된다.
fw.write(97);
fw.close();

 

    7) BufferedReader : 버퍼를 이용하여 파일의 한 라인씩 읽을 수 있어 실행속도가 빨라 FileReader보다 많이 사용된다.

BufferedReader br = null;
// BufferedReader는 생성자 인자로 FileReader객체를 매개변수로 받는다.
// FileReader fr = null;

try {
	br = new BufferedReader(new FileReader("src/io/InputStreamTest.java"));
	// fr = new FileReader("src/data/test.txt");
	// br = new BufferedReader(fr);
	// FileReader 객체를 따로 생성해서 BufferedReader 매개변수에 전달할 수 있으나
	// 코드를 줄이기 위해 한줄에 사용
	while (true) {
		String line = br.readLine(); // 한줄씩 읽는다.
		if (line == null) { // 읽을 라인이 없다면 null을 리턴.
			break;
		}
		System.out.println(line);
	}
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
} finally {

	try {
		if (br != null) {
			br.close();
		}
	} catch (IOException e) {
		e.printStackTrace();
	}
}

 

 

 

<tip>

* toString 자동 생성: Source - Generate toString

* API 문서에서의 Deprecated : 미사용 권고

1. main

public class 클래스명{ 
    public static void main(String[] args){
    } 
} 

 

 : java 인터프리터가 명시된 클래스 파일 안에서 "public static void main(String[] args)"를 찾아서 첫번째 문장부터 실행. 

 

2. 데이터 타입
① 기본형(Primitive) : 값을 저장하기 위한 타입
                         : 논리형(boolean - 1byte)

                         : 문자형(char (' ') - 2byte)

                         : 정수형(byte - 1byte, short - 2byte, int - 4byte, long - 8byte)

                         : 실수형(float-4byte, double-8byte)
 
② 참조형(Reference) : 자바프로그램 내부에서 사용하는 클래스들이 할당된 메모리의 주소를 저장.
                           : 자바에서 제공하는 API(클래스), 사용자 정의 클래스, 배열, 문자열(" ") 

③ 데이터 타입 범위 이상의 값은 할당할 수 없다.

long l = 1000;	// 1000은 int literal.
               	// 큰타입의 변수에 작은 타입의 값을 할당하는 것은 자동으로 데이터 타입 변환하여 가능
long l = 2147483648;	// error 
long l = 2147483648L;	// no error 
float f =10.5;	// error 
float f =10.5f;	// no error 
double d = 10.5;	// 10.5은 int literal.

④ 진수표현

    2진수 : 0b 

    8진수 : 0
    16진수 : 0x
    유니코드 : \u 
    (char) 'A' 는 (int) 65와 같다

 

3. 변수

 ① 변수사용시 주의사항
    1) 지역변수를 사용하는 경우 반드시 초기화 작업을 하고 사용해야한다.
    2) {}안에서 선언된 변수는 {}안에서만 사용할 수 있다.

 기본형 데이터 타입의 형변환
    1) 묵시적 형변환 - 자동형변환(큰타입의 변수에 작은 데이터를 담을경우)
    byte -> short -> int -> long -> float -> double

    1          2          4         8         4        8
               char -> 
                2

char c = 'A'; 
int i = c; // char - > int 자동 형변환 
char c = i; // int -> char 자동 형변환 되지않아 error 

 

    => byte, short char는 연산시 기본형인 int로 변환됨.

    2) 명시적 형변환 - 형변환을 직접 정의해야한다.

int i = 200; 
byte b = (byte)i; // error는 발생하지않지만 int의 bit중 유실되는 값이 존재하여 원하는 값이 출력이 되지않는다.
int c =65;
(char)c; // 'A' 출력

double d = 10.0/3.0;	// 3.3333
double d = 10/3.0;	// 3.3333    정수와 실수 연산은 실수값 반환.
double d = 10/3;	// int형 리터럴로 3이 출력되며 double 변수에 3.0으로 저장된다.

 

 ③ 실수의 연산결과는 부정확

double d = 2.0 - 1.1  // 0.8999999

 

  BigDecimal 사용 : 정확한 소수점 계산 가능.

import java.math.BigDecimal;
BigDecimal m1 = new BigDecimal("2.0");
BigDecimal m2 = new BigDecimal("1.1");
m1.subtract(m2);   //  0.9

 

 ⑤ 데이터의 최대 / 최소값 확인  

Integer.MIN_VALUE 
Integer.MAX_VALUE 
Long.MIN_VALUE 
Long.MAX_VALUE 
Float.MIN_VALUE 
Float.MAX_VALUE 



⑥ 상수 : 변경 할 수 없는 값으로 정의가능.

final 데이터형 변수명 = 초기값;

 

4. 연산자

 ① 산술 연산자 + - * / %
  증감 연산자

x=5; 
y=++x; 
// result : x=6,y=6 

x=5; 
y=x++; 
// result : x=6,y=5 

x=5; 
y=--x; 
// result : x=4,y=4 

x=5; 
y=x--; 
 // result : x=4,y=5 


  비교 연산자 : <,>,<=,>=,!=
"문자열"+숫자 => "문자열+숫자"

  대입 연산자 : +=,-=,*=, /=, %=
 
⑤ 논리 연산자 : &&, ||, !

 

 - 실행오류 : 컴파일은 문제가 없으나 실행 중에 오류가 발생하는 경우

    ex) null.length();

 

 - &,|과 &&, || 차이점
1) || 연산자는 왼쪽 할을 검사해서 true이면 || 연산의 특성에 따라 오른쪽 항은 검사하지않는다.
 => TRUE || 실행오류   -> 정상실행
 => TRUE | 실행오류    -> error

2) && 연산자는 왼쪽 할을 검사해서 false이면 || 연산의 특성에 따라 오른쪽 항은 검사하지않는다.
 => FALSE && 실행오류   -> 정상실행
 => FALSE & 실행오류    -> error

 - 삼항 연산자 : 조건이 참이면 A return, 거짓이면  B return
    조건식 ? A:B

 

5. 문법
 - 주석
    1) //    : 한줄 주석
    2) /* */ : 여러줄 주석 설정 (단축키 : ctrl+shift+/)
       여러줄 주석 해제 (단축키 : ctrl+shift+\)
 순차형    
 조건형
     1) if
     2) if else
     3) 다중 if
     4) switch(표현식 ) case

     : 표현식에는 byte, short, int, char, String, enum만 가능. 
     : 표현식에는 변수, 연산식, 메소드 호출문 가능.
     : switch에 int가 case에 char가 있는 경우 int를 형변환하여 비교. 
        ex)

int data=5; 
switch(data+60) {
	case 'A':
	System.out.println('A');
	break; 
 } 

 
반복형
     1) for(초기값;조건식;증감식)
     2) for 안 if
     3) 다중 for
     4) while(조건문){}
     5) do{} while(조건문);
     6) while break
     7) for break
     8) for continue
      => break와 continue는 가까운 반복문에만 적용.

      => 먼 반복문까지 이동하려면 라벨을 사용한다.

라벨: 
for(int i=0; i<10;i++){ 
	for(int i=0; i<10;i++){ 
		break 라벨; 
		// or continue 라벨; 
	} 
} 


     9) for-each

for(int i:array){ 
	array[i] 
}

 

7. 참조형 변수 : 자바언어에서 제공되는 API를 이용
 String
    String str = new String("문자열 초기값");
    java라는 문자열을 처리하기 위해서 String클래스를 메모리에 할당
    즉, String 클래스의 charAt이라는 기능(메소드)을 사용하기 위해서 JVM이 인식하는 작업 공간인 heap에 string

    클래스를 할당하고 할당된 주소를 str변수에 저장

* charAt(index) : index의 문자 추출. index는 0부터 시작( str.charAt(0) )

 

* length() : 문자열의 길이 리턴( str.length() )

 

 Random : 랜덤수를 관리하는 기능을 제공하는 클래스

import java.util.Random;
	Random rand = new Random();

* nextInt() : int 범위내의 랜덤 수 리턴. ( rand.nextInt() )
* nextInt(int) : 0부터 int-1까지의 램덤 수 리턴. ( rand.nextInt(100) ) -> 0~99까지 

 

 Scanner : 표준 입력 (키보드)으로 입력된 값을 읽어서 리턴하는 기능을 제공하는 클래스

import java.util.Scanner;
Scanner key = new Scanner(System.in);
    
System.in : 표준입력(키보드 입력)
System.out : 표준출력(모니터 출력)
표준입력으로 입력한 값을 저장하기 위해 System.in을 ()안에 정의
        
        
* nextLine() : 한 문장을 입력받기 위한 메소드 ( String line = key.nextLine() )
* next() : 단어를 입력 받기 위한 메소드. 공백입력 전의 문자열을 단어로 인식. ( String data = key.next() )
* nextInt() : 정수를 입력 받기위한 메소드( int num = key.nextInt() )
* System.out.print("문자열") : 문자열 출력 후 개행 없음
* System.out.println("문자열") : 문자열 출력 후 개행 있음.

 Array : 배열은 초기값을 가진다. 정수 0, bool false, 실수 0.0, 참조형 null
 1) 배열 선언

데이터형[] 변수명;
int[] array;
int array[];

 2) 배열 생성

변수명 = new 데이터형[개수]; 
array = new int[3];

 

3) 배열 선언과 생성

데이터형[] 변수명 = new 데이터형[개수]; 
int[] arr = new int[3]; 

 

4) 배열 get

변수명 => 주소값 
array 

변수명[index] => index번째 요소 값 리턴 
array[0] 


5) 배열 set

변수명[index] = 값; 
arry[0] = 1;

 

6) 참조형 배열 선언, 생성

데이터형[] 변수명 = new 데이터형[개수];
Random[] randarr = new Random[3]; 
randarr[0] = new Random(); 
randarr[0] => 주소값
String[] strArr = new String[5];
strArr[0] = new String("java");
strArr.length
strArr[1] // 값 리턴.
	

참조형 배열의 요소의 값을 sysout으로 액세스하는 것은 참조형 배열의 할당된 객체의 toString메소드를 호출하는 것과 같다.

 

5) 배열 생성, 선언, 초기화

int[] myarr = {10,20,30,40,50, 60}; 
int[] myarr2 = new int[]{10,20,30,40,50, 60}; 
String myVal = new String("javascript"); 
String[] myarr4 = {new String("aA"), 
   		new String("bB"), 
   		new String("cC"), 
   		myVal}; 
int[] arr; 
arr={1,2,3}; // error

 

⑤ 다차원 배열 : 배열을 참조하는 배열

int[][] array;
	array = new int[4][5];
	array = new int[4][];
	array = new int[][5]; => error
	array = new int[][]; => error
	
	int[][][] arr = new int[2][3][4];
	
	for(int i=0; i<array.length;i++)
		for(int j=0; j<array[i].length;j++)
			array[i][j]
			
	int[][] data= {{1,2,3,4,5},
				   {6,7,8,9,10}};//[2][5]

* System.arraycopy(복사하려는 원본배열, 원복배열의 복사할 시작시점(index), 복사배열을 붙여넣기 할 target 배열,붙여넣기할 target 시작위치, 복사될 요소개수);

System.arraycopy(arrSrc,0,arrDest,2,3);

8. 클래스 : 시스템을 구성하는 구성요소(시스템 적인 요소, 프로그램 내부에서 처리해야하는 구성요소)

 ① 형식

지정자 class 클래명{ 
	int 멤버변수명; 
}

클래스명 인스턴스명 = new 클래스명() 
인스턴스명.멤버변수 = 1;

 ② 클래스의 구성요소 : 멤버변수, 메소드, 생성자

 

 ③ 접근 지정자
public   : 다 가능
protected : 같은 클래스, 패키지, 상속 가능. 다른 패키지에서 접근 불가.
(default) : 같은 클래스, 패키지 가능. 상속,다른 패키지 불가능.
private   :  같은 클래스만 가능. 같은 패키지, 상속,다른 패키지 불가능.
 => 클래스 정의시 멤버변수는 private로 처리하고 메소드로 접근하여 처리.

 

9. 메소드

접근제어자 리턴타입 메소드명(매개변수1,...){ 
	// 메소드 내부 실행될 명령문 
	return 리턴값; 
	// 메소드 선언부에 명시한 리턴타입과 동일한 타입의 데이터 리턴. 
} 


 메소드 호출문 종류
    1) 매개변수가 없고 리턴타입이 없는 메소드의 호출
    2) 매개변수가 1개 이고 리턴값이 없는 메소드의 호출
    3) 매개변수가 여러 개인 메소드의 호출 - 매개변수가 여러 개인 경우 ,로 구분해서 값을 정의
      => 반드시 선언된 순서와 동일하게 값을 넘겨줘야한다.

    4) 매개변수가 있고 리턴타입이 있는 메소드의 호출
     => 리턴값을 갖고 있는 메소드는 다른 메소드의 매개변수로 바로 전달할 수 있다.

 

  메소드 선언 종류

    1) 매개변수가 없고 리턴타입이 없는 메소드

    2) 매개변수가 있고 리턴타입이 없는 메소드

    3) 매개변수가 있고 리턴타입이 있는 메소드

    4) 매개변수가 있고 리턴타입이 있는 메소드

 

③ 메소드 오버로딩

    매개변수는 메소드를 유연하게 만든다.(한가지만 처리하지 않도록 하기 때문에 다양한 곳에서 호출이 가능) 
    매개변수 개수나 타입을 다르게 정의한 메소드명을 동일하게 사용.

 

④ setter 메소드와 getter메소를 정의하는 방법
     set(get)+멤버변수명(멤버변수의 첫글자를 대문자로 변경)
     기본 자바에서는 getter나 setter메소드의 이름을 정해진 약속대로 작성하지않아도 문제될 것이 없으나
     스프링이나 웹에서 이 명명규칙을 지키지않으면 오류가 발생한다.

    1) name 변수에 외부에서 전달하는 값을 셋팅하기 위한 메소드 - setter

public void setName(String name) {
			this.name = name; // 멤버변수 name = 지역변수(매개변수) name
		}

    2) name 변수에 저장된 값을 외부에 전달하는 메소드 - getter

public String getName() {
			return this.name;
			//return name; // 안붙여도 가능


⑤ oop 특성 (객체 지향 프로그래밍 Object Oriented Programing)
     1) 캡슐화 : private 외부에서 데이터를 접근하지 하게 처리.
                 : 정보 은닉
                 : 객체의 통신을 통해서 값을 주고 받는다.
                 : 외부에서는 객체가 무슨일 하고 어떤 기능을 갖고 있는지 안다.

 

10. 생성자 : 객체가 생성될 때 한번만 호출되는 메소드.

               : 주로 자원 제어에 관련된 작업을 수행하거나 객체가 가지고 있는 멤버변수를 초기화.

               : new연산자가 생성자 메소드를 통해서 메모리에 할당할 객체가 어떤 클래스인지 파악하고 호출해야 하므로

                생성자 메소드를 정의할 때 규칙이 존재한다.

① 형식

 

클래스타입 변수 = new 생성자메소드(매개변수1, 매개변수2..) 


② 규칙
1) 생성자 메소드명은 클래스명과 대소문자까지 동일하게 정의.


2) 생성자 메소드는 정의할 때 리턴타입을 명시하지않는다. (void도 미표기)


3) 클래스를 만들때 생성자 메소드를 정의하지 않으면 컴파일러가 자동으로 매개변수 없는 생성자를 추가한다.

    매개변수가 없는 생성자는 기본생성자.


4) 일반 메소드처럼 매개변수 개수나 타입을 다르게 정의하면 여러 개의 생성자를 정의 가능.
   생성자 메소드도 오버로딩 가능


5) 생성자 메소드도 일반 메소드처럼 외부에서 값을 전달받아 사용할 수 있도록 매개변수를 정의할 수 있다.


6) 클래스를 정의하면서 생성자 메소드를 한 개 이상 정의하면 컴파일러가 기본생성자를 제공하지않는다.
    기본생성자는 자바 프레임워크(Spring)에서 기본으로 호출되므로 기본생성자를 쓸일이 없어도 반드시 기본 생성자는 정의해야한다.


7) 생성자 메소드가 오버로딩되어 있는 경우 자신의 생성자를 호출할 수 있다.
   생성자 메소드 안에서 또 다른 생성자 메소드를 호출할 수 있다.
   생성자내 생성자 호출시 생성자 맨앞에 호출해야한다.
   this(매개변수1, 매개변수2..)

 

③ static변수(클래스 변수) : 클래스가 로딩될때 한번 메모리에 로딩되어 모든 인스턴스가 공유해서 사용한다.

1)  멤버변수는 객체 참조 변수(인스턴스 변수)를 이용해서 액세스가 가능 (인스턴스 변수는 객체 소유)


2) static 변수는 객체의 소유가 아님으로 인스턴스변수를 통해서 접근하지 않고 클래스명으로 접근함. 

 

3) API 사용 시 static 메소드/변수인지 확인하여 static이면 (클래스명.메소드명) 또는 (클래스명.변수명)으로 사용.
   아닐 경우 인스턴스 변수를 선언하여 사용한다. (new 사용)

 static 메소드의 사용
 1) static 메소드는 static변수를 액세스 하기 위한 목적
 2) 유틸리티처럼 편하게 사용

 static 메소드 내 non-static 메소드 호출
    1) static 메소드에서 static 메소드 호출 - 일반적인 방법으로 접근 가능
    2) non-static 메소드에서 non-static 메소드 호출 - 일반적인 방법으로 접근 가능
    3) non-static 메소드에서 static 메소드 호출 - 일반적인 방법으로 접근 가능
    4) static 메소드에서 non-static 메소드 호출
    static메소드에서 non-static메소드를 호출하려면 자신 객체라 하더라도 객체를 생성해서 호출 해야함.

⑥ 초기화 블록 : 생성자 유사
    {}

⑦ static 블록
static {}

 

⑧ 클래스 배열 사용 

클래스명[] 인스턴스명 = new 클래스명[배열수]; 
Person[] personArr = new Person[3]; 



⑨ call by value
메소드의 매개변수로 값을 넘기는 경우 - 매개변수값을 변경해도 호출부 변수값은 변경되지않는다.

⑩ call by reference
메소드의 매개변수로 배열이나 객체를 넘기는 경우 - 매개변수값을 변경시 호출부 변수값이 변경된다..
String은 매개변수로 값은 전달되나 새로운 객체에 값이 전달된다.

change(i, mainArr);
		
public static void change(int i,int[] myarr) {
	i = 200;        => 변경안됨
	myarr[2] = 300; => 변경됨
}
class Point{
	int x = 10;
	int y = 20;
}
		
Point main_p = new Point(); // 참조형
String mainStr =new String("java"); // 참조형
		
change(i, main_p,mainStr);
		
public static void change(int x,Point p,String str) { // String str = new String()이 되어 새로운 객체가 생성
	x = 3000;		// 값 변경 안됨.
	int temp = p.x;
	p.x = p.y;
	p.y = temp;		// 값 변경.
	str = "myjava"; // 새로운 객체에 값이 전달됨.		
}

11. 상속 : is a 관계 <-> 클래스와 내부 변수 관계 : has a 관계

 ① 형식

class 자식클래스명 extends 부모클래스명{ 

}

 

같은 클래스내 class 생성시 메인 클래스에만 public을 부여한다.

public class 부모클래스명{ // 일반화된 기능이 정의된 클래스. 상위, 부모, super클래스 
} 

class 자식클래스명 extends 부모클래스 { // 부모클래스를 상속받아 확장해 놓은 클래스. 하위, 자식, sub클래스 
} 



② 상속관계에서 멤버변수가 갖는 특징
    1) 상속관계에서는 상위클래스에 선언된 멤버변수를 하위 클래스에서 접근가능.
    2) 상위클래스에서 선언된 변수와 동일한 이름의 변수가 하위클래스에 선언되어 있으면 부모클래스의 멤버변수 보다

        자신 클래스의 변수가 우선 순위가 높다.
    3) 하위클래스에서 상위클래스의 멤버변수를 접근하고 싶은 경우 super를 이용해서 접근한다.
       this  : 자기자신
       super : 부모
       super.변수명;
    4) 상위 클래스의 멤버가 private인 경우에는 하위클래스라고 하더라도 접근할 수 없다.

③ 상속관계에서 메소드가 갖는 특징
    1) 상위클래스에서 정의된 메소드를 하위클래스에서 호출할 수 있다.
    2) 하위클래스의 참조 변수를 통해서 상위클래스의 메소드를 호출할 수 있다.
    3) 상위클래스에 정의된 메소드와 동일한 메소드를 하위클래스에서 정의한 후 호출하면 하위클래스의 메소드가

       우선으로 인식됨.


* 메소드 오버라이딩 : 상위클래스의 메소드선언부를 동일하게 하여 메소드를 정의하는 것.
                           : 메소드를 오버라이딩하는 경우 반드시 메소드 선언부(리턴타입, 매개변수 개수, 매개변수 타입)가

                             상위클래스와 동일해야함.


    4) super를 이용해서 부모의 메소드를 사용할 수 있다.
        super.메소드명();

④ 상속관계에서 생성자의 특징
    1) 모든 클래스의 모든 생성자의 첫 번째 문장은 부모의 기본 생성자를 호출하는 호출문이 생략되어있음. 

        : 부모의 기본생성자를 호출하는 명령문 = super()
        :  this()를 이용해서 자기 자신의 다른 생성자를 호출하는 경우는 기본생성자를 생성하지않음.
     

     2) 모든 클래스의 최상위 클래스는 java.lang.Object 클래스

        자바에서 객체가 갖는 공통의 특징을 Object에 정의해놓고 컴파일러를 통해서 자동으로 상속받음.
        (단, 상속하고 있는 클래스가 없는 경우 - 자바는 하나의 클래스만 상속할 수 있다.)
        class Super extends Object{
         }

 

      3) 상위클래스에 정의되어 있는 멤버변수의 값을 셋팅해야하는 경우 부모에 정의되어 있는 매개변수 있는 생성자를

          직접 호출해서 작업할 수 있다.
          super(매개변수1, ...);

 

- 문자열1.equals(문자열2) => String은 같은 문자열내용이 같더라도 주소값이 다를 수 있으니 equals()를 사용한다.

- static 메소드 : 객체에 의해 값이 달라지지않는 다면 static으로 처리한다.
- 메서드 오버라이딩 : static final private는 오버라이딩 불가.

 

11. 다형성
 1) super타입의 참조변수로 super객체를 접근
    Parent obj1 = new Parent();
    부모타입 변수 = new 부모객체();

 2) sub타입의 참조변수로 sub객체를 접근
    Child obj1 = new Child();
    자식타입 변수 = new 자식객체();

 3) super타입의 참조변수로 sub객체를 접근
    Parent obj3 = new Child();
    부모타입 변수 = new 자식객체()

obj.멤버변수;  => 부모 멤버변수 실행.
obj3.display();  => 부모, 자식 오버라이딩된 메소드일 경우 자식 메소드 실행.
obj3.show();  => 부모에는 없고 자식 메소드일 경우 error.
((Child)obj3).show();  => 단, 참조변수의 타입이 부모타입이지만 실제 생성된 객체가 하위 객체인 경우에는
   명시적으로 하위타입으로 형변환을 해서 접근할 수 있다.

객체의 형변환 : Sub객체는 자동으로 Super타입으로 변환된다.
=> 참조형의 형변환은 상속관계에 있는 경우 상위타입의 변수가 하위타입의 객체를 참조하는 경우 자동으로 형변환됨.
1) 오버라이딩된 메소드가 있는 경우 오버라이딩된 메소드가 우선으로 인식된다.
2) 오버라이딩된 메소드를 빼면 무조건 참조변수의 타입을 기준으로 모든 멤버를 접근할 수 있다.

 4) sub타입의 참조변수로 super객체를 접근(불가)

   Child obj4 = new Parent(); => obj4는 형변환을 할 수 없다. Parent를 Child로 변환해야 하는
   Parent에는 Child정보가 없으므로 변환이 불가능

 5) sub타입의 참조변수 = Super객체를 참조하는 Super타입의 변수 (불가)
    Parent obj1 = new Parent();
    Child obj5 = (Child)obj1;
   -> 명시적으로 캐스팅하면 컴파일러는 속일 수 있다.(단, 상속관계에 있는 경우에만 가능)
   -> 컴파일러는 속였으나 실제 실행될때 obj1이 Parent를 참조하고 있으므로 Child로 타입을 변환할 수 없다.

 6) sub타입의 참조변수 = Sub객체를 참조하는 super타입의 변수
    Parent obj3 = new Child();
    Child obj6 = (Child)obj3;
    obj6.display();  => Child의 메소드
    -> obj3이 parnet타입이지만 실제 참조하는 객체가 Child이므로 Child로 변환이 가능

 

12. 추상클래스 : 미완성된 클래스 즉, 모든 내용이 구현되어 있지 않은 클래스로 완성되지 않았으므로 객체를 생성할 수 없다.
  : 내용이 정의되지 않은 메소드를 갖고 있는 클래스

추상메소드(body가 없는 메소드)
1) 추상메소드를 선언하는 방법
접근제어자 abstract 리턴타입 메소드명(매개변수list.....);
public abstract class 클래스명{ // 추상클래스

public abstract void 메소드명(int a, int b); // 추상메소드
=> 추상메소드를 정의하면 클래스도 미완성된 클래스 즉, 추상클래스가 되므로 클래스 선언부에 반드시 abstract키워드를 추가해야 한다.
}

2) 추상클래스의 특징
- 일반메소드, 추상메소드, 일반멤버변수 모두 정의할 수 있다.
- 추상메소드가 하나라도 있으면 추상클래스이므로 abstract을 클래스 선언부에 추가한다.
- 추상클래스는 객체 생성을 할 수 없다. (상위클래스로 사용할 목적으로 설계)
=> 추상클래스타입 인스턴스명 = new 추상클래스명();  => 불가.
Super s = new Super();
=> 추상클래스타입 인스턴스명 = null;  => 가능.
Super s = null;
=> 추상클래스타입[] 인스턴스명 = new 추상클래스명[index]; => 가능
Super[] s = new Super[3];
- 추상클래스를 상속받은 클래스는 부모의 추상 클래스를 오버라이딩 하지않으면 에러가 발생.
=> Sub가 Super를 상속받으면 Super의 모든 멤버가 Sub의 소유가 된다.
그러므로 Sub는 추상메소드를 갖게 된다.
- abstract클래인 상위클래스가 갖고 있는 추상메소드를 오버라이딩해서 body를 구현

 

13. final 키워드
1) 변수 - 변수를 상수로 정의

public final static int START_VALUE = 2000; //관용적으로 상수는 대문자로 정의 
START_VALUE = 3000; //error. 상수 : 절대 변경되지 않는 값을 저장하는 변수 


2) 메소드 - 오버라이딩 할 수 없는 메소드

class Parent{ 
	public final void 메소드(){ // 부모클래스의 메소드가 final이면 
	} 
}
class Child extends Parent{ 
	public void 메소드(){ // error. 자식 메소드는 오버라이딩 할 수 없다. (보안 목적) 
	} 
} 


3) 클래스 - 상속을 할 수 없는 클래스

final class Parent{ // 부모클래스가 final이면 
	public final void 메소드(){ 
	} 
} 
class Child extends Parent{ // error. final인 클래스는 상속 할 수 없다. (보안 목적) 
	public void 메소드(){ 
	} 
} 



14. interface : 추상메소드와 상수만 정의할 수 있는 클래스
                  : 사용목적은 다형성, 다중상속 구현
                  : 상위클래스로 사용하기 위한 목적
                  : 타입으로 사용하기 위한 목적


1) 인터페이스는 interface키워드를 이용해서 선언
2) 인터페이스는 추상메소드만 정의하는 클래스. 하위클래스에서 상속하고 오버라이딩하면 자동으로 public이 추가되므로 메소드를 정의할 때  public abstract은 생략이 가능

interface 인터페이스명1{ 
    void 메소드명(); //추상메소드 
} 



3) 클래스가 인터페이스를 상속하는 경우 implements키워드를 이용.

class 자식클래스명 extends 부모클래스 implements 인터페이스명1, 인터페이스명2{ 
} 


4) 인터페이스가 인터페이스를 상속하는 경우 extends를 이용.

interface 인터페이스명2 extends 인터페이스명1{ 
} 



5) 인터페이스끼리 다중상속이 가능. 여러 개의 인터페이스를 ,로 연결해서 동시에 상속.

interface 인터페이스명3 extends 인터페이스1, 인터페이스2..{ 
} 


6) 클래스가 인터페이스 다중 상속이 가능. 여러 개의 인터페이스를 ,로 연결해서 동시에 상속
7) 클래스와 인터페이스를 동시에 상속하는 경우 extends가 implements보다 먼저 선언해야한다.

class 자식클래스명 extends 부모클래스명 implements 인터페이스명1, 인터페이스명2 { 
} 


8) 자식 객체로 부모타입 인스턴스에 대입가능.

Interface Parent1{ 
} 

Interface Parent2{ 
} 

class Parent2{ 
} 

class Child extends Parent2 implements Parent1, Parent2{ 
} 
Child obj = new Child(); 
메소드1(obj); 
메소드2(obj); 
메소드3(obj); 

public static void 메소드1(Parent1 obj){ // 부모 인터페이스 인스턴스 
} 
public static void 메소드2(Parent2 obj){ // 부모 인터페이스 인스턴스 
} 
public static void 메소드3(Parent3 obj){ // 부모 클래스 인스턴스 
} 


9) instanceof - 객체가 클래스타입(하위 타입)인지 체크하는 연산자

if(인스턴스 instanceof 클래스타입/인터페이스타입){ // true or false 리턴

}

10) 익명 이너 클래스(Anonymous Inner class) : 클래스명 없이 클래스의 기능을 정의하여 생성.

interface Super{
	void display();
}
			
Super obj2 = new Super() { // 클래스명 implements Super
						   // Super의 하위 클래스를 바로 정의해서 생성 
	public void display() {
	}
};
JFrame f = new JFrame("익명이너클래스 테스트");
JButton btn = new JButton("누르세요");

//이벤트 연결 - 익명클래스를 클래스 안에 바로 정의하고 생성해서 메소드의 매개변수로 전달한 예.
btn.addActionListener(new ActionListener() {
	public void actionPerformed(ActionEvent e) {
		System.out.println("이너클래스로 연결한 이벤트");
	}
});
f.add(btn);
f.setSize(300,300);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

9. 예외처리
① Exception이 발생하는 경우
   1) 개발자가 실수할 수 있는 부분
       1. 0으로 나누는 경우 - ArithmeticException
          10/0

       2. 배열의 index 참조를 잘못한 경우 - ArrayIndexOutOfBoundsException
          args[0]

       3. null인 참조변수를 액세스해서 사용하려는 경우 - NullPointerException
          String str = null;

          str.charAt(0);

 

       4. 캐스팅 잘못한 경우 - ClassCastException
          Super obj = new Super();
          Sub obj2 = (Sub)obj;

   2) 사용자가 실수할 수 있는 부분
       1. 사용자가 잘못된 입력 - InputMismatchException         

int num = key.nextInt(); 

 

      2. API에서 예외처리를 요구하는데 처리하지 않은 경우
          API에서 예외처리를 문법적으로 요구하는 경우
          RuntimeException의 하위 Exception이 아닌 경우 반드시 문법적으로 예외에 대한 처리를 해야한다.
          예외처리를 하지않으면 문법적으로 예외처리를 하도록 오류를 발생시킨다. (컴파일체크오류)       

new String().getBytes("java");
FileInputStream fs = new FileInputStream("test.txt");

 

② try catch catch finally

try{ 
	// 예외발생 가능성이 있는 코드 
	// 예외가 발생되지않으면 catch블록이 실행되지않는다. 
} 
catch(ArithmeticException e){ 
} 
catch(InputMismatchException e) { 
} 
catch(Exception e){ // 상위 Exception에 대한 처리는 가장 마지막 블럭으로 처리한다. 다형성 
	// 예외가 발생되면 처리할 코드 
	// 예외가 발생되면 try블럭이 끝까지 실행되지 못하고 catch가블럭으로 제어가 넘어온다. 
	e.getMessage(); 
	e.printStackTrace(); // 예외발생시 오류발생 클래스와 오류 라인을 출력. 
} 
finally{ 
	//반드시 실행되어야하는 문장 - 메모리해제 
}

 

③ throws 처리 : throw를 이용해서 당장 예외가 발생되는 곳에서 처리하지않고 호출한 곳에서 try catch로 처리해야함

                    : 각각 다른 방법으로 예외를 처리할 수 있다.

public void test(String fileName) throws FileNotFoundException{
	FileInputStream fis = new FileInputStream(fileName); // 예외 발생
}
class A{

	void a(){
		try {
			test("test.txt");
		}
		catch(FileNotFoundException e) {
			// 예외처리 방법 A
		}
	}
}
class B{
	
    void b(){
		try {
			test("test.txt");
		}
		catch(FileNotFoundException e) {
			// 예외처리 방법 B
		}
	}
}
public static void main(String[] args) {
		A obj = new A();
        B obj = new B();
        obj.a();
        obj.b();
}
        

④ 상 하위 관계의 Exception 처리 : 하위의 Exception은 상위 Exception만 처리해도 모두 적용할 수 있다.(객체의 다형성)
                                            :  RuntimeException의 하위 Exception은 throws하지않아도 문법적으로 문제사항이

                                               아니나 명시적으로 모두 처리한다.

public void test() throws ArithmeticException{
	System.out.println(10/0);
}

public void test2() throws ArithmeticException, FileNotFoundException{
	test();
	FileInputStream fis = new FileInputStream("test.txt");
}

public void test3() throws UnknownHostException, IOException, ArithmeticException, FileNotFoundException{
	test2();
	Socket socket = new Socket("127.0.0.1",12345);
}

public void test4() throws IOException{
	test2();
	Socket socket = new Socket("127.0.0.1",12345);
}
// UnknownHostException, FileNotFoundException은 IOException의 하위이므로
// IOException만 처리해도 모두 적용할 수 있다. 

⑤ throw : 새로운 예외를 발생시킨다.

            : try catch로 처리하거나 메소드인 경우 throws를 이용해서 호출하는 곳에서 처리할 수 있도록 넘긴다.

try {
	throw new PasswordCheckException("패스워드가 3번 틀렸습니다.");
}
catch(PasswordCheckException e){
	System.out.println(e.getMessage());
}
catch(IllegalArgumentException e){
	System.out.println(e.getMessage());
}

⑥ 사용자 정의 Exception : Exception을 상속받아 구현한다. 해당 Exception class의 생성자에 매개변수를 전달하여

                                   메시지도 정의 가능하다.

public class TempException extends Exception {
	public TempException(){
	}
	public TempException(String message){
	    super(message);
	}
}

<tip>

 - sysout + ctrl + space => System.out.println();

 - System.out.println() : 빈줄 삽입

 - import 추가 단축키 : ctrl+shift+o

 - break point

        F5 : 함수 안으로 이동.

        F6 : 다음 줄로 이동.

        F7 : 현재 함수 끝까지 실행.

        F8 : 다음 중단점으로.

        F11 : 디버깅 시작

- 명령행 매개변수 (args 사용하기) : 실행창 오른쪽 클릭 - Run as - Run configurations - Arguments Tab - 

                         Proram argument - Variable - string_prompt 선택 - 공백을 기준으로 arg[]배열에 입력될 값 입력.

- setter, getter 자동생성 : Source - Generate setters and getters

- setter, getter 메소드 : Source - Generate setters and getters 

- 생성자 자동생성 : Source - Generate Constructor using fields

bool range(double x_start, double x_end, double y_start, double y_end)
{
	if(x_start <= y_start && x_end <= y_end)
		return true;

	if (y_start <= x_start && y_end <= x_end)
		return true;

	return false;
}

x_start~x_end

y_start~y_end

사이 값 겹치는 값이 존재할 경우 true return;

                              없을 경우 true return;

+ Recent posts

12