카테고리 없음

TIL(2/5)-Python 공부 , CS

kimjunki-8 2025. 2. 5. 23:26

하아......

오늘 배운 점 

먼저 code(python) convention 공부

PEP 8 (Python Enhancement Proposal 8)
PEP 8은 Python 코드 스타일 가이드의 표준입니다.
(1) 코드 레이아웃
들여쓰기(Indentation): 4칸 공백(Space 4개) 사용, 탭(Tab) 사용 금지
줄 길이(Line Length): 79자 이하 (docstring이나 주석은 72자 이하 권장)
빈 줄(Blank Lines):
최상위 레벨 함수 및 클래스는 두 줄의 빈 줄을 추가
클래스 내 메서드는 한 줄의 빈 줄을 추가
def my_function():
    """Example function."""
    print("Hello, World!")


(2) 공백(Whitespace) 사용
콤마 ,, 연산자 +, -, =, 비교 연산자 ==, != 등의 양쪽에는 한 칸 공백
리스트, 딕셔너리, 튜플 등의 내부에서는 공백 사용 X
틀린 예시:

x=10
y =x+5
my_list = [ 1, 2, 3, 4 ]

 

정답 예시:
x = 10
y = x + 5
my_list = [1, 2, 3, 4]​


(3) 변수 및 함수 명명 규칙(Naming Conventions)
변수 및 함수: snake_case (소문자 + 언더스코어 _)
상수(Constant): 대문자 + 언더스코어 _
클래스: PascalCase
보호된 속성: _접두어 (언더스코어 1개)
비공개 속성: __접두어 (언더스코어 2개)

# 변수와 함수
user_name = "Alice"
def get_user_info():
    pass

# 클래스
class MyClass:
    pass

# 상수
MAX_CONNECTIONS = 100

# 보호된 속성
class Example:
    def __init__(self):
        self._protected_var = "This is protected"

# 비공개 속성
class PrivateExample:
    def __init__(self):
        self.__private_var = "This is private"


(4) 주석(Comments)
한 줄 주석: # 뒤에 한 칸 띄고 작성
블록 주석: 여러 줄 주석은 """ """ 또는 ''' '''
docstring: 함수나 클래스 설명을 위한 주석

# 한 줄 주석
x = 5  # 변수 x는 5입니다.

# 블록 주석
"""
이 함수는 두 숫자를 더하는 함수입니다.
사용 예:
    add(2, 3) -> 5
"""
def add(a, b):
    return a + b


(5) 타입 힌트(Type Hint)
Python 3.5 이상에서는 타입 힌트를 추가할 수 있음.

def add_numbers(x: int, y: int) -> int:
    return x + y


(6) 예외 처리(Exception Handling)
except 블록에서는 가능한 한 구체적인 예외 클래스를 사용
else 블록은 예외가 발생하지 않았을 때 실행될 코드
finally 블록은 항상 실행됨

try:
    num = int(input("Enter a number: "))
except ValueError:
    print("Invalid input! Please enter a number.")
else:
    print("Valid number:", num)
finally:
    print("Execution finished.")


(7) Import 규칙
import는 항상 맨 위에 작성
한 줄에 하나의 라이브러리만 임포트
표준 라이브러리, 서드파티 라이브러리, 로컬 모듈 순서로 정리

# 표준 라이브러리
import os
import sys

# 서드파티 라이브러리
import numpy as np
import requests

# 로컬 모듈
import my_module

비즈니스 로직
일반적으로 애플리케이션의 구조에서 비즈니스 로직을 UI나 데이터 처리와 같은 다른 부분으로부터 분리하여 독립적인 컴포넌트로 구현하는 것을 의미합니다. 이렇게 하면 비즈니스 로직이 다른 모듈이나 서비스에 의해 쉽게 재사용될 수 있고, 시스템의 유지보수성이 높아지며, 테스트하기도 더 쉬워집니다.

비즈니스 로직은 실제 애플리케이션의 핵심 기능을 담당하는 부분으로, 사용자의 요구사항을 처리하거나 데이터 처리 규칙을 정의하는 데 관여합니다. 예를 들어, 학생 예산 관리 앱이라면, 예산을 계산하고 분배하는 규칙, 과소비를 감지하여 남은 기간에 부담을 분배하는 로직 등이 비즈니스 로직에 해당합니다.

이 로직을 외부 모듈이나 서비스로 분리함으로써, UI나 데이터베이스와 같은 다른 레이어는 비즈니스 로직에 종속되지 않고 독립적으로 관리할 수 있습니다. 이를 통해 코드의 가독성과 확장성을 높일 수 있죠.
예시:
# 예산 관리 로직이 UI와 데이터 처리 코드 안에 섞여 있는 예시

