3.SW개발/Python

[Java관점]4편. Python 함수와 메서드 – 호출 방식과 선언 구조 비교

쿼드큐브 2025. 11. 11. 23:27
반응형
반응형

4편. Python 함수와 메서드 – 호출 방식과 선언 구조 비교

 

📚 목차
1. 함수 정의와 호출 방식 - Java와 Python 구조 비교
2. 오버로딩 없이 유연한 호출 - 기본값 인자와 키워드 인자
3. 인자 개수 제한 없는 함수 - *args와 **kwargs의 활용
4. 간결한 함수 표현 - 람다(lambda)의 사용법
5. 메서드의 3가지 유형 - 인스턴스/클래스/정적 메서드 비교
✔ 마무리 - Python 함수의 유연함을 Java 시각에서 이해하기

 

Java 개발자에게 함수는 클래스 내부의 ‘메서드’로 정의되며, 명확한 반환 타입과 접근 제어자를 포함하는 정형화된 구조로 익숙합니다. 하지만 Python으로 전환하면 전혀 다른 함수 정의 방식, 인자 처리 방식, 호출 구조를 마주하게 됩니다.


예를 들어, Java에서는 동일한 이름의 메서드를 다양한 인자 조합으로 오버로딩하지만, Python은 **기본값 인자, 키워드 인자, *args, kwargs를 통해 훨씬 간결하고 유연하게 처리합니다.


이번 글에서는 Java 개발자의 시각에서 Python 함수의 핵심 특징을 비교하며, 실제 예제를 통해 구조적 차이를 직관적으로 이해할 수 있도록 정리합니다.

Java 메소드 vs Python 함수
Java 메소드 vs Python 함수

1. 함수 정의와 호출 방식 – Java와 Python 구조 비교

Java 개발자에게 가장 익숙한 메서드 정의는 클래스 내부에 public static void methodName()와 같은 형태일 것입니다. Python에서는 함수를 어떻게 정의하고 호출하는지 살펴보겠습니다.

항목 Java 예시 Python 예시
함수 정의 public int add(int a, int b) def add(a, b):
반환 방식 return a + b; return a + b
호출 방식 add(3, 5); add(3, 5)

 

✔️ Java 예시:

Java에서는 메서드가 항상 클래스 내부에 소속되며, 명확한 반환 타입과 접근 제어자를 가집니다.

 

🔸메서드 정의:

public class MyClass {
    // 반환값이 없는 정적 메서드
    public static void greet(String name) {
        System.out.println("Hello, " + name + "!");
    }

    // int 타입을 반환하는 인스턴스 메서드
    public int add(int a, int b) {
        return a + b;
    }
}

 

🔸호출 예시:

MyClass.greet("Alice"); // 'MyClass' 클래스의 정적 메서드 호출
MyClass obj = new MyClass(); // 클래스 인스턴스 생성
int result = obj.add(5, 3); // 'obj' 인스턴스의 메서드 호출
System.out.println(result); // 출력: 8

 

✔️ Python 예시

Python에서는 def 키워드를 사용하여 함수를 정의합니다.

함수 이름 뒤에 괄호를 열고 인자를 선언하며, 콜론(:)으로 함수 헤더를 닫습니다. 함수 본문은 들여쓰기(Indentation)로 구분됩니다.

 

Python에서는 함수가 클래스에 종속되지 않고도 독립적으로 존재할 수 있으므로, 대부분의 경우 클래스.함수명 또는 객체.함수명 없이 바로 함수명()으로 호출합니다.

(물론 클래스 내부에 정의된 메서드는 객체.메서드명()으로 호출합니다.)

 

🔸함수 정의:

# greet 함수 정의: 특정 이름을 받아 인사말을 출력
def greet(name):
    # f-string을 사용하여 문자열 포매팅. Java의 String.format()과 유사하지만 더 간결함.
    print(f"Hello, {name}!")

# add 함수 정의: 두 숫자를 받아 합계를 반환
def add(a, b):
    return a + b

 

🔸호출 예시:

greet("Bob") # 출력: Hello, Bob! (함수 이름으로 직접 호출)

