2014년 10월 7일 화요일

파이썬 기초 강좌 - 클래스를 정의하고 인스턴스를 생성해서 사용하는 법을 학습합니다.

클래스 선언: 일반적으로 클래스는 데이터와 메서드로 구성됩니다.
>>> class MyClass:
 """ 아주 간단한 클래스 """
 pass
>>> dir()
['MyClass', '__builtins__', '__doc__', '__name__', '__package__']
>>> type(MyClass)
<type 'classobj'>
데이터와 메서드가 추가된 클래스:
>>> class Person:
 Name = "Default Name"
 def Print(self):
  print("My Name is {0}".format(self.Name))
>>> p1 = Person()
>>> p1.Print()
My Name is Default Name
>>> p1.Name = "전우치"
>>> p1.Print()
My Name is 전우치
인스턴스 객체의 이름공간에 변경된 데이터를 저장합니다.
파이썬의 설계 철학은 개발자에게 많은 제약을 가하지 않는 것이기에 기본 접근 권한은 public으로 되어 있습니다.

클래스 객체와 인스턴스 객체의 이름공간이 다릅니다. 그래서 아래의 순서로 이름을 찾습니다: 인스턴스 객체 영역 => 클래스 객체 영역 => 전역 영역
파이썬에서는 런타임에 각 클래스와 인스턴스 이름공간에 멤버 변수를 추가하거나 삭제할 수 있다. C#이나 자바와는 다른 특징입니다.
>>> class Person:
 name = "Default Name"
>>>
>>> p1 = Person()
>>> p2 = Person()
>>> print("p1's name", p1.name)
p1's name Default Name
>>> print("p2's name", p2.name)
p2's name Default Name
>>>
>>> p1.name = "전우치"
>>> print("p1's name", p1.name)
p1's name 전우치
>>> print("p2's name", p2.name) ==> 서로 다른 값을 가지고 있다.
p2's name Default Name
• 클래스에 새로운 멤버 변수 title 추가
>>> Person.title = "New title"
>>> print("p1's title:", p1.title)
p1's title: New title
>>> print("p2's title:", p2.title)
p2's title: New title
>>> print("Person's title:", Person.title)
Person's title: New title

파이썬 에서는 클래스 객체와 인스턴스 객체에 동적으로 멤버 변수를 추가할 수 있습니다. P1객체에 추가한 age는 p1에서만 접근이 가능합니다. 
• >>> p1.age = 20
• >>> print("p1's age:", p1.age)
• p1's age: 20
• >>> print("p2's age:", p2.age)
• Traceback (most recent call last):
•   File "<pyshell#23>", line 1, in <module>
•     print("p2's age:", p2.age)
• AttributeError: 'Person' object has no attribute 'age'

멤버 메서드에서 self가 누락된 경우 아래와 같이 실행될 수 있습니다. 전역변수 str과 멤버변수 str이 겹치는 경우입니다.
str = "Not Class Member"
class GString:
    str = ""
    def Set(self, msg):
        self.str = msg
    def Print(self):
        print(str) ==>이 부분이 버그!
g = GString()
g.Set("First Message")
g.Print()
>>>
Not Class Member

인스턴스 객체가 어떤 클래스로부터 생성됐는지를 확인하는 방법은 isinstance()함수를 사용합니다. 버전 3이후로는 암묵적으로 object객체를 상속받습니다. 자료형 또한 object객체에서 파생됩니다.
>>> class Person:
     pass
>>> class Bird:
     pass
>>> class Student(Person):
     pass
>>> p, s = Person(), Student()
>>> print("p is instance of Person:", isinstance(p, Person))
p is instance of Person: True
>>> print("s is instance of Person:", isinstance(s, Person))
s is instance of Person: True
>>> print("p is instance of object:", isinstance(p, object))
p is instance of object: True
>>> print("p is instance of Bird:", isinstance(p, Bird))
p is instance of Bird: False
>>> print("int is instance of object:", isinstance(int, object))
int is instance of object: True

생성자, 소멸자 메서드: 자바나 C#과 동일하게 파이썬에서도 초기화 작업을 위해 생성자 메서드를 메모리 해제 등의 종료작업을 위해 소멸자 메서드를 지원합니다. 생성자 메서드는 인스턴스 객체가 생성될 때 자동으로 호출되며, 소멸자는 인스턴스 객체의 레퍼런스 카운트가 0이 될 때 호출됩니다.
class MyClass:
    def __init__(self, value):  ==>생성자
        self.Value = value
        print("Class is created! Value = ", value)
    def __del__(self): ==>소멸자
        print("Class is deleted!")

