본문 바로가기

대외활동/ABC 지역주도형 청년 취업역량강화 ESG 지원산업

[220823 ABC - 6일차] PYTHON 기초

반응형

[ 0822 복습 ]

- 전역변수와 지역변수

def fun_abc() :
    a = 10
    
fun_abc()

 : 사용자 정의 함수 내부에 선언된 a는 밖에 나와서는 의미있는 변수가 아니라 fun_abc()의 함수가 종료되면 사라지는 변수이다.

 

[ 사용자 정의 함수 ]

- 외부 함수를 호출해 수행을 완료하면 함수 안에 선언된 모든 지역변수의 생명주기는 마무리된다.

- 외부 함수에 있는 내부 변수들을 계속 유지할 수 있도록 도와주는 것에 클로저(closure)라는 것이 있다.

- 내부 함수의 변수값을 해당 함수 외부에서도 계속해서 참조할 수 있게 도와준다.

def outer():
    count = 0
    
    def inner() :
        nonlocal count 
        count += 1
        return count
    
    return inner 
    
var1 = outer()
print(var1()) # 출력결과 : 1
print(var1()) # 출력결과 : 2


var2 = outer() # 새로운 변수값으로 선언했을 경우는 처음부터 다시
print(var2())
print(var2())
print(var2())
print(var2())

print(var1())
#var1과 var2의 변수는 별도의 다른 값을 저장해주고 있는 것이다.

 : return inner 는 클로저, 내부함수의 주소를 반환한다. 이 명령어는 outer 함수에 종속되어 있다.(inner라고 헷갈리지 말자) outer함수 내부의 코드를 살펴보자. count 변수가 계속 저장되어 있는 상태가 유지된다. 그래서 출력결과에 반영됨. 외부 함수 안에 있는 내부 함수의 변수 값을 외부 함수에서도 참조할 수 있게 해주는 것이다.

 

def outer(tax) :
    def inner(num, danga) :
        amount = (num*danga)*tax
        return amount
    return inner

q1 = outer(0.1)
print("결과1 : ", q1(5, 10000)) 

q2 = outer(0.05)
print("결과 : ", q2(5,10000))

: 위의 코드블럭을 한번 살펴보자. q1의 변수에 outer(tax)를 입력하고 print문 안에 q1(num, danga)의 함수형태를 입력해준다. outer(tax)로 0.1과 0.05ㄹ를 줘서 q1, q2의 변수를 만들어준다. 그 후, q1, q2의 변수에 num과 danga인자를 넣어서 함수를 출력해준다. 사용자 정의 함수를 종속되게 만들 때 외부함수에 <return 내부함수>를 입력하면 내부함수의 변수를 계속 참조할 수 있게 도와준다.

 

[ 람다 함수 ]

- 람다함수는 람다 대수에서 유래되었다. 람다란 축약 함수 또는 익명 함수라고 한다.

- 이름이 없는 함수이고, return문 없이 결과를 반환하는 단순구조로 되어있다.

from distutils.command.config import LANG_EXT

def plus(x) :
    return x+10
    
# 람다함수버전
lambda x : x+10
# 이때 5행과 6행의 함수와 9행의 함수가 동일하다.

abc = lambda x,y, : x+y
print(abc(10, 20)) # 출력결과 30이 출력된다.

 : for문과 if문의 삼항연산자와 비슷한 개념이라고 생각하면 됨.

 

- 람다함수 역시 가변인수를 지정할 수 있다.

xyz = lambda a, *b : print(a, b)

xyz(5, 2, 3, 4, 5, 6)

 : 위의 코드 블럭을 살펴보자. a인자는 값을 하나만 받을 수 있으니까 5가 출력되고, b는 가변인자로 여러 값을 받을 수 있기 때문에 5를 제외한 모든 값이 b의 값이 된다.

 

- 람다함수도 딕셔너리 지정이 가능하다.

opq = lambda a, *b, **c : print(a,b,c)

opq(5,2,3,4,5,6,o=3,p=2,v=6,h=1)

 : 위의 코드블럭을 살펴보자. **는 딕셔너리를 의미한다. opq의 함수에서는 5는 a가, 2,3,4,5,6은 b가 가져가고 있다. c는 딕셔너리 타입으로 o=3, p=2, v=6, h=1를 가져가고 있는 것이다.

 

