Networks/Python

SK networks AI Camp - Python(Class)

코딩하는 Español되기 2024. 7. 16. 08:00

클래스에 대해 설명하기 전에 배운 꿀팁!

x = [1,2,3,4,5,6,7]

for i in x:
    print(i)

리스트를 for문으로 하나하나 출력하게 된다면 안 그래도 무거운 Python이기에 속도가 느려요.

위의 코드와 결과는 같으면서 빠르게 하는 방법이 있어요.

x = [1,2,3,4,5,6,7]
# 속도가 훠어얼씬 빠름, 함수로 감싸서 하면 빨라짐
for _, i in enumerate(x):  # _ 안 쓰면 ()에 감싸져서 인덱스가 같이 나옴 
    print(i)

위의 코드는 for문으로 그냥 돌린 것과 출력 결과는 같지만 속도면에서 빨라서 자주 사용한대요.


클래스

○ 변수와 함수를 묶어 놓은 개념

○ 클래스는 객체(데이터와 기능을 갖고 있는....)를 만들기 위한 설계도

인스턴스(Instance) : 클래스를 메모리에 객체화 하는 것

 

class GrandMother:              # 클래스 : 설계도
    family = 'grandparents'     # family(속성)

    def print_self(self):       # 메소드 : 클래스 내부 함수
        print(self)

LEE = GrandMother() # 인스턴스화(객체 생성)
type(GrandMother), type(LEE)

print(f'속성호출 : {GrandMother.family}') # 속성 호출
print(f'메소드호출 : {GrandMother.print_self()}') # 메소드 호출

self = 인스턴스를 의미 (무조건 class 안에 self 있어야 함!)


인스턴스

○ self

GrandMother.print_self()를 실행시킨 결과 에러가 발생

에러 내용 : self가 존재하지 않습니다.

여기서 self는 객체(인스턴스)를 나타내서 객체 생성(아래의 경우 LEE)을 통해서만 사용이 가능해요.

(속성 호출(GrandMother.family)인 경우에는 self가 없으므로 사용이 가능해요.)

아래와 같이 하면 출력이 가능해요.

LEE = GrandMother()
LEE.print_self()

○ __init__

객체를 생성할 때, 생성자(__init__)라는 함수를 통해서 만들어져요.

만약 생성자를 선언하지 않으면 파이썬은 자동으로 만들어줘요.

객체를 생성할 때, 특별한 작업이 필요하다면 생성자를 작성해서 실행시킬 수 있어요.

  ● 인스턴스 속성과 클래스 속성의 차이

class Person:
    name = "person name"
    age = 18

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

# 클래스 속성값
print(f'Person.name : {Person.name} / Person.age : {Person.age}')

  ● 인스턴스에서 값 변경 (p_instant1)

# 인스턴스에서 값 변경(p_instant1)
p_instant1 = Person('인스턴트1')
p_instant1.age = 20

# 인스턴스 속성값
print(f'p_instant1.name : {p_instant1.name} / p_instant1.age : {p_instant1.age}')

  ● 인스턴스에서 값 변경2 (p_instant2)

# 인스턴스에서 값 변경(p_instant2)
# p_instant1 과 p_instant2는 다른 객체!
p_instant2 = Person('인스턴트222')


# 인스턴스 속성값
print(f'p_instant2.name : {p_instant2.name} / p_instant2.age : {p_instant2.age}')

인스턴스 1(p_instant1)과 인스턴스 2(p_instant2)는 서로 다른 객체

  ● 클래스 속성 값

# 클래스의 속성값
print(f'Person.name : {Person.name} / Person.age : {Person.age}')
# 인스턴스 생성을 통해 속성값을 여러번 변경했지만 클래스 속성값 변화 X

인스턴스를 여러 번 생성하여 속성을 변경 했지만 클래스의 속성값은 변화가 없다!!!


상속(inheritance)

부모 클래스의 내용(속성, 메소드)를 물려받는 자식 클래스가 가지게 되는 것

