{ }codelper

배우기 › Python

언어마다 다른 것 · 37

클래스와 객체

데이터(필드)와 동작(메서드)을 한 틀에 묶고, 그 틀로 객체를 여러 개 만들어요.

이 단원은 Python · JavaScript · TypeScript · Java · C# · C++에서 배워요.
C에는 클래스가 없어서 구조체(struct)와 함수로 같은 일을 해요(구조체 단원 참고).
크레이콘은 직접 만드는 클래스가 없고 사전()에 학생["이름"]처럼 담아요.

클래스는 설계도이고, 객체는 그 설계도로 찍어 낸 실물이에요.
아래 예제는 이름과 점수를 가진 Student 클래스로 학생을 여러 명 만들고, 점수 높은 순으로 정렬해 등급과 함께 보여 줘요.

class Student:    def __init__(self, name, score):        self.name = name        self.score = score     def grade(self):        if self.score >= 90:            return "A"        if self.score >= 80:            return "B"        return "C"     def describe(self):        return f"{self.name} {self.score} {self.grade()}"  n = int(input())students = []for _ in range(n):    name, score = input().split()    students.append(Student(name, int(score))) students.sort(key=lambda s: s.score, reverse=True)for s in students:    print(s.describe())
stdin
3
Mina 82
Joon 95
Sora 78
stdout
Joon 95 A
Mina 82 B
Sora 78 C

핵심

  • 클래스에는 객체가 가질 데이터(필드)와 객체가 할 수 있는 일(메서드)을 적어요.
  • 생성자는 객체를 만들 때 처음 값을 채우는 특별한 함수예요.
  • 메서드 안에서 객체 자신은 this(Python은 self)예요.
    매개변수와 이름이 겹치면 this.name = name처럼 구분해요.
  • 접근 제한자(public, private)로 밖에서 쓸 수 있는 멤버를 정해요.
    필드는 보통 숨기고 메서드나 속성으로 읽게 해요.
  • 객체 목록은 필드를 기준으로 정렬해요.
    정렬 함수에 "무엇을 비교할지"를 넘기면 돼요.

언어별로 쓰는 법

Pythonclass Student: 안에 생성자 def __init__(self, name, score):.
필드는 self.name = name처럼 만들고, 모든 메서드의 첫 매개변수는 self.
객체는 new 없이 Student("Mina", 82).
정렬: students.sort(key=lambda s: s.score, reverse=True)
JavaScriptclass Student { constructor(name, score) { this.name = name; } }.
객체는 new Student("Mina", 82)이고, new를 빼면 TypeError: Class constructor Student cannot be invoked without 'new'.
정렬: students.sort((a, b) => b.score - a.score)
TypeScriptJavaScript와 같은 모양에 필드를 score: number;처럼 미리 선언해요.
private·readonly는 컴파일할 때만 검사하고 실행할 때는 사라져요.
정말 숨기려면 JavaScript의 #score 비공개 필드
Java생성자는 클래스 이름과 같고 돌려주는 타입을 안 적어요.
필드는 private으로 숨기고 getScore() 같은 게터로 읽어요.
제한자를 안 쓰면 같은 패키지에서만 보여요.
정렬: students.sort(Comparator.comparingInt(Student::getScore).reversed())
C#속성 public int Score { get; }을 쓰면 밖에서 s.Score처럼 필드같이 읽어요.
제한자를 안 쓴 멤버는 private.
정렬: students.Sort((a, b) => b.Score.CompareTo(a.Score))
C++class는 기본이 private, struct는 public이고 차이는 그것뿐이라 public:·private:을 직접 적어요.
생성자는 초기화 목록 : name_(name), score_(score), 메서드 뒤 const는 "객체를 바꾸지 않아요"라는 약속.
객체는 new 없이 Student s("Mina", 82);.
정렬: std::sort에 람다 [](const Student& a, const Student& b) { return a.score() > b.score(); }

자주 하는 실수

메서드에 self를 빠뜨렸어요Python

class Student:
    def grade():
        return "A"

Student().grade()

→ TypeError: Student.grade() takes 0 positional arguments but 1 was given. 메서드 안에서 self. 없이 score라고 쓰면 NameError예요

첫 매개변수로 self를 두고, 필드는 늘 self.score처럼 읽어요.

기본값에 목록 []을 뒀어요Python

def __init__(self, name, tags=[]):
    self.tags = tags

→ 그 목록은 def가 실행될 때 한 번만 만들어져요. 한 학생에게 넣은 태그가 다른 학생에게도 보여요

tags=None으로 받고, 생성자 안에서 새 목록을 만들어요.

객체 내용을 ==로 비교했어요Java · C#

new Student("Mina", 82) == new Student("Mina", 82)

→ false — ==는 같은 객체인지를 봐요. equals도 다시 정의하기 전에는 ==와 똑같이 동작해요

내용은 equals(C#은 Equals)로 비교하고, 그 메서드를 직접 다시 정의하거나 record를 써요.

언어마다 다른 점
b = a 다음에 b를 바꾸면 Python·JavaScript·TypeScript·Java·C#에서는 a도 바뀌어요(두 이름이 같은 객체를 가리켜요).
C++는 객체가 값이라 Student b = a;와 for (Student s : students)가 복사본을 만들어서, 원본을 다루려면 Student&(읽기만 하면 const Student&)를 써요.

연습 문제