[ 재귀함수 ]

- 수행중인 함수 내에서 자기 자신을 다시 호출하는 패턴을 가진 함수

- 반복문은 속도나 메모리 점유면에서 유리하지만 코드를 작성하면 지저분해질 수 있다. 이런 측면에서 재귀함수는 코드를 간결하게 만들어줄 수 있다.

def func1(n) :
    if n == 0 :
        print(" 종료 ")
    else : 
        print(n, end = ' ')
        func1(n-1) 
        
func1(10)

 : 위의 코드 블럭을 살펴보자. if - else 문 마지막에 자기 자신을 다시 참조한다. 이를 재귀처리라고 하는데 마치 for문처럼 반복문의 역할을 한다. func1(10) 으로 함수를 호출하면 0이 되어서 종료가 출력될 때 까지 계속 반복해서 함수를 호출한다.

- 다른 예문을 살펴보자.

def fun_sum(n) :
    print(n)
    if n == 1 : # 무한루프 탈출을 위한 탈출조건 지정
        print("종료")
        return True # True가 없으면 잘못된 반복실행을 한다.
    return n+fun_sum(n-1)

re = fun_sum(10)
print(re)

 

[ 모듈(module) ]

- 모듈은 변수, 함수, 클래스, 명령문으로 구성되며, 보조기억장치에 저장되어 사용된다.

- 모듈은 하나의 물리적인 파일이다.

- 라이브러리 vs 패키지 vs 모듈

    1. 라이브러리 : 여러개의 모듈이나 패키지의 묶음을 지칭

    2. 패키지 : 성격이 유사한 여러개의 모듈이 저장된 폴더

    3. 모듈 : 특정 기능으로 구성된 파일

- import문을 사용하여 모듈을 메모리로 로딩한다.

- 기본적으로 설치되어 있는 것들은 import했을 때 에러 안남(설치 안되어있으면 에러가 발생)

import calendar as ca

ca.setfirstweekday(6) # 일요일을 첫 요일로 설정(첫 요일을 무엇으로 지정할거야?)
ca.prmonth(2022,8) # 달력을 만들어줌(해당 년도 월의 달력을 출력)
print()

import math

print(math.pi) # 원주율 출력
print(math.sin(math.radians(30))) # 라디언 30의 sin값을 출력

import sys # 현재 모듈이 있는 폴더 위치 경로 설명

print(sys.path) 

del math # 메모리에서 해당 모듈을 삭제해준다.
print(math.pi) # 메모리에서 삭제되었으니까 출력 안되고 오류뜬다.

 

- os 모듈

print(os.getcwd()) # 작업경로 폴더 위치를 확인해주는 함수

# 작업폴더 설정
os.chdir("d:/P.exam/")

print(os.getcwd()) 
# 위의 os.chdir("d:/P.exam/") 의 명령문으로 인해 경로가 바뀐 것을 확인할 수 있다

print(os.listdir("d:/P.exam/")) 
# 해당 폴더에 어떤 파일이 있는지 확인하는 것이 가능(파일 확인)

print(len(os.listdir("d:/P.exam/"))) 
# 몇개의 파일이 있는지 확인한다.

 

<import 모듈>

- 모듈 안에 들어있는 모든 함수를 표출한다.

- os모듈에는 chdir, getswd, listdir 등의 함수가 들어있다는 것을 알 수 있다.

- 프로그램 안에서 해당 함수를 사용하기 위해서는 모듈, 함수의 형식으로 '모듈 이름'을 앞에 반드시 써준다.

- from 모듈 import 함수1, 함수2, ...

- 모듈안에 들어있는 것들 중 필요한 함수만을 골라서 호출한다.

- 모듈 이름 없이 함수 이름만 갖고 사용이 가능하다

 

<import 모듈 as 별명>

- 모듈이름을 새로운 이름(별명)으로 변경해준다.

- 쉽게 사용 가능하고, 이름의 충돌도 피해준다

- 예를들어 abc모듈 open()함수, def 모듈 open()

 

<from 모듈 import 함수 as 별명>