result = add(10, 20)
print(result) # 출력: 30

 

✔️ 주요 차이점

▪️def 키워드: Java의 public static void와 같은 접근 제어자나 반환 타입 선언 없이 def 키워드만 사용합니다.
▪️들여쓰기(Indentation): Python은 중괄호 {} 대신 들여쓰기를 사용하여 코드 블록을 구분합니다.

이는 Python의 가장 큰 특징 중 하나이며, 가독성을 높여줍니다. (Java 개발자에게는 처음엔 어색할 수 있습니다.)
▪️반환 타입: Python 함수는 Java처럼 명시적으로 반환 타입을 선언하지 않습니다.

return 문이 있으면 해당 값을 반환하고, return 문이 없으면 None을 반환합니다.

None은 Java의 null과 유사한 개념입니다.

 

2. 오버로딩 없이 유연한 호출 – 기본값 인자와 키워드 인자

Java에서는 메서드 오버로딩(Method Overloading)을 통해 같은 이름의 메서드를 다양한 매개변수 조합으로 정의하여 유연성을 확보합니다.

Python은 '기본값 인자'와 '키워드 인자'라는 강력한 기능을 통해 이보다 더 유연하고 간결하게 함수를 호출할 수 있게 합니다.

 

✔️ Java에서의 유사 기능 (메소드 오버로딩):

public class Greeter {
    // 매개변수 하나 (기본 인사)
    public void sayHello(String name) {
        System.out.println("Hello, " + name + "!");
    }

    // 매개변수 두 개 (특정 메시지로 인사)
    public void sayHello(String name, String message) {
        System.out.println(message + ", " + name + "!");
    }
}

// 사용 예시
Greeter g = new Greeter();
g.sayHello("Alice");          // 출력: Hello, Alice!
g.sayHello("Bob", "Hi there"); // 출력: Hi there, Bob!

Java의 오버로딩은 매개변수의 타입이나 개수가 다를 때 유용하지만, 매개변수가 많아지면 정의해야 할 메서드의 수가 급증할 수 있습니다.

 

✔️ Python의 기본값 인자 (Default Argument Values):

Python에서는 함수를 정의할 때 특정 인자에 미리 기본값을 할당할 수 있습니다.

이렇게 하면 함수 호출 시 해당 인자를 생략할 수 있으며, 만약 값이 제공되면 그 값으로 기본값이 덮어쓰여집니다.

이는 Java의 오버로딩을 상당 부분 대체할 수 있는 강력한 기능입니다.

def say_hello(name, greeting="Hello"): # 'greeting' 인자에 "Hello"라는 기본값 설정
    print(f"{greeting}, {name}!")

# 기본값이 사용되는 경우: 'greeting' 인자를 생략
say_hello("Charlie") # 출력: Hello, Charlie!

# 기본값이 오버라이드되는 경우: 'greeting'에 새로운 값 전달
say_hello("David", "Hi there") # 출력: Hi there, David!

 

✔️Python의 키워드 인자 (Keyword Arguments)

함수를 호출할 때 인자의 순서에 관계없이 인자 이름을 명시하여 값을 전달할 수 있습니다.

이는 특히 함수가 많은 수의 매개변수를 가질 때 코드의 가독성을 높이고, 특정 인자에만 선택적으로 값을 전달하고 싶을 때 매우 유용합니다.

def create_profile(name, age, city="Seoul", occupation="Student"):
    print(f"--- 사용자 프로필 ---")
    print(f"이름: {name}")
    print(f"나이: {age}")
    print(f"도시: {city}")
    print(f"직업: {occupation}")
    print(f"------------------")

# 일반적인 위치 인자(Positional Arguments) 사용: 순서가 중요
create_profile("Minjun", 30, "Busan", "Engineer")
# 출력: 이름: Minjun, 나이: 30, 도시: Busan, 직업: Engineer