형태

class 부모클래스:
  ... 부모 코드(속성, 메소드) ...
 
class 자식클래스(부모클래스):
  ... 자식 코드(속성, 메소드) ... # 부모 클래스의 코드도 사용 가능!!!

예제로 알아볼게요.

우선 부모와 자식 클래스를 생성해볼게요.

부모 클래스 : GrandMother

자식 클래스 : father

# 부모 클래스
class GrandMother:
    family = "Hello World"
    name = "GrandMother"

    def print_self(self):
        print(self)
    
    def print_HI():
        print('HI!')
        
# 자식 클래스
class father(GrandMother):
    name = 'father'

    def __init__(self,name,age):
        self.name = name
        self.age = age
        self.home = 'seoul'

father에는 print_HI 메서드가 없지만 GrandMother을 상속받아서 print_HI 메서드를 사용 가능해요.

father.print_HI()

child는 father을 상속받았어요. father이 GrandMother을 상속받았기에 child도 print_HI 메서드를 사용가능해요.

즉 여러 번 상속이 가능해요.

또 child.family를 하였더니 GrandMother에 있는 'Hello World'가 나와요.

class child(father):
    name = 'child'

child.print_HI(), child.family

Override

부모로부터 받은 메서드 또는 속성을 수정하고 싶을 때 자식 클래스에서 재정의를 해요.

class PlayerCharacter:
    def __init__(self,hp=100, exp=0):
        self.hp = hp
        self.exp = exp

    def attack(self):
        print('공격하기')
        self.exp = self.exp + 2
    
    def defend(self):
        print('방어하기')
        self.exp = self.exp + 1

Wizard는 PlayerCharacter을 상속받아서 defend를 수정해 주었어요. 이것이 메서드 오버라이딩이에요.

 

class Wizard(PlayerCharacter): #상속 받기
    def __init__(self, mp):
        super().__init__()      # 부모클래스의 생성자를 실행하겠다.
        self.mp = mp
    
    def magic_skill(self):
        print('마법 공격')
        self.mp = self.mp - 2
    
    # 메소드 오버라이딩
    def defend(self):
        print('마법사가 방어하기')
        self.exp = self.exp + 3

Wizard 객체를 생성하여서 20을 하였더니 exp는 0이 나왔어요.

 

player = Wizard(20)
player.exp

defend 메서드를 실행하였더니 PlayerCharacter의 메서드가 아닌 오버라이딩된 '마법사가 방어하기'가 출력이 돼요.

player.defend()
player.exp

playerCharacter 객체를 생성한 origin_player defend 메서드를 실행하였더니 방어하기가 출력이 돼요.

origin_player = PlayerCharacter()
origin_player.defend()
origin_player.exp


접근 지정자(Access Specifiers)

○ Public

모든 멤버(속성, 메서드)는 default가 공용입니다. 모든 멤버는 객체 외부에서도 액세스를 할 수 있어요.

class Student:
    schoolName = 'XYZ School' # class Attribute(클래스 내부 변수)

    def __init__(self, name, age):
        self.name = name # instance Attribute(인스턴스 내부 변수)
        self.age = age  # instance Attribute(인스턴스 내부 변수)

    def display(self):  # public method
        print('This is public method')

std = Student('Steve', 25)

std.schoolName, std.name

값을 변경하게 되면? 변경될까요? 변경된답니다.

std.name = 'Dipa'
std.name

std.display()

○ Private

모든 프라이빗 멤버(속성, 메서드)는 객체 외부에서 엑세스가 불가합니다.

프라이빗 멤버들은 객체 내부에서만 호출이 가능해요.

class Student:
    __schoolName = 'XYZ School' # private class Attribute(프라이빗 클래스 내부 변수)

    def __init__(self, name, age):
        self.name = name # instance Attribute(인스턴스 내부 변수)
        self.age = age  # instance Attribute(인스턴스 내부 변수)

    def __display(self):  # private method
        print('This is public method')
        
