본문 바로가기
프로그래밍/Python

[AI 부트캠프] DAY 12 - 파이썬 6

by HOHHOH 2023. 8. 2.

[오늘의 일지]

파이썬 익숙해지기 - 다양한 매개변수, 람다함수, map과 filter 함수, 클래스, 모듈

[상세 내용]

파이썬 익숙해지기

다양한 매개변수

- 위치 매개변수

# 가장 기본적인 매개변수

def my_func(a, b):
    print(a, b)

my_func(2, 3)
>>>

# 2. 기본 매개변수
# 매개변수의 기본값을 지정할 수 있다.

def post_info(title, content='내용없음'):
    print('제목 :', title)
    print('내용 :', content)

post_info('안녕하세요!')
>>>
제목 : 안녕하세요!
내용 : 내용없음

# 3. 키워드 매개변수
# 함수 호출 시에 키워드를 붙여서 호출
# 매개변수의 순서를 지키지 않아도 됩니다.

def post_info(title, content):
    print('제목 :', title)
    print('내용 :', content)

post_info(content='안녕하세요!', title='인사법')
>>>
제목 : 인사법
내용 : 안녕하세요!

 

- 위치 가변 매개변수(가변 매개변수 = 개수가 정해지지 않은 매개변수)

# 1. 위치 가변 매개변수
def print_fruits(*args):
    for arg in args:
        print(arg)

print_fruits('사과', '오렌지', '망고', '포도')
>>>
사과
오렌지
망고
포도

# 2. 키워드 가변 매개변수
def comment_info(**kwargs):
    for key, value in kwargs.items():
        print(f'{key} : {value}')

comment_info(name='음식', content='피자')
>>>
name : 음식
content : 피자

# 매개변수 작성 순서
# 위치 - 기본 - 위치 가변 - 키워드(기본) - 키워드 가변

def post_info(*tags, title, content, **kwargs):
    print(f'제목 : {title}')
    print(f'내용 : {content}')
    print(f'태그 : {tags}')

post_info('#파이썬', '#함수',title='파이썬 함수', content='다양한 매개변수 정리')
>>>
제목 : 파이썬 함수
내용 : 다양한 매개변수 정리
태그 : ('#파이썬', '#함수')

 

람다함수

-람다함수의 정의 : 이름을 지을 필요도 없을 간단한 형태의 함수를 뜻하며 다른 함수의 인자(argument)로 넣을 수 있다. 람다함수를 사용하면 코드가 간결해지고 메모리가 절약된다.

# 기존 함수
def minus_one(a):
    return a-1

# 람다 함수 - 이름이 필요없는 간단한 함수
lambda a : a-1

# 람다 함수 호출방법 1. 함수 자체를 호출
print((lambda a : a-1)(10))
>>>
9

# 람다 함수 호출방법 2. 변수에 담아서 호출
minus_one_2 = lambda a : a-1
print(minus_one_2(100))
>>>
99

# 람다 함수에서 if 문 사용

# 기존 함수
def is_positive_number(a):
    if a > 0:
        return True
    else:
        return False

# 람다 함수
lambda a : True if a > 0 else False

# 람다 함수 호출 (1)
print((lambda a : True if a > 0 else False)(-2))
>>>
False

# 람다 함수 호출 (2)
is_positive_number = lambda a : True if a > 0 else False
print(is_positive_number(2))
>>>
True

 

 

map과 filter 함수

map 함수 - map 함수는 파이썬의 내장 함수로서 여러 개의 데이터를 한 번에 다른 형태로 변환할 때 사용합니다. 주로 list, tuple과 같은 sequence를 대상으로 사용합니다.

# map 함수
# - 사용이유
# 기존 리스트를 수정해서 새로운 리스트를 만들때

# - 사용방법
# map(함수, 순서가있는자료형)
print(list(map(int, ['3', '4', '5', '6'])))
>>>
[3, 4, 5, 6]

# - 예제
# 리스트 모든 요소의 공백 제거
items = ['  마우스  ', '  키보드  ','    모니터    ']

# 1) for 사용
for i in range(len(items)):
    items[i] = items[i].strip()
print(items)
>>>
['마우스', '키보드', '모니터']

# 2) map 사용
def strip_all(x):
    return x.strip()
items = list(map(strip_all, items))
print(items)
>>>
['마우스', '키보드', '모니터']

# 3) 람다 함수 사용
items = list(map(lambda x : x.strip(), items))
print(items)
>>>
['마우스', '키보드', '모니터']

 

 

