KR_Functional - somaz94/python-study GitHub Wiki

Python ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐœ๋… ์ •๋ฆฌ


1๏ธโƒฃ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ์ดˆ

ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœ๊ทธ๋žจ์„ ์ž‘์„ฑํ•˜๋Š” ํŒจ๋Ÿฌ๋‹ค์ž„์ด๋‹ค.

# ์ˆœ์ˆ˜ ํ•จ์ˆ˜์˜ ์˜ˆ
def add(x, y):
    return x + y

# ์ˆœ์ˆ˜ํ•˜์ง€ ์•Š์€ ํ•จ์ˆ˜์˜ ์˜ˆ
total = 0
def add_to_total(x):
    global total
    total += x
    return total

# ๋ถ€์ž‘์šฉ์ด ์—†๋Š” ๋ฐฉ์‹์œผ๋กœ ์ž‘์„ฑํ•˜๊ธฐ
def create_adder(initial=0):
    def add(x):
        return initial + x
    return add

add_to_5 = create_adder(5)
print(add_to_5(10))  # 15

โœ… ํŠน์ง•:

  • ์ˆœ์ˆ˜ ํ•จ์ˆ˜
  • ๋ถ€์ž‘์šฉ ์—†์Œ
  • ์ฐธ์กฐ ํˆฌ๋ช…์„ฑ
  • ์ƒํƒœ ๋ณ€๊ฒฝ ์ตœ์†Œํ™”
  • ์„ ์–ธ์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์Šคํƒ€์ผ


2๏ธโƒฃ map, filter, reduce

ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๊ณ ์ฐจ ํ•จ์ˆ˜๋“ค์ด๋‹ค.

from functools import reduce

# map: ๋ชจ๋“  ์š”์†Œ์— ํ•จ์ˆ˜ ์ ์šฉ
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x**2, numbers))
print(squares)  # [1, 4, 9, 16, 25]

# filter: ์กฐ๊ฑด์— ๋งž๋Š” ์š”์†Œ๋งŒ ์„ ํƒ
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens)  # [2, 4]

# reduce: ์š”์†Œ๋“ค์„ ํ•˜๋‚˜๋กœ ์ค„์ž„
product = reduce(lambda x, y: x * y, numbers)
print(product)  # 120

# ๋ฆฌ์ŠคํŠธ ์ปดํ”„๋ฆฌํ—จ์…˜์„ ํ™œ์šฉํ•œ ๋Œ€์•ˆ
squares_comp = [x**2 for x in numbers]
evens_comp = [x for x in numbers if x % 2 == 0]

# ์—ฌ๋Ÿฌ ํ•จ์ˆ˜๋ฅผ ์กฐํ•ฉํ•œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
result = reduce(
    lambda acc, x: acc + x,
    filter(lambda x: x > 10,
           map(lambda x: x**2, numbers))
)
print(result)  # 16 + 25 = 41

โœ… ํŠน์ง•:

  • ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜
  • ์š”์†Œ ํ•„ํ„ฐ๋ง
  • ์ง‘๊ณ„ ์—ฐ์‚ฐ
  • ์ง€์—ฐ ํ‰๊ฐ€ (map๊ณผ filter๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฐ˜ํ™˜)
  • ์ฒด์ด๋‹ ๊ฐ€๋Šฅ
  • ์„ ์–ธ์  ์Šคํƒ€์ผ


3๏ธโƒฃ ๊ณ ์ฐจ ํ•จ์ˆ˜

ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ๋ฐ›๊ฑฐ๋‚˜ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.

def multiply_by(n):
    def multiplier(x):
        return x * n
    return multiplier

times_two = multiply_by(2)
times_three = multiply_by(3)

print(times_two(5))    # 10
print(times_three(5))  # 15

# ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š” ๊ณ ์ฐจ ํ•จ์ˆ˜
def apply_twice(func, arg):
    return func(func(arg))

def add_five(x):
    return x + 5

print(apply_twice(add_five, 10))  # 10 + 5 + 5 = 20

# ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋„ ๊ณ ์ฐจ ํ•จ์ˆ˜์˜ ์ผ์ข…์ด๋‹ค
def log_function_call(func):
    def wrapper(*args, **kwargs):
        print(f"ํ•จ์ˆ˜ {func.__name__} ํ˜ธ์ถœ๋จ")
        return func(*args, **kwargs)
    return wrapper