- 모듈 안에 있는 함수의 이름을 변경할 수 있다.

- 긴 이름의 함수들에 대해서 쉽게 이용할 수 있다.

from os import getcwd, listdir

 : 위의 코드블럭을 살펴보자. os 모듈의 getcwd(), listdir()함수만 사용하겠다는 의미이다.

 

- 외부모듈 설치

! pip install xlrd

 : import xlrd를 하면 에러가 날 경우, 내부에 xlrd모듈이 설치되어있지 않기 때문에 발생하는 에러이다. 외부에 잇는 모듈 라이브러리를 설치할 경우 위와 같은 코드를 사용한다. 단, 터미널에서 사용할 경우는 pip install 라이브러리명 의 코드를 사용하고 Jupyter에서 설치할 경우는 ! pip install 라이브러리명 의 코드를 사용해서 설치한다.

 

- 사용자 정의 모듈 작성 및 읽기 : 우리만의 모듈을 만들어보자!

import sys
sys.path.append(r"d:/P.exam/")

pi = 3.14592

def num_input() :
    output = input("숫자입력 >>>>> ")
    return float(output)

def get_circumference(radius) :
    return 2*pi*radius

def get_circle_area(radius) :
    return pi*radius*radius

print()
print("현 모듈명 : ", __name__)
print("get_circumference(10) : ", get_circumference(10))
print("get_circle_area(10) : ", get_circle_area(10))
print()

 : 이렇게 작성 후 다른이름으로 파일을 저장했다. test_m2.py파일로 저장함.

- 사용자 정의 모듈을 불러와서 사용해보자.

import sys
sys.path.append(r"d:/P.exam/")

import test_m2 as test
# 사용자 정의 모듈인 test_m2 모듈을 가져왔다.

print("__현 모듈명__ : " , __name__)
# 현 모듈명이 뭐냐 라는 것을 __name__으로 확인한다. (현재 위치가 어디니 라고 묻는 것)
# 사용자 정의 모듈에서 실행하는 것이 아니라 현재 위치인 main에서 그냥 test_m2 모듈의 함수를 끌어와서 사용하는 것
print()

radius = test.num_input()
print(test.get_circumference(radius))
print(test.get_circle_area(radius))

 : 위의 코드블럭을 살펴보자. 이처럼 모듈을 만들어서 배포하는 것이 가능하다. 모듈을 만들어서 배포하는 이유는 각 회사마다 알맞는 패키지를 만들어서 판매하는 것이다. 이러한 것들로 인해 파이썬이 확장성이 있다고 말한다. 소스 코드를 다 주는 것이 아닌 파일만 주면 사용할 수 있다는 것이다. ( 모듈을 암호화 시켜서 파일만 주면 그 모듈을 사용할 수 있지만 코드 노출에서 오는 위험성은 적어진다.

 

[ GUI 파일 띄우기 ]

from tkinter import *
# ikinter라는 라이브러리에 * 를 가져와서 사용
import os
print(os.getcwd())
os.chdir(r"d://P.exam/")

window = Tk()

photo = PhotoImage(file='rmfla.gif')
# PhotoImage()함수는 jpg, bmp 파일을 지원하지 않는다.
label1= Label(window, image=photo)
bu1 = Button(window, text="파이썬 종료", fg='red', command=quit)

label1.pack()
bu1.pack()
window.mainloop() # 창을 띄워주는 함수
from tkinter import *

import os
print(os.getcwd())
os.chdir(r"d://P.exam/")

window = Tk()

ph = PhotoImage(file='rmfla.gif')
label1= Label(window, image = ph)
bu1 = Button(window, text="파이썬 종료", fg='red', command=quit)

mainMenu = Menu(window)
window.config(Menu = mainMenu)

fileMenu = Menu(mainMenu)
mainMenu.add_cascade(label="파일", menu=fileMenu)
mainMenu.add_cascade(label="열기", command = func_open)
mainMenu.add_cascade(label="종료")


label1.pack()
bu1.pack()
window.mainloop() # 창을 띄워주는 함수

 

[ 중간 정리 ] 

1. 파이썬 설치

2. 변수의 개념 - 대소문자 구분

3. print()

4. ~~~()로 되어있는 것을 함수라고 부른다. ()안에는 인자값 또는 매개변수를 입력한다.

5. print() 출력을 해주는 함수, 여기에 서식을 지정하는 것이 가능하다.

    : .format, r, f => print(f"반갑다 {name}, 나이가 {age}세 맞지")

    : strip, upper, lower

6. input() 함수 : 입력받기

7. 입력을 할 때 정수형, 실수형, 문자형, bool 이런걸 메모리 때문에 별도로 구분해서 변수타입을 지정한다.

8. a = 10, 여러개를 데이터에 저장?

   : 리스트, 튜플, 세트, 딕셔너리 등 데이터를 저장하는 타입을 배움

9. 각 데이터를 확인하거나 별도로 추출하는 기능 : 인덱스, 슬라이싱을 이용한다.

10. 제어문 : 조건문 if문, 반복문 while, for문

      - 삼항연산자를 사용해서 간단하게 사용하는 방법도 있음

11. 사용자 정의 함수 def

      - 클로저 closure

      - 람다함수

      - 재귀함수

12. 새로운 패키지를 설치해서 사용하는 모듈 import

      - 사용자 정의 모듈

13. 작업폴더 설정

 

[ 객체지향과 클래스 ]

- 파이썬은 함수 중심적 언어이다. 그러면서도 객체지향 프로그래밍 표준 기능을 제공하여 클래스의 포함과 상속 메커니즘을 지원한다

- 객체를 이해하고 만들어보자.

   예) 학생 리스트를 만들어보자