std = Student("Bill", 25)
std.name

여기서 없는 __salary를 호출한다면?

std.__salary

그렇다면 존재하는 변수 schoolName, 메소드 __display()를 입력하면??

존재하지 않는 Attribute라고 나오네요. 바로 '__'(언더바 2개)로 Private 설정을 해주었기 때문이에요.

std.__schoolName


Decorators

Decorator 관련 글

2024.07.12 - [컴퓨터 공학/Networks] - SK networks AI Camp - Python_함수

 

SK networks AI Camp - Python_함수

함수(Function)하나의 특별한 목적의 작업을 수행하기 위해 독립적으로 설계된 코드의 집합1. 용어  ○ 입력 변수(함수에 입력하는 변수) : 파라미터  ○  출력 변수(함수 결과) : 리턴 값 2. 왜 사

joowon582.tistory.com

○ @property

: 메서드를 속성으로 선언합니다.

○ @<properry-name>. setter : 속성에 값을 설정하는 속성에 대한 setter 메서드를 지정

○ @<property-name>. deleter : 속성을 삭제하는 속성으로 삭제방법을 지정

class Student:
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name
    
    @name.setter
    def name(self, value):
        self.__name = value
    
    @name.deleter   # Property-name, deleter decorator
    def name(self):
        print('Deleting...')
        del self.__name
s = Student('Steve')
s.name

s.name = 'Bill'
s.name

del s.name
s.name

@classmethod

○ 클래스 메서드를 선언

○ 첫 번째 매개변수 : 클래스 속성에 액세스 하는 데 사용할 수 있는 cls여야(아래 코드 참고)함

○ 클래스 메서드 : 클래스 속성에만 액세스 가능, 인스턴스 속성에는 엑세스 불가

                             ClassName.MethodName() 및 객체를 사용해 호출 가능

○ 클래스의 객체를 반환 가능

class Student:
    name = 'unknown'    # class attribute
    def __init__(self, name):
        self.age = 20   # instance attribute
        self.name = name    # instance attribute

    @classmethod
    def tostring(cls):
        print(f'StudentClass Attributes: name= {cls.name}')

Student.tostring(), Student.name

std = Student('test')   # 객체를 생성하여 메소드 호출도 가능
std.tostring(), std.name

class Student:
    name = 'unknown'    # class attribute
    def __init__(self, name):
        self.age = 20   # instance attribute
        self.name = name    # instance attribute

    @classmethod
    def tostring(cls):
        print(f'StudentClass Attributes: name= {cls.name}, age = {cls.age}')

Student.name

아래의 코드는 오류가 발생. Student 객체가 age가 없다고 하네요.

Student.tostring()

class Student:

    def __init__(self, name, age):
        self.age = age   # instance attribute
        self.name = name    # instance attribute

    @classmethod
    def getobjcet(cls, name="Steve", age=25):
        return cls(name, age)
 
std = Student('hi', 22)
std.name, std.age

다시 객체를 생성하면서 값을 지정하지 않으면 값이 초기값(Steve, 25)으로 변환

std = Student.getobjcet()
std.name, std.age

객체 생성할 때 값을 지정해 주면 값은 초기값이 X

std = Student.getobjcet('hi', 22)
std.name, std.age

@staticmethod

○ 클래스에서 정적 메서드를 선언

○ cls | self 매개변수를 가질 수 없음

정적메서드 : 클래스 속성이나 인스턴스 속성에 액세스 불가

                        ClassName을 사용해 정적메서드 호출 가능

MethodName() 및 object.MethodName()도 사용

○ 클래스의 객체를 반환 가능

class Student:
    name = 'unknown'

    def __init__(self):
        self.age = 20

    @staticmethod
    def tostring():
        print('Student Class')

Student.tostring()  # 그냥 메소드 호출

std = Student() # 객체 생성 후 메소드 호출
std.tostring()


Magic Methods