@log_function_call
def greet(name):
    return f"์•ˆ๋…•, {name}!"

print(greet("์ฒ ์ˆ˜"))  # "ํ•จ์ˆ˜ greet ํ˜ธ์ถœ๋จ" ์ถœ๋ ฅ ํ›„ "์•ˆ๋…•, ์ฒ ์ˆ˜!" ๋ฐ˜ํ™˜

โœ… ํŠน์ง•:

  • ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ์ „๋‹ฌ
  • ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜
  • ํด๋กœ์ € ํ™œ์šฉ
  • ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ์ง€์›
  • ํ•จ์ˆ˜ ํ•ฉ์„ฑ ๊ฐ€๋Šฅ
  • ์ถ”์ƒํ™” ์ˆ˜์ค€ ์ฆ๊ฐ€


4๏ธโƒฃ ๋ถˆ๋ณ€์„ฑ

๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•œ ํ›„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š” ์›์น™์ด๋‹ค.

from typing import NamedTuple
import copy

class Point(NamedTuple):
    x: int
    y: int

def move_point(point, dx, dy):
    return Point(point.x + dx, point.y + dy)

p1 = Point(1, 2)
p2 = move_point(p1, 3, 4)  # ์ƒˆ๋กœ์šด ๊ฐ์ฒด ์ƒ์„ฑ
print(p1)  # Point(x=1, y=2) - ์›๋ณธ ๋ณ€๊ฒฝ ์—†์Œ
print(p2)  # Point(x=4, y=6) - ์ƒˆ ๊ฐ์ฒด ๋ฐ˜ํ™˜

# ๋ถˆ๋ณ€ ๋ฆฌ์ŠคํŠธ ํ‰๋‚ด๋‚ด๊ธฐ
def append_to_list(lst, item):
    # ์›๋ณธ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์ƒˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜
    new_list = lst.copy()
    new_list.append(item)
    return new_list

original = [1, 2, 3]
modified = append_to_list(original, 4)
print(original)  # [1, 2, 3] - ์›๋ณธ ๋ณ€๊ฒฝ ์—†์Œ
print(modified)  # [1, 2, 3, 4] - ์ƒˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜

# ์ค‘์ฒฉ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์—์„œ์˜ ๋ถˆ๋ณ€์„ฑ
def update_user_email(user_dict, new_email):
    # ๋”•์…”๋„ˆ๋ฆฌ ๊นŠ์€ ๋ณต์‚ฌ
    new_user = copy.deepcopy(user_dict)
    new_user['email'] = new_email
    return new_user

user = {'name': 'ํ™๊ธธ๋™', 'email': '[email protected]', 'settings': {'theme': 'dark'}}
updated_user = update_user_email(user, '[email protected]')
print(user['email'])  # [email protected]
print(updated_user['email'])  # [email protected]

โœ… ํŠน์ง•:

  • ๋ถˆ๋ณ€ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ
  • ์ƒํƒœ ๋ณ€๊ฒฝ ๋ฐฉ์ง€
  • ์•ˆ์ „ํ•œ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ
  • ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ๋™์ž‘
  • ๋””๋ฒ„๊น… ์šฉ์ด์„ฑ
  • ์‹œ๊ฐ„ ์—ฌํ–‰ ๋””๋ฒ„๊น… ๊ฐ€๋Šฅ
  • ๋ถ€์ž‘์šฉ ๊ฐ์†Œ


5๏ธโƒฃ ํ•จ์ˆ˜ ํ•ฉ์„ฑ

์—ฌ๋Ÿฌ ํ•จ์ˆ˜๋ฅผ ์กฐํ•ฉํ•˜์—ฌ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ธฐ๋ฒ•์ด๋‹ค.

def compose(f, g):
    return lambda x: f(g(x))

def double(x):
    return x * 2

def increment(x):
    return x + 1

# ํ•จ์ˆ˜ ํ•ฉ์„ฑ
double_then_increment = compose(increment, double)
increment_then_double = compose(double, increment)

print(double_then_increment(3))  # 3*2 + 1 = 7
print(increment_then_double(3))  # (3+1)*2 = 8