filter 함수 - filter 함수는 의미 그대로 "거르다"를 하기 위해 정의된 함수입니다. 특정 데이터가 주어졌을 때 조건을 만족하는 대상들을 찾는 경우에 filter()를 사용할 수 있습니다.

# filter 함수
# - 사용 이유
# 기존 리스트에서 조건을 만족하는 요소만 뽑고 싶을 때

# - 사용 방법
# filter(함수, 순서가있는자료형)
def func(x):
    return x < 0
print(list(filter(func, [-3, -2, 0, 5, 7])))
>>>
[-3, -2]

# - 예제
# 리스트에서 길이가 3이하인 문자들만 필터링
animals = ['cat', 'tiger', 'dog', 'bird', 'monkey']

# 1) for 사용
result = []
for i in animals:
    if len(i) <= 3:
        result.append(i)
print(result)
>>>
['cat', 'dog']

# 2) filter 사용
def word_check(x):
    return len(x) <= 3
result = list(filter(word_check, animals))
print(result)

# 3) 람다 함수 사용
result = list(filter(lambda x : len(x) <= 3, animals))
>>>
['cat', 'dog']

 

클래스

- 클래스 예시(수업 내용을 참고했습니다.)

# 많은 양의 캐릭터를 관리할 수 있다
class Champion:
    def __init__(self, name, health, attack):
        self.name = name
        self.health = health
        self.attack = attack
        print(f"{name}님 게임에 입장하신 것을 환영합니다.")
    def basic_attack(self):
        print(f"{self.name} 기본공격 {self.attack}")

캐릭터1 = Champion("캐릭터1", 700, 90)
캐릭터2 = Champion("캐릭터2", 800, 95)
캐릭터3 = Champion("캐릭터3", 750, 92)
캐릭터1.basic_attack()
캐릭터2.basic_attack()
캐릭터3.basic_attack()

 

- 기본형 클래스 만들기

class Monster:
    def say(self):
        print("나는 몬스터다!")

goblin = Monster()
goblin.say()
>>>
나는 몬스터다!

# 파이썬에서는 자료형도 클래스다
a = 10
b = "문자열객체"
c = True

print(b.__dir__())
>>>
['__new__', '__repr__', '__hash__', '__str__', '__getattribute__', '__lt__', '__le__',
'__eq__', '__ne__', '__gt__', '__ge__', '__iter__', '__mod__', '__rmod__', '__len__',
'__getitem__', '__add__', '__mul__', '__rmul__', '__contains__', 'encode', 'replace', 
'split', 'rsplit', 'join', 'capitalize', 'casefold', 'title', 'center', 'count', 
'expandtabs', 'find', 'partition', 'index', 'ljust', 'lower', 'lstrip', 'rfind',
'rindex', 'rjust', 'rstrip', 'rpartition', 'splitlines', 'strip', 'swapcase',
'translate', 'upper', 'startswith', 'endswith', 'removeprefix', 'removesuffix', 
'isascii', 'islower', 'isupper', 'istitle', 'isspace', 'isdecimal', 'isdigit', 
'isnumeric', 'isalpha', 'isalnum', 'isidentifier', 'isprintable', 'zfill', 'format',
'format_map', '__format__', 'maketrans', '__sizeof__', '__getnewargs__', '__doc__', 
'__setattr__', '__delattr__', '__init__', '__reduce_ex__', '__reduce__', '__subclasshook__',
'__init_subclass__', '__dir__', '__class__']

 

- 여러 가지 메서드

- 매직 메서드 : 클래스 안에 정의된 함수를 우리는 특별히 '메서드(method)'라고 부릅니다. 메서드 중에서 __로 시작해서 __로 끝나는 메서드들이 있는데 이를 매직 메서드 또는 특별 메서드(special method)라고 부릅니다. 가장 유명한 매직 메서드에는__init__이라는 생성자가 있습니다.

 

- 인스턴스(instance) 메서드 : 인스턴스 생성 후, '참조 변수. 메서드. 명()'으로 호출하고 인스턴스 멤버와 관련된 작업을 합니다. 메서드 내에서 인스턴스 변수를 사용할 수 있으며 인스턴스 변수를 이용해서 작업을 하므로 변수의 묶음인 객체를 생성해야 인스턴스 메서드를 호출할 수 있습니다.

 