print("\n--- 키워드 인자 사용 ---")
# 키워드 인자(Keyword Arguments) 사용: 순서 무관, 인자 이름 명시
create_profile(age=25, name="Jihye") # 'city'와 'occupation'은 기본값 사용
# 출력: 이름: Jihye, 나이: 25, 도시: Seoul, 직업: Student

create_profile(occupation="Designer", city="Jeju", name="Sumi", age=28) # 순서가 바뀌어도 문제 없음
# 출력: 이름: Sumi, 나이: 28, 도시: Jeju, 직업: Designer

 

✔️ 주요 주의 사항:

함수 정의 시, 기본값이 없는 인자는 반드시 기본값이 있는 인자보다 먼저 선언되어야 합니다.

그렇지 않으면 SyntaxError가 발생합니다.

# 올바른 예시: 기본값 없는 'a'가 먼저 선언됨
def func(a, b=1):
    pass

# 잘못된 예시 (SyntaxError 발생): 기본값 있는 'a'가 먼저 선언됨
# def func(a=1, b):
#     pass

Python은 인자들을 처리할 때 먼저 위치 인자를 매칭하고, 그 다음 키워드 인자를 매칭하기 때문에 이러한 규칙이 필요합니다.

3. 인자 개수 제한 없는 함수 – *args와 **kwargs의 활용

Java에서 가변 인자는 타입... 변수명 (String... args와 같이)을 사용하여 동일한 타입의 인자를 여러 개 받을 때 활용됩니다.

Python에서는 *args와 **kwargs를 사용하여 인자의 개수나 종류가 불특정 다수일 때 훨씬 더 유연하게 처리할 수 있는 방법을 제공합니다.

 

✔️ Java 가변 인자 예시:

public class Calculator {
    // 'int' 타입의 가변 인자 'numbers'를 받아서 합계를 계산
    public static int sum(int... numbers) {
        int total = 0;
        for (int num : numbers) { // 'numbers'는 내부적으로 배열처럼 취급
            total += num;
        }
        return total;
    }
}

// 사용 예시
int result1 = Calculator.sum(1, 2, 3);          // 출력: 6
int result2 = Calculator.sum(10, 20, 30, 40, 50); // 출력: 150

Java의 가변 인자는 동일한 타입의 인자에 대해서만 작동하며, 배열 형태로 묶여 들어옵니다.

✔️ Python의 *args (위치 인자 튜플):

*args는 함수에 전달되는 '위치(positional) 인자'들을 하나의 튜플(tuple) 형태로 묶어서 받습니다.

인자의 개수가 미리 정해지지 않았거나, 다양한 수의 인자를 받고 싶을 때 유용합니다.

*args의 args 부분은 관례적인 이름이며, 다른 이름을 사용해도 됩니다 (예: *numbers).

def calculate_sum(*numbers): # '*numbers'는 전달된 위치 인자들을 튜플로 묶음
    """
    주어진 모든 숫자 인자들의 합계를 계산합니다.
    """
    total = 0
    for num in numbers: # 튜플 'numbers'를 반복하여 합계 계산
        total += num
    return total

print(calculate_sum(1, 2, 3))          # 출력: 6 (numbers = (1, 2, 3))
print(calculate_sum(10, 20, 30, 40)) # 출력: 100 (numbers = (10, 20, 30, 40))
print(calculate_sum())               # 출력: 0 (numbers = ())

 

✔️ Python의 **kwargs (키워드 인자 딕셔너리):

**kwargs는 함수에 전달되는 '키워드(keyword) 인자'들을 하나의 딕셔너리(dictionary) 형태로 묶어서 받습니다.

딕셔너리의 키(key)는 인자 이름이 되고, 값(value)은 인자의 값이 됩니다.

다양한 종류의 데이터를 키-값 쌍 형태로 유연하게 처리할 때 사용됩니다. **kwargs의 kwargs 부분도 관례적인 이름입니다.

def show_info(**details): # '**details'는 전달된 키워드 인자들을 딕셔너리로 묶음
    """
    딕셔너리 형태로 전달된 사용자 정보를 출력합니다.
    """
    print("=== 사용자 정보 ===")
    if not details:
        print("제공된 정보가 없습니다.")
        return
    for key, value in details.items(): # 딕셔너리 'details'의 키-값 쌍 반복
        print(f"  {key.replace('_', ' ').capitalize()}: {value}") # 가독성을 위해 키 포매팅