# ์—ฌ๋Ÿฌ ํ•จ์ˆ˜ ํ•ฉ์„ฑํ•˜๊ธฐ
def compose_all(*functions):
    def compose_two(f, g):
        return lambda x: f(g(x))
    
    if not functions:
        return lambda x: x  # ํ•ญ๋“ฑ ํ•จ์ˆ˜
    
    return functools.reduce(compose_two, functions)

def square(x):
    return x * x

# square(double(increment(x)))
composed = compose_all(square, double, increment)
print(composed(3))  # square(double(increment(3))) = square(double(4)) = square(8) = 64

# ๋ถ€๋ถ„ ์ ์šฉ ํ•จ์ˆ˜
from functools import partial

def add(x, y):
    return x + y

add_five = partial(add, 5)  # x=5๋กœ ๊ณ ์ •
print(add_five(10))  # 15

โœ… ํŠน์ง•:

  • ํ•จ์ˆ˜ ์กฐํ•ฉ
  • ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ
  • ๋ชจ๋“ˆํ™”
  • ์ถ”์ƒํ™” ์ˆ˜์ค€ ์ƒ์Šน
  • ํŒŒ์ดํ”„๋ผ์ธ ์ƒ์„ฑ ๊ฐ€๋Šฅ
  • ๋ถ€๋ถ„ ํ•จ์ˆ˜ ์ ์šฉ
  • ์ปค๋ง(Currying) ์ง€์›


6๏ธโƒฃ ์‹ค์šฉ์ ์ธ ์˜ˆ์ œ

ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์‹ค์ œ ์ƒํ™ฉ์— ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

import functools

def pipeline(*funcs):
    def wrapper(x):
        result = x
        for f in funcs:
            result = f(result)
        return result
    return wrapper

# ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜๋“ค
clean = lambda x: x.strip().lower()
split_words = lambda x: x.split()
count_words = lambda x: len(x)

# ํŒŒ์ดํ”„๋ผ์ธ ์ƒ์„ฑ
word_counter = pipeline(clean, split_words, count_words)

text = "  Hello World  "
print(word_counter(text))  # 2

# ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ ํŒŒ์ดํ”„๋ผ์ธ
def transform_data(data):
    # ํ•จ์ˆ˜ํ˜• ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜
    return (
        data
        | pipe(filter_invalid_entries)
        | pipe(normalize_fields)
        | pipe(enrich_with_external_data)
        | pipe(calculate_statistics)
    )

# ํŒŒ์ดํ”„ ์—ฐ์‚ฐ์ž ํ‰๋‚ด๋‚ด๊ธฐ
def pipe(func):
    def wrapper(data):
        return func(data)
    return wrapper

# ํ•จ์ˆ˜ํ˜• ์—๋Ÿฌ ์ฒ˜๋ฆฌ - Maybe ๋ชจ๋‚˜๋“œ ํŒจํ„ด
class Maybe:
    def __init__(self, value=None):
        self.value = value
    
    @classmethod
    def just(cls, value):
        return cls(value)
    
    @classmethod
    def nothing(cls):
        return cls(None)
    
    def bind(self, func):
        if self.value is None:
            return self
        try:
            result = func(self.value)
            if isinstance(result, Maybe):
                return result
            return Maybe.just(result)
        except:
            return Maybe.nothing()
    
    def get_or_else(self, default):
        return self.value if self.value is not None else default

# Maybe ๋ชจ๋‚˜๋“œ ์‚ฌ์šฉ ์˜ˆ์‹œ
def safe_divide(x, y):
    return Maybe.just(x / y) if y != 0 else Maybe.nothing()

def safe_sqrt(x):
    return Maybe.just(x ** 0.5) if x >= 0 else Maybe.nothing()

# ์•ˆ์ „ํ•œ ๊ณ„์‚ฐ ํŒŒ์ดํ”„๋ผ์ธ
def calculate(x, y):
    return (Maybe.just(x)
            .bind(lambda v: safe_divide(v, y))
            .bind(safe_sqrt)
            .get_or_else("๊ณ„์‚ฐ ๋ถˆ๊ฐ€"))

print(calculate(16, 4))  # 2.0
print(calculate(16, 0))  # "๊ณ„์‚ฐ ๋ถˆ๊ฐ€"
print(calculate(-16, 4))  # "๊ณ„์‚ฐ ๋ถˆ๊ฐ€"