○ 메소드 명이 두 개의 언더바로 감싸져 있다.

○ 파이썬의 다양한 내장함수들이 클래스의 매직 메서드들을 호출해 결과를 만들어 냄

class MyDataset:
    def __init__(self, data):
        self.data = data
    
    def __call__(self, a):
        print(f'{a} 함수 호출 방법처럼 객체를 함수 호출하듯이 만들어주는 메소드')
        return len(self.data)
    
    def __getitem__(self, idx): # 인덱싱과 슬라이싱
        return self.data[idx]

data = list(range(50, 100))
dt = MyDataset(data)
print(dt(1004))
print('-'*30)
print(dt[:5])

Initialization and Construction(초기화 및 구성)

Initialization and Construction Description
__new__(cls, other) 객체의 인스턴스화에 의해 호출
__init__(self, other) __new__ 메소드에 의해 호출
__del__(self) 소멸자 방법
class Employee:
    def __new__(cls):
        print('__new__ magic method is called')
        inst = object.__new__(cls)
        return inst
    
    def __init__(self):
        print('__init__ magic method is called')
        self.name = 'Saka'

emp = Employee()

class Employee:
    def __init__(self, salary):
        self.salary = salary

    def __round__(self, n):
        return round(self.salary*10, n)
    
emp = Employee(33.33333)
round(emp, 2)

Unary operators and functions(단항 연산자 및 호출)

Unary operators and functions Description
__pos__(self) 단항 긍정문 호출 e.g. +someobject
__neg__(self) 단한 부정문 호출 e.g. -someobject
__abs__(self) 내장된 abs() 함수에 의해 호출
__invert__(self) ~ 연산자를 사용하여 반전 호출
__round__(self, n) 내장된 round() 함수에 의해 호출
__floor__(self) 내장된 math.floor() 함수에 의해 호출
__cell__(self) 내장된 math.cell() 함수에 의해 호출
__trunc__(self) 내장된 math.trunc() 함수에 의해 호출

 

* round(a, b) : a를 b이하 자릿수에서 반올림 e.g. round(3.141592, 2) ==> 3.14

* floor(a) : a의 내림값 반환

* cell(a) : a의 올림값 반환

* trunc(a) : 해당 값에서 0에 가까운 정수 선택(= 버림) e.g. math.trunc(1.5) ==> 1

* floor()와 trunc()의 차이

    ● 양수에서는 비슷하게 동작하지만 음수에서 다름.

       floor() 함수 : 음수에 대해서는 내림연산

       trunc() 함수 : 단순히 소수점 아래를 잘라내기 때문에 음수에 대해서는 소수점 이하를 올림 하는 효과

class Employee:
    def __init__(self, salary):
        self.salary = salary
    
    def __str__(self):
        return f'salary : {str(self.salary)}'

emp = Employee(33.3333)
str(emp)

String

String Magic Methods Description
__str__(self) 내장된 str() 메소드에 의해 호출되어 유형의 문자열 표현을 반환하고자 할때
__repr__(self) 내장된 repr()메소드에 의해 호출되어 기계가 읽을 수 있는 유형의 표현을 반환하고자 할때
__unicode__(self) 내장된 unicode() 메소드에 의해 호출되어 특정 유형의 유니코드 문자열 반환하고자 할때
__format__(self, formatstr) 내장된 string.format() 메소드에 의해 호출되어 새로운 스타일의 문자열 반환하고자 할때
__hash__(self) 내장된 hash() 메소드에 의해 호출되어 정수를 반환하고자 할때
__nonzero__(self) 내장된 bool() 메소드에 의해 호출되어  True | False를 반환하고자 할 때
__dir__(self) 클래스의 속성목록을 반환하기 위해 내장된 dir() 메소드에 의해 호출
__sizeof__(self) 내장된 sys.getsizeof() 메소드에 의해 호출되어 객체의 크기를 반환하고자 할 때

표준 라이브러리 함수의 경우 다음에 따로 포스팅하겠습니다!