st_list = [
    {"이름" : "유재석", "통계" : 87, "파이썬" : 92, "엑셀" : 85, "메타버스" : 90},
    {"이름" : "지석진", "통계" : 29, "파이썬" : 49, "엑셀" : 95, "메타버스" : 99},
    {"이름" : "김종국", "통계" : 38, "파이썬" : 20, "엑셀" : 15, "메타버스" : 80},
    {"이름" : "하동훈", "통계" : 87, "파이썬" : 39, "엑셀" : 36, "메타버스" : 79},
    {"이름" : "송지효", "통계" : 90, "파이썬" : 82, "엑셀" : 39, "메타버스" : 20},
    {"이름" : "전소민", "통계" : 77, "파이썬" : 92, "엑셀" : 19, "메타버스" : 83}
]

print("성명", "총점", "평균", sep="\t")

for stt in st_list :
    s_sum = stt["통계"] + stt["파이썬"] + stt["엑셀"] + stt["메타버스"]
    s_avg = s_sum / 4
    
    print(stt["이름"], s_sum, s_avg, sep="\t")

 : st_list 에는 이름, 통계, 파이썬, 엑셀, 메타버스라는 키로 각각의 값들을 저장했다. 딕셔너리의 형태로 학생을 표현하고 이를 리스트의 형태로 묶어서 학생들의 전체를 구현하였다. 이처럼 여러가지 속성을 구성하는 형태를 우리는 객체라고 한다. 즉, 여기서는 학생들이 객체라고 볼 수 있다. 여기서 중요한 것은 이름, 통계,파이썬, 엑셀, 메타버스에서 각각의 유재석, 지석진, 김종국, 하동훈, 송지효, 전소민이 각각의 데이터를 갖고 있는데 이 자체가 중요한게 아니라 객체 내의 내용을 사용해서 총점과 평균을 구했다는 점이다.  왜 이걸 하냐? => 코드의 오류를 지우거나 최소화한다. 그리고 간편함 즉, 관리의 편리함을 위해서 만든다.

 

-다시한번 객체를 생성해보자

def cre_St(name_v1, a_v2, b_v3, c_v4, d_v5) :
    return {
        "이름" : name_v1,
        "통계" : a_v2,
        "파이썬" : b_v3,
        "엑셀" : c_v4,
        "메타버스" : d_v5
    }
    
st_list = [
    cre_St("유재석",87,92,54,16),
    cre_St("지석진",30,23,49,28),
    cre_St("김종국",87,92,16,34),
    cre_St("하동훈",87,54,16,34),
    cre_St("송지효",92,54,16,34),
    cre_St("전소민",92,54,16,34)
]