โœ… ํŠน์ง•:

  • ํŒŒ์ดํ”„๋ผ์ธ ํŒจํ„ด
  • ํ•จ์ˆ˜ ์ฒด์ด๋‹
  • ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์ž๋™ํ™”
  • ๋ชจ๋‚˜๋“œ ํŒจํ„ด
  • ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์ถ”์ƒํ™”
  • ์„ ์–ธ์  ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜
  • ๋ณต์žกํ•œ ๋กœ์ง ๋‹จ์ˆœํ™”


7๏ธโƒฃ ์žฌ๊ท€์™€ ๊ผฌ๋ฆฌ ์žฌ๊ท€ ์ตœ์ ํ™”

๋ฐ˜๋ณต ๋Œ€์‹  ์žฌ๊ท€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

# ์ผ๋ฐ˜์ ์ธ ์žฌ๊ท€ - ํŒฉํ† ๋ฆฌ์–ผ ๊ณ„์‚ฐ
def factorial(n):
    if n <= 1:
        return 1
    return n * factorial(n-1)

print(factorial(5))  # 120

# ๊ผฌ๋ฆฌ ์žฌ๊ท€(Tail Recursion) - ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๋ฐฉ์ง€
def factorial_tail(n, acc=1):
    if n <= 1:
        return acc
    return factorial_tail(n-1, n*acc)

print(factorial_tail(5))  # 120

# ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด - ๋ฉ”๋ชจ์ด์ œ์ด์…˜์œผ๋กœ ์„ฑ๋Šฅ ๊ฐœ์„ 
def fibonacci(n, memo=None):
    if memo is None:
        memo = {}
    if n in memo:
        return memo[n]
    if n <= 1:
        return n
    
    memo[n] = fibonacci(n-1, memo) + fibonacci(n-2, memo)
    return memo[n]

print(fibonacci(10))  # 55

# ํŠธ๋žจํด๋ฆฐ(Trampoline) ํŒจํ„ด - ๊ผฌ๋ฆฌ ์žฌ๊ท€ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
def trampoline(func, *args, **kwargs):
    result = func(*args, **kwargs)
    while callable(result):
        result = result()
    return result

def factorial_trampoline(n, acc=1):
    if n <= 1:
        return acc
    return lambda: factorial_trampoline(n-1, n*acc)

print(trampoline(factorial_trampoline, 5))  # 120

โœ… ํŠน์ง•:

  • ๋ฐ˜๋ณต๋ฌธ ๋Œ€์ฒด
  • ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ฌธ์ œ ํ•ด๊ฒฐ ๋ฐฉ์‹
  • ์ƒํƒœ ๋ณ€์ด ์—†์Œ
  • ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ๊ธฐ๋ฒ•
  • ๊ผฌ๋ฆฌ ์žฌ๊ท€ ์ตœ์ ํ™”
  • ํŠธ๋žจํด๋ฆฐ ํŒจํ„ด
  • ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๋ฐฉ์ง€ ๊ธฐ๋ฒ•


8๏ธโƒฃ ํ•จ์ˆ˜ํ˜• ๋„๊ตฌ์™€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

Python์—์„œ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ง€์›ํ•˜๋Š” ๋„๊ตฌ์™€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด๋‹ค.

# ๋‚ด์žฅ ํ•จ์ˆ˜ ํ™œ์šฉ
from functools import reduce, partial
import itertools
import operator

data = [1, 2, 3, 4, 5]

# ๋ถ€๋ถ„ ์ ์šฉ ํ•จ์ˆ˜
multiply = lambda x, y: x * y
double = partial(multiply, 2)

# ์—ฐ์‚ฐ์ž ๋ชจ๋“ˆ ํ™œ์šฉ
total = reduce(operator.add, data)
product = reduce(operator.mul, data)

# itertools ํ™œ์šฉ
combinations = list(itertools.combinations(data, 2))
permutations = list(itertools.permutations(data, 2))

# ๋ฌดํ•œ ์‹œํ€€์Šค ์ƒ์„ฑ๊ณผ ์Šฌ๋ผ์ด์‹ฑ
infinite = itertools.count(1)
first_10 = list(itertools.islice(infinite, 10))

# ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - toolz
# pip install toolz
try:
    from toolz import compose, curry, pipe

    def add(x, y):
        return x + y

    def double(x):
        return x * 2

    # ์ปค๋ง
    curried_add = curry(add)
    add_5 = curried_add(5)
    
    # ํ•ฉ์„ฑ
    transform = compose(double, add_5)
    
    # ํŒŒ์ดํ”„
    result = pipe(10, add_5, double)