show_info(name="Alice", age=30)
# 출력:
# === 사용자 정보 ===
#   Name: Alice
#   Age: 30

show_info(country="Korea", city="Seoul", zip_code="03185", email="alice@example.com")
# 출력:
# === 사용자 정보 ===
#   Country: Korea
#   City: Seoul
#   Zip code: 03185
#   Email: alice@example.com

show_info() # 인자 없이 호출
# 출력:
# === 사용자 정보 ===
# 제공된 정보가 없습니다.

 

✔️ *args와 **kwargs 함께 사용:

함수 정의 시 일반 인자, *args, **kwargs를 함께 사용할 수 있습니다. 이때 인자의 선언 순서가 매우 중요합니다.

 

🔸 순서 규칙: 일반 인자(위치/기본값 인자) -> *args -> **kwargs

def complex_function(required_arg, *args_example, default_arg="default", **kwargs_example):
    """
    다양한 종류의 인자를 받는 복합 함수 예시.
    """
    print(f"고정/필수 인자 (required_arg): {required_arg}")
    print(f"기본값 인자 (default_arg): {default_arg}")
    print(f"가변 위치 인자 (*args_example): {args_example}") # 튜플
    print(f"가변 키워드 인자 (**kwargs_example): {kwargs_example}") # 딕셔너리

print("--- 복합 함수 호출 예시 1 ---")
complex_function("필수값", 1, 2, 3, default_arg="새로운 기본값", name="Python", version=3.9)
# 출력:
# 고정/필수 인자 (required_arg): 필수값
# 기본값 인자 (default_arg): 새로운 기본값
# 가변 위치 인자 (*args_example): (1, 2, 3)
# 가변 키워드 인자 (**kwargs_example): {'name': 'Python', 'version': 3.9}

print("\n--- 복합 함수 호출 예시 2 (기본값 인자 생략) ---")
complex_function("필수값2", "a", "b", job="Developer")
# 출력:
# 고정/필수 인자 (required_arg): 필수값2
# 기본값 인자 (default_arg): default
# 가변 위치 인자 (*args_example): ('a', 'b')
# 가변 키워드 인자 (**kwargs_example): {'job': 'Developer'}

이러한 가변 인자 기능은 함수의 유연성을 극대화하여 다양한 상황에 대응할 수 있는 강력한 코드를 작성할 수 있게 해 줍니다.

반응형

 

4. 간결한 함수 표현 – 람다(lambda)의 사용법

Java 8부터 도입된 람다 표현식(Lambda Expressions)은 익명 함수를 간결하게 정의할 수 있게 해 주어 함수형 프로그래밍 스타일을 지원합니다.

Python에도 유사한 개념인 '람다 함수(Lambda Functions)'가 있으며, 역시 익명 함수를 간결하게 표현할 때 사용됩니다.

 

✔️ Java 람다 표현식 예시:

import java.util.Arrays;
import java.util.List;
import java.util.Collections;
import java.util.Comparator;

public class LambdaExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

        // Java 람다를 사용하여 문자열 길이를 기준으로 리스트 정렬
        // Comparator 인터페이스의 추상 메서드 compare(T o1, T o2)를 람다로 구현
        Collections.sort(names, (s1, s2) -> s1.length() - s2.length());
        System.out.println("정렬 후: " + names); // 출력: 정렬 후: [Bob, Alice, Charlie]

        // Function 인터페이스를 이용한 예시
        java.util.function.Function<Integer, Integer> addFive = (x) -> x + 5;
        System.out.println("5 더하기: " + addFive.apply(10)); // 출력: 5 더하기: 15
    }
}

Java 람다는 함수형 인터페이스의 추상 메서드를 구현하는 데 사용되며, 코드 블록 내부에 여러 줄의 로직을 포함할 수 있습니다.

 

✔️ Python 람다 함수 예시:

Python의 람다 함수는 lambda 키워드를 사용하여 한 줄로 간단한 익명 함수를 정의할 때 사용됩니다.

주로 map(), filter(), sorted()와 같은 고차 함수(Higher-Order Functions)의 key 인자나 콜백 함수(Callback Function)로 사용될 때 그 진가를 발휘합니다.

# 람다 기본 구조: lambda 인자들: 표현식 (expression)
# 즉, 입력 인자들을 받아서 '표현식'을 계산하여 반환하는 익명 함수
add_one = lambda x: x + 1
print(f"람다로 5에 1 더하기: {add_one(5)}") # 출력: 람다로 5에 1 더하기: 6

multiply = lambda a, b: a * b
print(f"람다로 3과 4 곱하기: {multiply(3, 4)}") # 출력: 람다로 3과 4 곱하기: 12

 

✔️ 주요 차이점 및 Python 람다의 특징:

🔸단일 표현식(Single Expression)만 가능:

Python 람다의 가장 큰 제약사항입니다. Java 람다와 달리 여러 줄의 문장(statement)이나 복잡한 로직을 포함할 수 없습니다.

람다 본문에는 단 하나의 결과값을 반환하는 표현식만 올 수 있습니다. if-else 같은 조건문도 '표현식' 형태로 (삼항 연산자처럼) 사용해야 합니다.
🔸이름 없음 (익명 함수):

람다는 이름이 없는 함수이므로, 정의와 동시에 사용되거나 다른 함수의 인자로 전달됩니다.
🔸간결성:

간단한 연산이나 로직을 즉석에서 정의하여 사용하기에 매우 간결합니다.

 

✔️ Python 람다 활용 예시:

람다는 주로 다른 함수의 인자로 전달되어 콜백 함수처럼 사용될 때 강력합니다.

Python 람다 활용 예시
Python 람다 활용 예시

# 1. list를 정렬하는 sorted() 함수와 함께 사용 (문자열 길이 기준)
names = ["Alice", "Bob", "Charlie", "David"]
# key 인자에 람다 함수를 전달하여 각 문자열의 길이를 기준으로 정렬
sorted_names = sorted(names, key=lambda s: len(s))
print(f"길이 기준 정렬: {sorted_names}") # 출력: 길이 기준 정렬: ['Bob', 'Alice', 'David', 'Charlie']

# 2. map() 함수와 함께 사용 (각 요소에 10 더하기)
# map(함수, 이터러블)은 이터러블의 각 요소에 함수를 적용하여 새로운 이터레이터를 반환
numbers = [1, 2, 3, 4, 5]
add_ten = list(map(lambda x: x + 10, numbers)) # map 결과는 이터레이터이므로 list()로 변환
print(f"각 요소에 10 더하기: {add_ten}") # 출력: 각 요소에 10 더하기: [11, 12, 13, 14, 15]

# 3. filter() 함수와 함께 사용 (짝수만 필터링)
# filter(함수, 이터러블)은 함수가 True를 반환하는 요소들만 필터링하여 이터레이터를 반환
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(f"짝수만 필터링: {even_numbers}") # 출력: 짝수만 필터링: [2, 4]

# 4. 조건부 논리 포함 예시 (삼항 연산자처럼)
is_even_odd = lambda x: "Even" if x % 2 == 0 else "Odd"
print(f"7은? {is_even_odd(7)}") # 출력: 7은? Odd
print(f"10은? {is_even_odd(10)}") # 출력: 10은? Even

복잡한 로직이나 여러 줄의 문장이 필요한 경우에는 람다 대신 일반 def 키워드를 사용한 함수를 정의하는 것이 가독성 면에서 더 좋습니다. 람다는 '간결하게 한 번 사용할' 목적으로 설계되었습니다.

 

5. 메서드의 3가지 유형 – 인스턴스/클래스/정적 메서드 비교

✔️ 인스턴스 메소드(Instance Method):

인스턴스 메서드는 특정 객체(인스턴스)에 바인딩된 메서드입니다.