-  정적(static) 메서드 : 데코레이터를 사용해서 클래스에 메서드를 선언하면 해당 메서드는 정적(static) 메서드가 되며, 정적 메서드는 인스턴스 메서드나 클래스 메서드와 달리 첫 번째 매개 변수가 할당되지 않습니다. 따라서 정적 메서드 내에서는 인스턴스/클래스 속성에 접근하거나, 인스턴스/클래스 메서드를 호출하는 것이 불가능합니다.

 

- 클래스(class) 메서드 : 객체 생성 없이 '클래스 명. 메서드. 명()'으로 호출이 가능하고 인스턴스 멤버와 관련되지 않은 작업을 합니다. 메서드 내에서 인스턴스 변수를 사용할 수 없고 인스턴스 메서드와 달리 인스턴스 변수가 필요 없으므로 객체를 생성하지 않고도 호출할 수 있습니다.

 

- 여러 가지 메서드 예시

class Unit:
    """
    인스턴스 속성 : 이름, 체력, 방어막, 공격력
    클래스 속성 : 전체 유닛 개수
    """
    count = 0
    def __init__(self, name, hp, shield, demage):
        self.name = name 
        self.hp = hp
        self.shield = shield
        self.demage = demage
        Unit.count += 1
        print(f"[{self.name}](이)가 생성 되었습니다.")

    def __str__(self):
        return f"[{self.name}] 체력 : {self.hp} 방어막 : {self.shield} 공격력 : {self.demage}"

    # 인스턴스 메서드 (instance method)
    # 인스턴스 속성에 접근할 수 있는 메서드
    def hit(self, demage):
        # 방어막 변경
        if self.shield >= demage:
            self.shield -= demage
            demage = 0
        else:
            demage -= self.shield
            self.shield = 0
        
        # 체력 변경
        if demage > 0:
            if self.hp > demage:
                self.hp -= demage
            else:
                self.hp = 0
    
    # 클래스 메서드 (class method)
    # 클래스 속성에 접근하는 메서드
    @classmethod
    def print_count(cls):
        print(f"생성된 유닛 개수 : [{cls.count}]개")

character1 = Unit("캐릭1", 20, 20, 5)
character2 = Unit("캐릭2", 100, 60, 16)
character3 = Unit("캐릭3", 100, 80, 20)
>>>
[캐릭1](이)가 생성 되었습니다.
[캐릭2](이)가 생성 되었습니다.
[캐릭3](이)가 생성 되었습니다.

character1.hit(16)
print(character1)
character1.hit(16)
print(character1)
character1.hit(16)
print(character1)
>>>
[캐릭1] 체력 : 20 방어막 : 4 공격력 : 5
[캐릭1] 체력 : 8 방어막 : 0 공격력 : 5
[캐릭1] 체력 : 0 방어막 : 0 공격력 : 5

Unit.print_count()
>>>
생성된 유닛 개수 : [3]개


print(dir(character1)) # dir() 함수 : 객체가 가지고 있는 매서드와 속성을 확인할 수 있는 함수
>>>
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
'count', 'demage', 'hit', 'hp', 'name', 'print_count', 'shield']


class Math:

    # 정적 메서드(static method)
    # 인스턴스를 만들 필요가 없는 메서드
    @staticmethod
    def add(x, y):
        return x + y

    @staticmethod
    def sub(x, y):
        return x - y

print(Math.add(3, 4))
print(Math.sub(3, 4))
>>>
7
-1

 

- 상속과 오버라이딩

- 상속 : 클래스들에 중복된 코드를 제거하고 유지보수를 편하게 하기 위해서 사용합니다.

- 오버라이딩 : 오버라이딩(overriding)은 무시하다, 우선하다는 뜻을 가지고 있는데 말 그대로 기반 클래스의 메서드를 무시하고 새로운 메서드를 만든다는 뜻입니다.

- 상속과 오버라이딩의 예시

# 상속
# : 클래스들에 중복된 코드를 제거하고 유지보수를
#   편하게 하기 위해서 사용.

# 클래스 변수
# : 인스턴스들이 모두 공유하는 변수

import random
# 부모 클래스
class Monster:
    max_num = 1000
    def __init__(self, name, health, attack):
        self.name = name
        self.health = health
        self.attack = attack
        Monster.max_num -= 1
    def move(self):
        print(f"[{self.name}] 걸어가기")

# 자식 클래스
class Char1(Monster):
    pass

class Char2(Monster):
    def move(self): # 메서드 오버라이딩
        print(f"[{self.name}] 헤엄치기")