except ImportError:
    print("toolz ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")

# ํ•จ์ˆ˜ํ˜• ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ - pyrsistent
# pip install pyrsistent
try:
    import pyrsistent as pyr
    
    # ๋ถˆ๋ณ€ ๋ฆฌ์ŠคํŠธ
    v = pyr.pvector([1, 2, 3])
    v2 = v.append(4)  # ์ƒˆ ๋ฒกํ„ฐ ๋ฐ˜ํ™˜
    
    # ๋ถˆ๋ณ€ ๋งต
    m = pyr.pmap({'a': 1, 'b': 2})
    m2 = m.set('c', 3)  # ์ƒˆ ๋งต ๋ฐ˜ํ™˜
except ImportError:
    print("pyrsistent ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")

โœ… ํŠน์ง•:

  • ๋‚ด์žฅ ํ•จ์ˆ˜ํ˜• ๋„๊ตฌ
  • ์—ฐ์‚ฐ์ž ๋ชจ๋“ˆ์˜ ๊ธฐ๋Šฅ
  • ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋„๊ตฌ
  • ์™ธ๋ถ€ ํ•จ์ˆ˜ํ˜• ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ๋ถˆ๋ณ€ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ
  • ์ปค๋ง๊ณผ ๋ถ€๋ถ„ ์ ์šฉ ์ง€์›
  • ํ•จ์ˆ˜ ํ•ฉ์„ฑ ๋„๊ตฌ


์ฃผ์š” ํŒ

โœ… ๋ชจ๋ฒ” ์‚ฌ๋ก€:

  • ์ˆœ์ˆ˜ ํ•จ์ˆ˜ ์‚ฌ์šฉํ•˜๊ธฐ
  • ์ƒํƒœ ๋ณ€๊ฒฝ ํ”ผํ•˜๊ธฐ
  • ํ•จ์ˆ˜๋ฅผ ์ผ๊ธ‰ ๊ฐ์ฒด๋กœ ๋‹ค๋ฃจ๊ธฐ
  • ๊ณ ์ฐจ ํ•จ์ˆ˜ ํ™œ์šฉํ•˜๊ธฐ
  • ๋ถˆ๋ณ€์„ฑ ์œ ์ง€ํ•˜๊ธฐ
  • ๋ถ€์ž‘์šฉ ์ตœ์†Œํ™”ํ•˜๊ธฐ
  • ์žฌ๊ท€ ํ™œ์šฉํ•˜๊ธฐ (์Šคํƒ ์ œํ•œ ์ฃผ์˜)
  • ํ•ฉ์„ฑ ํ•จ์ˆ˜ ํ™œ์šฉํ•˜๊ธฐ
  • map, filter, reduce ์ ์ ˆํžˆ ์‚ฌ์šฉํ•˜๊ธฐ
  • ๋ฆฌ์ŠคํŠธ ์ปดํ”„๋ฆฌํ—จ์…˜๊ณผ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ‘œํ˜„์‹ ํ™œ์šฉ
  • ์ดํ„ฐ๋ ˆ์ดํ„ฐ์™€ ์ง€์—ฐ ํ‰๊ฐ€ ํ™œ์šฉํ•˜๊ธฐ
  • ๋ช…๋ นํ˜•๊ณผ ํ•จ์ˆ˜ํ˜• ์Šคํƒ€์ผ ์ ์ ˆํžˆ ํ˜ผํ•ฉํ•˜๊ธฐ
  • ๋ฉ”๋ชจ์ด์ œ์ด์…˜์œผ๋กœ ์„ฑ๋Šฅ ์ตœ์ ํ™”ํ•˜๊ธฐ
  • ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ/๋ฉ€ํ‹ฐํ”„๋กœ์„ธ์‹ฑ๊ณผ ํ•จ๊ป˜ ํ™œ์šฉํ•˜๊ธฐ
  • ํ•จ์ˆ˜ํ˜• ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ํŒจํ„ด ๊ณ ๋ คํ•˜๊ธฐ
  • ๊ฐ€๋…์„ฑ ๊ท ํ˜• ์œ ์ง€ํ•˜๊ธฐ


โš ๏ธ **GitHub.com Fallback** โš ๏ธ