이 메서드는 해당 인스턴스의 속성에 접근하거나 수정하는 등, 인스턴스 고유의 상태와 관련된 작업을 수행할 때 사용됩니다.

 

🔸Java 예시:

Java에서도 클래스 내부에서 정의된 메서드는 기본적으로 인스턴스 메서드입니다.

객체가 생성된 후 호출되며, 객체의 상태(필드)에 접근할 수 있습니다.

public class Person {
    private String name;

    // 생성자
    public Person(String name) {
        this.name = name;
    }

    // 인스턴스 메서드
    public String greet() {
        return "Hello, I'm " + this.name;
    }

    public static void main(String[] args) {
        Person p = new Person("Alice");
        System.out.println(p.greet());  // Hello, I'm Alice
    }
}

- this.name은 현재 인스턴스의 name 필드에 접근하는 코드입니다.
- greet()는 Person 객체를 생성한 후 p.greet()로 호출되며, 해당 인스턴스의 상태에 따라 결과가 달라질 수 있습니다.
- Java에서는 this 키워드가 선택적으로 사용되며, 필드와 지역 변수명이 충돌하지 않는다면 생략 가능합니다.

 

🔸Python 예시:

Python에서 클래스 내부에 정의된 일반적인 함수는 인스턴스 메서드(instance method)입니다.

이 메서드는 해당 클래스의 인스턴스를 통해 호출되며, 인스턴스 변수에 접근하거나 조작할 수 있습니다.

class Person:
    def __init__(self, name):
        self.name = name  # 인스턴스 변수 정의

    def greet(self):      # 인스턴스 메서드
        return f"Hello, I'm {self.name}"

p = Person("Alice")       # 클래스 인스턴스 생성
print(p.greet())          # Hello, I'm Alice

- def greet(self)에서 self는 메서드가 속한 인스턴스 자신을 가리킵니다.
- self.name은 해당 인스턴스가 가지고 있는 name 속성에 접근합니다.
- Python에서는 모든 인스턴스 메서드는 첫 번째 인자로 self를 명시해야 합니다. (자동으로 전달됨)
- p.greet() 호출 시, 내부적으로는 Person.greet(p)와 같은 형태로 호출됩니다.

 

🔸self vs this:

구분 Python(self) Java(this)
의미 인스턴스 자신을 나타냄 인스턴스 자신을 나타냄
선언 방식 메서드 첫 번째 인자로 명시 자동 전달, 생략 가능
사용 예 self.name this.name
호출 방식 p.method() → 내부적으로 Class.method(p) p.method()

 

✔️클래스 메서드 – @classmethod

클래스 메서드는 클래스 자체를 대상으로 동작하는 메서드입니다.
즉, 인스턴스(객체)가 아닌 클래스 레벨에서 작동하며, 클래스 변수(class variable)를 조작하거나 클래스와 관련된 동작을 정의할 때 유용합니다.

 

🔸Java 예시:

Java에는 Python의 @classmethod에 정확히 대응되는 문법은 없습니다. 하지만 static 메서드 + 클래스(static) 변수 조작으로 유사하게 구현할 수 있습니다.

public class Counter {
    private static int count = 0;

    public static int increment() {
        count++;
        return count;
    }

    public static void main(String[] args) {
        System.out.println(Counter.increment());  // 1
        System.out.println(Counter.increment());  // 2
    }
}

- static 키워드를 사용하면 클래스 레벨의 필드와 메서드를 정의할 수 있습니다.
- static int count는 모든 인스턴스가 공유하는 클래스 변수입니다.
- static int increment()는 클래스 메서드로 작동하며, count를 직접 조작합니다.
- Python과 달리 Java에서는 데코레이터나 특별한 키워드는 없고, static으로만 표현합니다.

 

🔸Python 예시:

Python에서는 @classmethod 데코레이터를 통해 명확히 선언합니다.

class Counter:
    count = 0  # 클래스 변수

    @classmethod
    def increment(cls):
        cls.count += 1
        return cls.count

print(Counter.increment())  # 1
print(Counter.increment())  # 2