print("성명", "총점", "평균", sep="\t")

for stt in st_list :
    s_sum = stt["통계"] + stt["파이썬"] + stt["엑셀"] + stt["메타버스"]
    s_avg = s_sum / 4
    
    print(stt["이름"], s_sum, s_avg, sep="\t")

 : 이렇게 만드는 것이 학생에 대한 객체를 증가시키면서 쉽게 만들 수 있다. 사용자 정의 함수를 만들어 놓고 학생 리스트를 만들어서 이름과 숫자만 넣어서 전달해주면서 학생리스트를 만들고 있다.

 

[ 클래스(class) ]

- 객체를 조금 더 효율적으로 생성하기 위해서 만들어진 구문이다.

class Car: 
    pass

class Dog:
    pass

class Cat:
    pass

car1 = Car()
car2 = Car()
car3 = Car()

my_dog = Dog()
yr_dog = Dog()

# 클래스를 통해서 할 수 있는게 뭘까 다시 한번 생각해보자
class k_u : # 위에서 만들었는데 아래 또 만들었다? => 클래스 재생성
    aa = "예술대학"
    accel = 3.0
    mpg = 25
    
car1 = k_u()
car2 = k_u()

 : car1 = Car() 라는 코드는 클래스를 통해서 인스턴스를 여러개 생성하는 것이다. 

 

- 변수명을 만드는데 있어서 규칙이 있다. 

1. 변수명은 띄어쓰기가 불가능하다

2. 스네이크 케이스 vs 캐멀 케이스

   : 스네이크 케이스 - 소문자로 시작하는 변수명

     1) 뒤에 괄호가 있다? => print(), input() ==> 함수

     2) 뒤에 괄호가 없다? => print, input ==> 변수

   : 캐멀 케이스 - 대문자로 시작하는 변수명 => 대문자로 시작한다? ==> 클래스

 

- 클래스는 전체를 수정하는 것이 아니라 객체별로 수정하고 싶은 부분만 수정하는 것이 가능하다.

- 한 클래스에서 객체를 만들어내는 과정을 인스턴스화라고 한다

class Car : 
    accel = 3.0
    mpg = 25

car1 = Car()
car2 = Car()
my_car = Car()
yr_car = Car()

my_car.accel = 5.0

print(car1.accel)
print(car2.accel)
print(my_car.accel)
print(yr_car.accel)
class Car :
    pass

my_car = Car()
yr_car = Car()

my_car.name = "슈퍼 전기차"
my_car.brand = "코리아 슈퍼카 회사"
my_car.age = 2022

print("내 자동차의 브랜드 및 연식은 {} and {}".format(my_car.brand, my_car.age))
# print("너의 자동차의 브랜드 및 연식은 {} and {}".format(yr_car.brand, yr_car.age))
# yr_car에는 속성값을 지정해주지 않았기 때문에 에러가 발생하게 된다.

- python의 인스턴스(객체) 변수는 클래스 안에서 직접 생성되지 않는다.

- 대신, 필요할 때마다 바로 생성되거나 __init__ 이라는 메소드 안에서 생성된다.

class Korea_student :
    def __init__(self, name, a, b, c, d) : # 클래스 생성자
        self.이름 = name
        self.통계 = a
        self.파이썬 = b
        self.엑셀 = c
        self.메타버스 = d
    
    def __del__(self, name, a, b, c, d): # 클래스 소멸자
        self.이름 = name
        self.통계 = a
        self.메타버스 = d
        
# 학생리스트
st_list = [
    Korea_student("유재석",87,92,54,16),
    Korea_student("지석진",30,23,49,28),
    Korea_student("김종국",87,92,16,34),
    Korea_student("하동훈",87,54,16,34),
    Korea_student("송지효",92,54,16,34),
    Korea_student("전소민",92,54,16,34)
]

# 객체에 속성을 접근하는 방법
print(st_list[0].이름)
print(st_list[4].이름)

 : 클래스 내부의 함수는 첫번째 매개변수로 반드시 self를 입력해야 한다. self는 자기 자신을 나타내는 딕셔너리이다. self 이름 형태로 접근하는 방식이다. (하나의 인자값이 아니다)

 

