5 - Python : class, input, output, module, package, exception

최민규·2023년 1월 6일
0

getter setter

  • 객체의 내부 변수에 접근할때 특정 메서드를 거쳐서 접근할수 있도록 하는 방법
class Person:

    def __init__(self, pw):
        self.hidden_pw = pw
    
    @property
    def pw(self):
        print('getter')
        return self.hidden_pw[:2] + '****'

    @pw.setter
    def pw(self, new_pw):
        print('setter')
        input_pw = input('insert password : ')
        if input_pw == self.hidden_pw:
            self.hidden_pw = new_pw
        else:
            print('wrong password!')
person = Person('abcd')
person.pw = 'qwer'

# Terminal
setter
insert password : abcd
person.pw

# Terminal
getter
qw****
class Person:

    def __init__(self, pw):
        self.hidden_pw = pw

    def getter(self):
        print('getter')
        return self.hidden_pw

    def setter(self, new_pw):
        print('setter')
        input_pw = input('insert password : ')
        if input_pw == self.hidden_pw:
            self.hidden_pw = new_pw
        else:
            print('wrong password!')

    pw = property(getter, setter)
person = Person('abcd')
person.pw

# Terminal
getter
abcd
person.pw = 'qwer'

# Terminal
setter
insert password : abcd
person.pw

# Terminal
getter
qwer
person.hidden_pw = 'qqqq'
person.pw

# Terminal
getter
qqqq

non public mangling

  • 변수에 직접적으로 접근하는것을 막는 방법
  • 사용법 : 변수명 앞에 __ 를 붙임
class Person:

    def __init__(self, pw):
        self.__hidden_pw = pw

    def getter(self):
        print('getter')
        return self.__hidden_pw

    def setter(self, new_pw):
        print('setter')
        input_pw = input('insert password : ')
        if input_pw == self.__hidden_pw:
            self.__hidden_pw = new_pw
        else:
            print('wrong password!')

    pw = property(getter, setter)
person = Person('abcd')
person.__hidden_pw = 'qqqq'
# person.pw
# _Person__hidden_pw
# dir(person)
person._Person__hidden_pw = 'aaaa'
person.pw

# Terminal
getter
aaaa
person.__hidden_pw = 'qqqq' # X
person.pw = 'wwww' # O

# Terminal
setter
insert password : aaaa

메서드의 종류 : instance class static

  • instance method : 파라미터 self / 객체를 이용하여 메서드 호출
  • class method : 파라미터 cls / 클래스를 이용하여 메서드 호출 (객체로 생성된 초기 변수값을 모두 수정)
  • static method : 파라미터 X / 객체를 선언하지 않고 메서드 호출
class Account:

    interest = 1.01 # 이자율 1%

    def __init__(self, asset=10000):
        self.asset = asset

    def __show_asset(self):
        print('total asset', self.asset)

    def deposit(self, amount):
        self.asset += amount
    
    def withdraw(self, amount):
        if self.asset >= amount:
            self.asset -= amount
        else:
            self.__show_asset()

    def add_interest(self):
        self.asset = int(self.asset * self.interest)
        self.__show_asset()

    def change_interest(self, interest):
        if interest < 1.10:
            self.interest = interest
        else:
            print('이자율을 10% 미만으로 설정해주세요.')

    @classmethod
    def cls_change_interest(cls, interest):
        if interest < 1.10:
            cls.interest = interest
        else:
            print('이자율을 10% 미만으로 설정해주세요.')
    
    @staticmethod
    def interest_grade(interest):
        if interest > 1.05:
            print('high interest')
        elif interest > 1.02:
            print('middle interest')
        else:
            print('low interest')
account1 = Account(10000)
account2 = Account(20000)
account3 = Account(30000)
account1.asset, account2.asset, account3.asset,\
account1.interest, account2.interest, account3.interest

# Terminal
(10000, 20000, 30000, 1.01, 1.01, 1.01)
# 인스턴스 메서드 사용
account1.change_interest(1.09)
account1.asset, account2.asset, account3.asset,\
account1.interest, account2.interest, account3.interest

# Terminal
(10000, 20000, 30000, 1.09, 1.01, 1.01)
# 클래스 메서드 사용
# 해당 클래스로 부터 만들어진 객체의 변수를 한꺼번에 변경할때 사용
Account.cls_change_interest(1.04)
account1.asset, account2.asset, account3.asset,\
account1.interest, account2.interest, account3.interest