- count는 클래스 변수로, 모든 인스턴스가 공유하는 변수입니다.
- @classmethod는 해당 메서드가 클래스 메서드임을 나타내는 데코레이터입니다.
- increment(cls)에서 cls는 해당 메서드가 소속된 클래스 자체를 가리킵니다 (self가 인스턴스를 가리키듯).
- 메서드 내부에서는 cls.count를 통해 클래스 변수에 접근하고 값을 증가시킵니다.
- 여러 인스턴스가 있더라도 count는 하나의 클래스 변수이기 때문에, 공유되어 같이 증가합니다.


✔️ 정적 메서드 – @staticmethod

정적 메서드는 클래스나 인스턴스의 상태와 무관하게, 단지 기능(functional logic)을 제공하는 메서드입니다.
즉, 클래스 내에 정의되지만 클래스나 인스턴스를 전혀 참조하지 않는 메서드입니다.

보통 유틸리티 기능(계산, 변환, 문자열 처리 등)에 자주 사용되며, 공통 로직을 재사용하기 위해 클래스 내부에 배치합니다.

 

🔸Java 예시:

Java는 static 키워드를 사용하여 정적 메서드를 정의합니다. Python과 유사하게 인스턴스를 생성하지 않고 사용할 수 있습니다.

public class MathUtil {
    public static int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        System.out.println(MathUtil.add(2, 3));  // 5
    }
}

- static 키워드가 붙은 메서드는 클래스에 속하며, 인스턴스와 관계없이 호출할 수 있습니다.
- MathUtil.add(2, 3)처럼 클래스 이름으로 직접 호출합니다.
- 인스턴스를 통해 호출하는 것은 금지되어 있지는 않지만 비권장 방식입니다.

 

🔸Python 예시:

Python에서는 @staticmethod 데코레이터를 사용해 정적 메서드를 정의합니다.

class MathUtil:
    @staticmethod
    def add(a, b):
        return a + b

print(MathUtil.add(2, 3))  # 5

- add(a, b)는 단순히 두 숫자를 더하는 기능만 수행하며, self나 cls를 받지 않습니다.
- @staticmethod 데코레이터는 이 메서드가 클래스/인스턴스를 전혀 참조하지 않는 함수임을 명시합니다.
- MathUtil.add(2, 3)처럼 클래스 이름으로 직접 호출하며, 인스턴스를 만들 필요가 없습니다.
- 인스턴스로도 호출할 수는 있지만, 내부적으로 self를 사용하지 않기 때문에 인스턴스를 생성할 필요는 없습니다.

 

✔ 마무리 - Python 함수의 유연함을 Java 시각에서 이해하기

Java에서는 메서드가 클래스에 종속되고, 접근 제어자와 반환 타입을 명확히 지정해야 하는 정형화된 구조가 일반적입니다.

반면, Python의 함수는 클래스 밖에서도 자유롭게 정의할 수 있으며, 기본값 인자, 키워드 인자, 가변 인자 등을 통해 함수 정의와 호출의 유연성을 극대화합니다.


이러한 차이는 단순히 문법의 차이가 아니라, 언어가 추구하는 철학의 차이입니다.

🔸Java는 명확성과 안정성을 중시합니다.

🔸 Python은 간결함과 개발 속도를 우선합니다.


Python에서는 오버로딩 없이 하나의 함수로 다양한 상황을 처리할 수 있고, 함수도 일급 객체이므로 변수처럼 전달하거나 반환할 수 있는 고차 함수 프로그래밍도 자연스럽게 가능합니다.

또한 self, cls, @staticmethod 같은 메서드 유형은 객체지향과 함수형 프로그래밍의 조화를 지원합니다.


Python의 함수는 선언적이면서도 표현력이 풍부한 도구입니다.

Java 개발자 입장에서는 처음엔 생략된 정보(타입, 접근 범위 등)로 인해 불안할 수 있지만, 점차 그 자유로움과 생산성을 체감하게 될 것입니다.

 

※ 게시된 글 및 이미지 중 일부는 AI 도구의 도움을 받아 생성되거나 다듬어졌습니다.
반응형

 

반응형