참조 카운트를 증가시키고 감소 시키는 코드:
레퍼런스 카운트가 2로 증가되었다가 1에서 0이 되면 자동으로 소멸자를 호출합니다.
# -*- 생성자와 소멸자 그리고 참조 카운트 관리  -*-
class MyClass:
    def __init__(self, value):
        self.Value = value
        print("Class is created! Value = ", value)
    def __del__(self):
        print("Class is deleted!")
d = MyClass(10)
d_copy = d
del d
del d_copy

d = MyClass(10)   #참조 카운트 1
d_copy = d   #참조 카운트 2
del d  #참조 카운트 1로 감소
del d_copy  #참조 카운트 0 (여기서 소멸자 호출)

정적 메서드 와 클래스 메서드:
메서드의 확장 형태로 정적 메서드, 클래스 메서드가 있습니다. 정적 메서드는 클래스를 통해 직접 호출할 수 있는 메서드입니다. 메서드를 정의할 때 인스턴스 객체를 참조하는 self라는 인자를 선언하지 않습니다. 클래스 메서드는 암묵적으로 첫 인자로 클래스 객체가 전달됩니다.

<호출할 메서드 이름> = staticmethod(클래스 내에 정의한 메서드 이름)
<호출할 메서드 이름> = classmethod(클래스 내에 정의한 메서드 이름)

class CounterManager:
    insCount = 0
    def __init__(self):
        CounterManager.insCount += 1
    def staticPrintCount():  è 정적 메서드 정의
        print("Instance Count: ", CounterManager.insCount)
    SPrintCount = staticmethod(staticPrintCount) #정적 메서드 등록
   
    def classPrintCount(cls): è클래스 메서드 정의(암묵적으로 첫 인자는 클래스를 받음)
        print("Instance Count: ", cls.insCount)
    CPrintCount = classmethod(classPrintCount) #클래스 메서드로 등록
       
a, b, c = CounterManager(), CounterManager(), CounterManager()
#정적 메서드로 인스턴스 객체 개수를 출력
CounterManager.SPrintCount()
b.SPrintCount()
#클래스 메서드로 인스턴스 객체 개수를 출력
CounterManager.CPrintCount()
b.CPrintCount()

정적 메서드로 출력하는 경우 암묵적으로 받는 첫 인자가 필요하지 않습니다. 이렇게 정의한 메서드는 정적 메서드로 등록해야 하며, 호출할 때 등록된 이름으로 호출해야 합니다. 클래스 메서드의 경우 첫 인자는 암묵적으로 클래스 객체가 되며, 이 역시 클래스 메서드로 등록해야 호출할 때 암묵적으로 클래스 객체를 전달합니다. 이렇게 정의된 정적 메서드와 클래스 메서드는 클래스뿐 아니라 인스턴스 객체를 통해서도 호출할 수 있습니다.

private 멤버 속성: 앞의 CounterManager클래스에서 멤버 변수 insCount는 중요한 변수임에도 불구하고 파이썬에서 기본적으로 public속성을 갖기 때문에 클래스의 외부에서 접근하거나 변경할 수 있습니다. 그래서 파이썬에서는 이름 변경(Naming Mangling)으로 문제를 해결했습니다. 즉 클래스 내의 멤버 변수나 함수를 정의할 때 ‘__’로 시작하는 경우 클래스 외부에서 참조할 때 자동적으로 ‘_클래스이름__멤버이름’으로 변경됩니다.
class CounterManager:
    __insCount = 0
    def __init__(self):
        CounterManager.__insCount += 1
    def staticPrintCount():
        print("Instance Count: %d" % CounterManager.__insCount)
    SPrintCount = staticmethod(staticPrintCount)  #정적 메서드로 등록
a, b, c = CounterManager(), CounterManager(), CounterManager()
CounterManager.SPrintCount()
   
print(CounterManager.__insCount)  #이렇게 접근하는 것을 에러!
Instance Count: 3
Traceback (most recent call last):
  File "C:/workPython/private멤버속성.py", line 12, in <module>
    print(CounterManager.__insCount)
AttributeError: type object 'CounterManager' has no attribute '__insCount'
>>>
>>> print(CounterManager._CounterManager__insCount)  #이렇게 접근하는 것은 가능!
3

댓글 없음:

댓글 쓰기

참고: 블로그의 회원만 댓글을 작성할 수 있습니다.

5월 14일 새벽에 chatGPT 4o가 발표되었습니다. 옵티마이즈, 옴니라는 의미인데 실시간 통역, 다자간 회의, 멀티모달 기능의 강화등이 보이네요.

  초격차로 OpenAI진영이 다시 앞서가는 모양을 보여주고 있습니다. 저도 새벽에 일어나자 마자 올라온 영상들과 글을 정리하고 있습니다. ㅎㅎ 영화 HER의 사진이 새벽에 많이 올라왔었는데 저도 안본 영화입니다. 주말에 한번 봐야 할 것 같습니다....