[ 클래스 메소드(Class method) ]

- 메소드는 클래스가 가지고 있는 함수를 말한다.(사용자가 만들 수 있음)

- 클래스 메소드는 클래스 정의문 안에서 정의된다.

- self라고 불리는 이름으로 첫번째 인자값을 추가해야한다.

- 메소드 안에서 메소드가 속한 객체 자체는 항상 self로 참조해야 한다.

- 객체(인스턴스) 변수는 self.변수이름 으로 참조할 수 있다.

class Pretty :
    
    def __init__(self, prefix) :
        self.prefix = prefix
    
    def print_me(self, a, b, c) :
        print(self.prefix, a, sep="")
        print(self.prefix, b, sep="")
        print(self.prefix, c, sep="")
        

printer = Pretty('--> ')
printer.print_me(10, 20, 30)

 

class K_st:
    def __init__(self, name, a, b, c, d) :
        self.이름 = name
        self.통계 = a
        self.파이썬 = b
        self.엑셀 = c
        self.메타버스 = d
        
    def get_sum(self): # get_sum()의 함수로서 역할을 해주고 있다.
        return self.통계 + self.파이썬 + self.엑셀 + self.메타버스
    
    def get_avg(self): # get_avg()의 함수로서 역할을 해주고 있다.
        return self.get_sum()/ 4
    
    def to_string(self):
        return "{}\t{}\t{}".format(self.이름,self.get_sum(), self.get_avg())
    
st_list = [
    K_st("유재석",87,92,54,16),
    K_st("지석진",30,23,49,28),
    K_st("김종국",87,92,16,34),
    K_st("하동훈",87,54,16,34),
    K_st("송지효",92,54,16,34),
    K_st("전소민",92,54,16,34)
]

print("성명", "총점", "평균", sep="\t")

for sst in st_list:
    print(sst.to_string()) # to_string()함수만 꺼내서 본다.

- 즉, 클래스에서는 변수를 만들 수 없으니까 __init__를 만들어서 변수를 만들어줄 수 있다. 단, self라는 인자를 맨 앞에 넣어야 한다.(자기 자신을 지칭)

- 클래스를 쓰는 이유는 뭐다? ==> 객체를 효율적으로 생성하기 위해서, 변수 관리나 통합 관리를 쉽게 처리하기 위해서 사용한다.(데이터 관리의 편의성)

- 코드를 쉽게 사용하고 균형있게 관리하기 위해서!

 

[ 클래스의 포함관계 ]

- 특정 클래스 내에서 해당 클래스 멤버처럼 다른 클래스 타입을 선언해 사용하는 것을 말한다.

class Poham_h :
    quantity = 0
    
    def leftturn(self, quantity) :
        self.quantity = quantity
        return "좌회전"
    
    def rightturn(self, quantity) :
        self.quantity = quantity
        return "우회전"
    
class Poham_Car:
    Turnshow = "정지"
    
    def __init__(self, ownername) :
        self.ownername = ownername
        self.handle = Poham_h() # 클래스를 포함한다
        
    def turnhandle(self, q):
        
        if q > 0 :
            self.Turnshow = self.handle.rightturn(q)
        elif q < 0:
            self.Turnshow = self.handle.leftturn(q)
        elif q == 0:
            self.Turnshow = "직진"

k_car = Poham_Car("KOREA_CAR")
k_car.turnhandle(10)
print(k_car.ownername + "의 회전량은 " + k_car.Turnshow + " " + str(k_car.handle.quantity))

 

[ 클래스 상속 ]

- 상위 클래스의 것들을 하위 클래스가 받아서 사용할 수 있다.

class Animal :
    def move(self) :
        print("움직이는 동물")
        
class Dog(Animal) : # Animal 클래스를 상속받음
    def my(self) : 
        print("나는 강아지")
        
dog1 = Dog()
dog1.my()
dog1.move()
print()

class Horse(Animal):
    pass

horse1 = Horse()
horse1.move()

 ※ 포함은 동등한 관계에서 서로 받아서 사용하는 것이고 상속은 상위 클래스의 것들을 하위 클래스가 받아서 사용하는 것이다. ※

반응형