class Char3(Monster):
    # 생성자 오버라이딩
    def __init__(self, name, health, attack):
        super().__init__(name, health, attack)
        self.skills = ("스킬1", "스킬2", "스킬3")

    def move(self) : # 메서드 오버라이딩
        print(f"[{self.name}] 날기")
    
    def skill(self):
        print(f"[{self.name}] 스킬 사용 {self.skills[random.randint(0,2)]}")

char1 = Char1("캐릭터1", 1500, 200)
char1.move()
print(char1.max_num)

char2 = Char2("캐릭터2", 3000, 400)
char2.move()
print(char2.max_num)

char3 = Char3("캐릭터3", 8000, 800)
char3.move()
char3.skill()
print(char3.max_num)
>>>
[캐릭터1] 걸어가기
999
[캐릭터2] 헤엄치기
998
[캐릭터3] 날기
[캐릭터3] 스킬 사용 스킬1
997

 

- 추상 클래스 : 추상 클래스(Abstract Class)는 추상 메서드를 선언해 놓고 상속을 통해 자식 클래스에서 메서드를 완성하도록 유도하는 클래스입니다. 이러한 특성 탓에 미완성 설계도라고 표현하기도 하며 추상클래스는 상속을 위한 클래스이기 때문에 따로 인스턴스를 생성할 수 없습니다.

from abc import *

class Item(metaclass=ABCMeta):
    """
    속성 : 이름
    메서드 : 줍기, 버리기
    """
    def __init__(self, name):
        self.name = name
    
    def pick(self):
        print(f"[{self.name}]을(를) 주웠습니다.")

    def discard(self):
        print(f"[{self.name}]을(를) 버렸습니다.")

    @abstractmethod
    def use(self):
        pass

class Weapon(Item):
    """
    속성 : 공격력
    메서드 : 공격하기
    """
    def __init__(self, name, demage):
        super().__init__(name)
        self.demage = demage

    def use(self):
        print(f"[{self.name}]을(를) 이용해 {self.demage}로 공격합니다.")

class HealingItem(Item):
    """
    속성 : 회복량
    메서드 : 사용하기
    """
    def __init__(self, name, recovery_amount):
        super().__init__(name)
        self.recovery_amount = recovery_amount

    def use(self):
        print(f"[{self.name}]을(를) 사용합니다. {self.recovery_amount} 회복")

gun = Weapon("총", 110)
pill = HealingItem("치료약", 20)

gun.use()
pill.use()
>>>
[총]을(를) 이용해 110로 공격합니다.
[치료약]을(를) 사용합니다. 20 회복

 

모듈

- 내부 모듈과 외부 모듈

# 내장 모듈
# : 파이썬 설치 시 자동으로 설치되는 모듈
from math import pi, ceil as c
print(pi)
print(c(2.7))
>>>
3.141592653589793
3

# 외부 모듈
# : 다른 사람이 만든 파이썬 파일 pip로 설치해서 사용
# pyautogui 
import pyautogui as pg
pg.moveTo(500, 500, duration=2)

 

-모듈 만들기

# 결제 정보, 관리 모듈
# 변수
version = 2.0

# 함수
def printAuthor():
    print("모듈제작자")

# 클래스
class Pay:
    def __init__(self, id, price, time):
        self.id = id
        self.price = price
        self.time = time
    def get_pay_info(self):
        return f"{self.time} {self.id} {self.price}"

# 해당 파일을 직접 실행했을 때만 실행된다.
if __name__ == "__main__":
    print("pay module 실행")

print(__name__)

 

- 만든 모듈 사용하기

import pay_module

# 변수 사용
print(pay_module.version)

# 함수 사용
pay_module.printAuthor()

# 클래스 사용
pay_info = pay_module.Pay("제품번호", 제품가격, "제품생산일")
print(pay_info.get_pay_info())

print(pay_module.__name__)

 

[마무리]

 오늘은 온라인 녹화 강의를 통해서 파이썬에서 사용되는 다양한 부분을 학습했습니다. 특히 오늘은 람다 함수나  map, filter 등의 새로운 함수를 알게 되었는데 이 함수들은 간단하면서 유용하게 쓰이는 것 같았습니다. 그리고 오늘도 클래스 파트에 대해서 많이 복습을 했는데 여전히 어렵게 느껴지는 것은 어쩔 수 없나 봅니다.

 

 

반응형

댓글