# Terminal
(10000, 20000, 30000, 1.09, 1.04, 1.04)
# 스태틱 메서드 사용
# 클래스 메서드, 스태틱 메서드 차이 : 클래스 메서드는 클래스의 변수에 접근이 가능
Account.interest_grade(account1.interest)
Account.interest_grade(account2.interest)

# Terminal
high interest
middle interest
ef interest_grade(interest):
    if interest > 1.05:
        print('high interest')
    elif interest > 1.02:
        print('middle interest')
    else:
        print('low interest')

interest_grade(account1.interest)

# Terminal
low interest
dir(account1)[:5]

# Terminal
['_Account__show_asset', '__class__', '__delattr__', '__dict__', '__dir__']
account1.add_interest()

# Terminal
total asset 10100

class 설계 : is a has a

  • is a : A is a B, 상속을 이용해서 클래스 설계
  • has a : A has a B, 객체를 객체에 넣어서 클래스 설계
  • 두가지 방법을 혼용해서 사용
# is a
class Info:
    def __init__(self, name, email):
        self.name = name
        self.email = email
class Person(Info):
    def show(self):
        print(self.name, self.email)
person = Person('peter', 'peter@gmail.com')
person.name, person.email

# Terminal
('peter', 'peter@gmail.com')
# has a
class Name:
    def __init__(self, name):
        self.name_str = name

class Email:
    def __init__(self, email):
        self.email_str = email
class Person:
    def __init__(self, name_obj, email_obj):
        self.name = name_obj
        self.email = email_obj
    def show(self):
        print(self.name.name_str, self.email.email_str)
name_obj = Name('peter')
email_obj = Email('peter@gmail.com')
person = Person(name_obj, email_obj)
person.show()

# Terminal
peter peter@gmail.com

입출력 : input output

  • RAM → SSD(HDD), RAM ← SSD(HDD)
  • RAM → 직렬화(byte()) → SSD(HDD)
  • pickle : 직렬화, 입출력 속도 빠름
class Msg:
    def __init__(self, data):
        self.data = data
msg = Msg('AI School')
msg.data

# Terminal
AI School
import pickle
# RAM > SSD
with open('msg.pkl', 'wb') as file:
    pickle.dump(msg, file)
%ls
# Terminal
msg.pkl  sample_data/
# RAM < SSD
with open('msg.pkl', 'rb') as file:
    load_msg = pickle.load(file)
load_msg.data

# Terminal
AI School
# 입출력 사용 X
# 학습 데이터 > 모델링(학습:8h) > 모델객체(RAM) > 예측
# 학습 데이터 > 모델링(학습:8h) > 모델객체(RAM) > 예측
# 학습 데이터 > 모델링(학습:8h) > 모델객체(RAM) > 예측

# 입출력 사용 O
# 학습 데이터 > 모델링(학습:8h) > 모델객체(RAM) > 모델저장(SSD) > 예측
# 모델로드(SSD > RAM:5min) > 예측
with open('sales.pkl', 'rb') as file:
    data = pickle.load(file)
data.keys()

# Terminal
dict_keys(['meeting_count', 'meeting_time', 'sales'])
# 상관계수 구하기
import numpy as np
np.corrcoef(data['meeting_count'], data['sales'])[0, 1],\
np.corrcoef(data['meeting_time'], data['sales'])[0, 1]

# Terminal
(0.7822244248616061, 0.22829902637616528)
# 모델링 : 미팅 횟수, 미팅 시간으로 매출을 예측 모델
import pandas as pd
features = pd.DataFrame({
    'meeting_count': data['meeting_count'],
    'meeting_time': data['meeting_time'],
})
target = data['sales']
features[:2]

# Terminal

from sklearn.linear_model import LinearRegression
model = LinearRegression().fit(features, target)
type(model)

# Terminal
sklearn.linear_model._base.LinearRegression
model.predict([[230.1, 69.2]]), target[0]