class BudgetApp:
    def __init__(self, student_data):
        self.student_data = student_data

    def calculate_budget(self):
        # 예산 계산
        total_income = self.student_data['income']
        total_expenses = sum(self.student_data['expenses'].values())
        remaining_budget = total_income - total_expenses
        print(f"남은 예산: {remaining_budget}")

    def display_budget(self):
        self.calculate_budget()
        print(f"학생 이름: {self.student_data['name']}")
        print(f"등록금: {self.student_data['expenses']['tuition']}")
        print(f"기타 지출: {self.student_data['expenses']['other']}")


사이드 프로젝트
local()
setattr()
코드의 가독성을 높이고자, 여러 코드를 적는 것을 대신할 방법을 찾다가 우연히 발견.
class Consulting:
    def __init__(self,
                 total_amount,
                 daily_spend,
                 tuition_fee, book_fee,
                 courses_fee, communication_fee,
                 food_fee, transportation_fee, leisure_fee,
                 self_development_fee, club_fee,
                 preparation_fee=None,
                 dormitory_fee=None,
                 healthcare_fee=None):
        category = [
            "total_amount",
            "daily_spend",
            "tuition_fee",
            "book_fee",
            "courses_fee",
            "dormitory_fee",
            "communication_fee",
            "food_fee",
            "transportation_fee",
            "preparation_fee",
            "leisure_fee",
            "self_development_fee",
            "healthcare_fee",
            "club_fee",
        ]

        kwargs = locals()  

        for cat in category:
            setattr(self, cat, kwargs.get(cat, None))

먼저, 저 값들을 list에 넣어서 관리할려고 했지만, __init__에서 초기화를 시켜줘야 한다. 즉, self가 들어가야 한다. 참고로 객체 속성을 동적으로 추가할려면 변수가 아니라 문자열로 list에 들어가야 한다.
먼저
locals는 현재 __init__의 모든 로컬 변수 가져옵니다. __init__말고도 다른데에 쓰면 그곳의 로컬 변수를 가져옵니다.
예시:

def example(a, b):
    c = a + b
    d = c * 2
    print(locals())

example(3, 5)

출력:
{'a': 3, 'b': 5, 'c': 8, 'd': 16}

즉, 인자로 값들을 받으면 그것을 dict 형태로 반환.

그러면 이제 저 setattr는 뭘까요.

setattr(object, name, value)

먼저 구조 입니다.
object: 속성을 추가할 객체
name: 속성의 이름 (문자열로)
value: 속성에 할당할 값
먼저 
setattr(self, name, value)에서 object는 바로 그 클래스의 인스턴스를 말하는 것이며, 이 인스턴스는 클래스에서 정의한 속성이나 메서드를 갖는 객체입니다.
다시 돌아와서

for cat in category:
    setattr(self, cat, kwargs.get(cat, None))

이것은 category를 하나씩 가져와서, 
self.로 인스턴스를 만드는 과정이며, kwargs.get(cat, None)은 즉,
클래스 객체를 만들고, 그리고 가져온 값을 받아서 딕셔너리 형태로 만든다음, key의 이름과 똑같은 것을 list에서 찾아, name에 넣어주고, 값을 kwargs.get을 통해 가져옵니다. None은 만약 값이 없으면 대체할 값입니다.


setattr()와 getattr()의 차이
1. setattr: 객체의 속성 값 설정
구조: setattr(object, name, value)
object: 속성을 설정할 객체
name: 속성 이름 (문자열로 지정)
value: 설정할 값
용도: 주어진 name에 해당하는 속성을 객체에 설정합니다. 만약 객체에 해당 속성이 없으면 새로 생성하여 설정합니다.

class Person:
    pass

p = Person()
setattr(p, 'name', 'John')  # Person 객체 p에 'name' 속성을 'John'으로 설정
print(p.name)  # 'John'


2. getattr: 객체의 속성 값 가져오기
구조: getattr(object, name, default=None)
object: 속성을 가져올 객체
name: 속성 이름 (문자열로 지정)
default: 만약 속성이 없으면 반환할 값 (선택적)
용도: 주어진 name에 해당하는 속성 값을 가져옵니다. 만약 해당 속성이 없으면 default 값을 반환하거나, default가 제공되지 않으면 AttributeError를 발생시킵니다.

class Person:
    def __init__(self, name):
        self.name = name

p = Person('John')
print(getattr(p, 'name'))  # 'John'
print(getattr(p, 'age', 'Unknown'))  # 'Unknown' (age 속성이 없으면 default값 반환)

3. setattr와 getattr의 차이점
기능:
setattr는 속성을 설정합니다.
getattr는 속성 값을 가져오거나, 없으면 기본값을 반환합니다.
인수 차이:
setattr: 객체, 속성 이름, 속성 값이 필요합니다.
getattr: 객체, 속성 이름, (선택적으로) 기본값이 필요합니다.
용도:
setattr은 객체의 속성을 동적으로 추가하거나 수정할 때 사용됩니다.
getattr은 객체에서 동적으로 속성 값을 가져올 때 사용됩니다.

일단 여기까지...