# Terminal
/usr/local/lib/python3.8/dist-packages/sklearn/base.py:450: UserWarning: X does not have valid feature names, but LinearRegression was fitted with feature names
  warnings.warn(
(array([19.62690144]), 22.1)
# RAM > SSD
with open('model.pkl', 'wb') as file:
    pickle.dump(model, file)
%ls

# Terminal
model.pkl  msg.pkl  sales.pkl  sample_data/
# SSD > RAM
with open('model.pkl', 'rb') as file:
    load_model = pickle.load(file)
import warnings
warnings.filterwarnings('ignore')

load_model.predict([[100, 10]])

# Terminal
array([10.9072636])

모듈, 패키지

  • 모듈 : 변수, 함수, 클래스를 하나의 파일(.py)로 모아서 코드 작성
  • 패키지 : 여러개의 모듈 파일을 디렉토리로 구분하여 코드를 작성하는 방법 (버전정보 포함)
# 모듈 만들기

%%writefile ai_school.py
data = 'python'

def echo(msg):
    print('ai school : ', msg)

# Terminal
Writing ai_school.py
%ls

# Terminal
Writing ai_school.py

모듈 사용 : import from as

import ai_school
%whos

# Terminal
Variable    Type      Data/Info
-------------------------------
ai_school   module    <module 'ai_school' from '/content/ai_school.py'>
%cat ai_school.py

# Terminal
data = 'python'

def echo(msg):
    print('ai school : ', msg)
ai_school.data

# Terminal
python
ai_school.echo('fighting!')

# Terminal
ai school :  fighting!
import ai_school as ais
print(ais.data)
ais.echo('fighting!')

# Terminal
python
ai school :  fighting!
import numpy as np
import pandas as pd
%reset

# Terminal
Once deleted, variables cannot be recovered. Proceed (y/[n])? y
from ai_school import echo

from ai_school import data, echo

from ai_school import *
%whos

# Terminal
Variable   Type        Data/Info
--------------------------------
data       str         python
echo       function    <function echo at 0x7f1f7cc7a310>
echo('fighting!')

# Terminal
ai school :  fighting!
%cat ai_school.py

# Terminal
data = 'python'

def echo(msg):
    print('ai school : ', msg)

패키지

  • 여러개의 모듈을 디렉토리로 구분해서 코드를 작성
  • tree : 디렉토리의 구조를 출력하는 우분투(OS) 패키지 (!apt-get install tree -y)
  • 패키지 구조 만들기
    • mkdir : 디렉토리 만들기
    • -p : 상위 디렉토리 만들면서 디렉토리를 만들기
    • touch : 빈파일 생성
!rm -rf stock
!mkdir -p stock/kor
!mkdir -p stock/usa
!touch stock/__init__.py
!touch stock/kor/__init__.py
!touch stock/usa/__init__.py
!tree stock

# Terminal
stock
├── __init__.py
├── kor
│   └── __init__.py
└── usa
    └── __init__.py

2 directories, 3 files
# 모듈파일 추가

%%writefile stock/kor/kospi.py
def crawl_kospi():
    print('crawl_kospi')

# Terminal
Writing stock/kor/kospi.py
%%writefile stock/kor/kosdaq.py
def crawl_kosdaq():
    print('crawl_kosdaq')

# Terminal
Writing stock/kor/kosdaq.py
%%writefile stock/usa/snp500.py
def crawl_snp500():
    print('crawl_snp500')

# Terminal
Writing stock/usa/snp500.py
%%writefile stock/usa/nasdaq.py
def crawl_nasdaq():
    print('crawl_nasdaq')

# Terminal
Writing stock/usa/nasdaq.py
!tree stock

# Terminal
stock
├── __init__.py
├── kor
│   ├── __init__.py
│   ├── kosdaq.py
│   └── kospi.py
└── usa
    ├── __init__.py
    ├── nasdaq.py
    └── snp500.py

2 directories, 7 files
# import 패키지

from sklearn.linear_model import LinearRegression

import stock.kor.kospi

stock.kor.kospi.crawl_kospi()

import stock.kor.kospi as skk

skk.crawl_kospi()

# Terminal
crawl_kospi
from stock.kor import kospi

kospi.crawl_kospi()

# Terminal
crawl_kospi

__init__.py

  • 패키지에 있는 디렉토리의 모듈을 설정하는 파일
  • __init__.py python 3.x 버전부터는 쓰지 않아도 괜찮음
  • 하위버전 호환성 때문에 써주는 것이 좋긴 함
%%writefile stock/kor/__init__.py
__all__ = ['kospi']

# Terminal
Overwriting stock/kor/__init__.py
# 모듈이나 패키지 코드를 수정하면 런타임 다시시작을 해야 적용

from stock.kor import *

%whos

# Terminal
Variable   Type      Data/Info
------------------------------
kospi      module    <module 'stock.kor.kospi'<...>tent/stock/kor/kospi.py'>
# defaul package path
import random

import sys

for path in sys.path:
    print(path)

# Terminal
/content
/env/python
/usr/lib/python38.zip
/usr/lib/python3.8
/usr/lib/python3.8/lib-dynload

/usr/local/lib/python3.8/dist-packages
/usr/lib/python3/dist-packages
/usr/local/lib/python3.8/dist-packages/IPython/extensions
/root/.ipython
# !ls /usr/lib/python3.8
# defaul packages

# !ls /usr/local/lib/python3.8/dist-packages
# installed packages
!pip list | grep pandas

# Terminal
pandas                        1.3.5
pandas-datareader             0.9.0
pandas-gbq                    0.17.9
pandas-profiling              1.4.1
sklearn-pandas                1.8.0
# 패키지 설치 파일 만들기

!rm -rf stock
!mkdir -p stock/stock/kor
!mkdir -p stock/stock/usa
%%writefile stock/stock/kor/kospi.py
def crawl_kospi():
    print('crawl_kospi')

# Terminal
Writing stock/stock/kor/kospi.py
%%writefile stock/stock/kor/kosdaq.py
def crawl_kosdaq():
    print('crawl_kosdaq')

# Terminal
Writing stock/stock/kor/kosdaq.py
%%writefile stock/stock/usa/snp500.py
def crawl_snp500():
    print('crawl_snp500')

# Terminal
Writing stock/stock/usa/snp500.py
%%writefile stock/stock/usa/nasdaq.py
def crawl_nasdaq():
    print('crawl_nasdaq')

# Terminal
Writing stock/stock/usa/nasdaq.py
!tree stock

# Terminal
stock
└── stock
    ├── kor
    │   ├── kosdaq.py
    │   └── kospi.py
    └── usa
        ├── nasdaq.py
        └── snp500.py

3 directories, 4 files
# setup.py 파일 생성

%%writefile stock/setup.py
from setuptools import setup, find_packages

setup(
    name='stock',
    version='0.0.1',
    author='ai_school',
    author_email='ai_school@likelion.net',
    packages=find_packages(),
    include_package_data=True,
)

# Terminal
Overwriting stock/setup.py
# __init__.py 설정

%%writefile stock/stock/__init__.py 
from .kor.kosdaq import crawl_kosdaq
from .kor.kospi import crawl_kospi
from .usa.nasdaq import crawl_nasdaq

# Terminal
Writing stock/stock/__init__.py

디렉토리 이동

  • ./ : 현재 디렉토리 (생략가능)
  • ../ : 상위 디렉토리
  • ~/ : 현재 로그인 되어있는 계정의 최상위 디렉토리
!tree stock

# Terminal
stock
├── setup.py
└── stock
    ├── __init__.py
    ├── kor
    │   ├── kosdaq.py
    │   └── kospi.py
    └── usa
        ├── nasdaq.py
        └── snp500.py

3 directories, 6 files
# 만든 패키지 설치
# -e 옵션 : 개발자 모드 옵션 : 패키지 설치 후에 코드를 수정해도 수정된 코드가 적용
!pip install -e stock

# Terminal
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/
Obtaining file:///content/stock
  Preparing metadata (setup.py) ... done
Installing collected packages: stock
  Running setup.py develop for stock
Successfully installed stock-0.0.1
!pip list | grep stock

# Terminal
stock                         0.0.1                  /content/stock
# colab에서는 uninstall, 설치된 패키지 사용 동작 X

예외처리

  • 코드의 에러를 처리하는 방법, 문법
  • try except finally raise

try

# try

try:
    print(1/0)
except Exception as e:
    print(e)
print('python')

# Terminal
division by zero
python
try:
    print('connet database') # 리소스 사용
    print(1/0)
except Exception as e:
    print(e)
finally: # try 구문에 에러가 있던 없던 항상 코드 실행하는 구문
    print('disconnect') # 리소스 반납
print('python')

# Terminal
connet database
division by zero
disconnect
python

raise

  • 강제로 에러 발생시키기
# 에러만들기
class LowNumber(Exception):
    def __str__(self):
        return 'insert number grater then 10!'

# 함수의 파라미터에 10이하의 데이터가 넘어오면 에러(LowNumber)발생
def input_number(number):
    if number <= 10:
        raise LowNumber()
    print(number)

input_number(5)

# Terminal
---------------------------------------------------------------------------
LowNumber                                 Traceback (most recent call last)
<ipython-input-46-68e5aa26cfd6> in <module>
----> 1 input_number(5)

<ipython-input-44-71eab23d1c38> in input_number(number)
      2 def input_number(number):
      3     if number <= 10:
----> 4         raise LowNumber()
      5     print(number)

LowNumber: insert number grater then 10!
profile
안녕

0개의 댓글