Python 3-객체 지향

파이썬은 존재 한 이후로 객체 지향 언어였습니다. 이로 인해 클래스와 객체를 만들고 사용하는 것이 매우 쉽습니다. 이 장은 Python의 객체 지향 프로그래밍 지원을 사용하는 전문가가되는 데 도움이됩니다.

객체 지향 (OO) 프로그래밍에 대한 이전 경험이없는 경우 기본 개념을 파악할 수 있도록 이에 대한 입문 과정이나 적어도 일종의 자습서를 참조 할 수 있습니다.

그러나 다음은 OOP (Object-Oriented Programming)에 대한 간단한 소개입니다.

OOP 용어 개요

  • Class− 클래스의 모든 객체를 특성화하는 속성 집합을 정의하는 객체에 대한 사용자 정의 프로토 타입. 속성은 점 표기법을 통해 액세스되는 데이터 멤버 (클래스 변수 및 인스턴스 변수) 및 메서드입니다.

  • Class variable− 클래스의 모든 인스턴스가 공유하는 변수. 클래스 변수는 클래스 내에서 정의되지만 클래스의 메서드 외부에서 정의됩니다. 클래스 변수는 인스턴스 변수만큼 자주 사용되지 않습니다.

  • Data member − 클래스 및 그 객체와 관련된 데이터를 보유하는 클래스 변수 또는 인스턴스 변수.

  • Function overloading− 특정 기능에 하나 이상의 행동을 할당하는 것. 수행되는 작업은 관련된 개체 또는 인수의 유형에 따라 다릅니다.

  • Instance variable − 메서드 내에서 정의되고 클래스의 현재 인스턴스에만 속하는 변수.

  • Inheritance − 클래스의 특성을 파생 된 다른 클래스로 이전하는 것.

  • Instance− 특정 클래스의 개별 개체. 예를 들어 Circle 클래스에 속하는 객체 obj는 Circle 클래스의 인스턴스입니다.

  • Instantiation − 클래스의 인스턴스 생성.

  • Method − 클래스 정의에 정의 된 특별한 종류의 함수.

  • Object− 해당 클래스에 의해 정의 된 데이터 구조의 고유 한 인스턴스. 객체는 데이터 멤버 (클래스 변수 및 인스턴스 변수)와 메서드로 구성됩니다.

  • Operator overloading − 특정 연산자에 하나 이상의 기능 할당.

클래스 생성

클래스 문은 새로운 클래스 정의를 작성합니다. 클래스의 이름은 다음과 같이 키워드 class 다음에 콜론이 뒤 따릅니다.

class ClassName:
   'Optional class documentation string'
   class_suite
  • 클래스에는 다음을 통해 액세스 할 수있는 문서 문자열이 있습니다. ClassName.__doc__.

  • 그만큼 class_suite 클래스 멤버, 데이터 속성 및 함수를 정의하는 모든 구성 요소 문으로 구성됩니다.

다음은 간단한 Python 클래스의 예입니다.

class Employee:
   'Common base class for all employees'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print ("Total Employee %d" % Employee.empCount)

   def displayEmployee(self):
      print ("Name : ", self.name,  ", Salary: ", self.salary)
  • empCount 변수 는이 클래스의 모든 인스턴스간에 값이 공유되는 클래스 변수입니다. 이는 클래스 내부 또는 클래스 외부에서 Employee.empCount 로 액세스 할 수 있습니다 .

  • 첫 번째 메서드 __init __ () 는이 클래스의 새 인스턴스를 만들 때 Python이 호출하는 클래스 생성자 또는 초기화 메서드라고하는 특수 메서드입니다.

  • 각 메서드의 첫 번째 인수가 self 인 것을 제외하고 일반 함수와 같은 다른 클래스 메서드를 선언 합니다. Python 은 목록에 self 인수를 추가합니다 . 메서드를 호출 할 때 포함 할 필요가 없습니다.

인스턴스 개체 만들기

클래스의 인스턴스를 만들려면 클래스 이름을 사용하여 클래스를 호출하고 __init__ 메서드가 허용 하는 인수를 전달 합니다.

This would create first object of Employee class
emp1 = Employee("Zara", 2000)
This would create second object of Employee class
emp2 = Employee("Manni", 5000)

속성 액세스

객체와 함께 도트 연산자를 사용하여 객체의 속성에 액세스합니다. 클래스 변수는 다음과 같이 클래스 이름을 사용하여 액세스됩니다-

emp1.displayEmployee()
emp2.displayEmployee()
print ("Total Employee %d" % Employee.empCount)

이제 모든 개념을 종합하여

#!/usr/bin/python3

class Employee:
   'Common base class for all employees'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print ("Total Employee %d" % Employee.empCount)

   def displayEmployee(self):
      print ("Name : ", self.name,  ", Salary: ", self.salary)


#This would create first object of Employee class"
emp1 = Employee("Zara", 2000)
#This would create second object of Employee class"
emp2 = Employee("Manni", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print ("Total Employee %d" % Employee.empCount)

위의 코드가 실행되면 다음과 같은 결과가 생성됩니다.

Name :  Zara ,Salary:  2000
Name :  Manni ,Salary:  5000
Total Employee 2

언제든지 클래스와 객체의 속성을 추가, 제거 또는 수정할 수 있습니다.

emp1.salary = 7000  # Add an 'salary' attribute.
emp1.name = 'xyz'  # Modify 'age' attribute.
del emp1.salary  # Delete 'age' attribute.

일반 문을 사용하여 속성에 액세스하는 대신 다음 함수를 사용할 수 있습니다.

  • 그만큼 getattr(obj, name[, default]) − 객체의 속성에 액세스합니다.

  • 그만큼 hasattr(obj,name) − 속성이 존재하는지 여부를 확인합니다.

  • 그만큼 setattr(obj,name,value)− 속성을 설정합니다. 속성이 없으면 생성됩니다.

  • 그만큼 delattr(obj, name) − 속성을 삭제합니다.

hasattr(emp1, 'salary')    # Returns true if 'salary' attribute exists
getattr(emp1, 'salary')    # Returns value of 'salary' attribute
setattr(emp1, 'salary', 7000) # Set attribute 'salary' at 7000
delattr(emp1, 'salary')    # Delete attribute 'salary'

내장 클래스 속성

모든 Python 클래스는 다음과 같은 내장 속성을 유지하며 다른 속성과 마찬가지로 도트 연산자를 사용하여 액세스 할 수 있습니다.

  • __dict__ − 클래스의 네임 스페이스를 포함하는 사전.

  • __doc__ − 정의되지 않은 경우 클래스 문서 문자열 또는 없음.

  • __name__ − 클래스 이름.

  • __module__− 클래스가 정의 된 모듈 이름. 이 속성은 대화식 모드에서 "__main__"입니다.

  • __bases__ − 기본 클래스 목록에서 발생하는 순서대로 기본 클래스를 포함하는 빈 튜플.

위 클래스의 경우 이러한 모든 속성에 액세스 해 보겠습니다.

#!/usr/bin/python3

class Employee:
   'Common base class for all employees'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print ("Total Employee %d" % Employee.empCount)

   def displayEmployee(self):
      print ("Name : ", self.name,  ", Salary: ", self.salary)

emp1 = Employee("Zara", 2000)
emp2 = Employee("Manni", 5000)
print ("Employee.__doc__:", Employee.__doc__)
print ("Employee.__name__:", Employee.__name__)
print ("Employee.__module__:", Employee.__module__)
print ("Employee.__bases__:", Employee.__bases__)
print ("Employee.__dict__:", Employee.__dict__ )

위의 코드가 실행되면 다음과 같은 결과가 생성됩니다.

Employee.__doc__: Common base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: (<class 'object'>,)
Employee.__dict__: {
   'displayCount': <function Employee.displayCount at 0x0160D2B8>, 
   '__module__': '__main__', '__doc__': 'Common base class for all employees', 
   'empCount': 2, '__init__': 
   <function Employee.__init__ at 0x0124F810>, 'displayEmployee': 
   <function Employee.displayEmployee at 0x0160D300>,
   '__weakref__': 
   <attribute '__weakref__' of 'Employee' objects>, '__dict__': 
   <attribute '__dict__' of 'Employee' objects>
}

개체 삭제 (가비지 컬렉션)

Python은 불필요한 객체 (내장 유형 또는 클래스 인스턴스)를 자동으로 삭제하여 메모리 공간을 확보합니다. 파이썬이 더 이상 사용되지 않는 메모리 블록을 주기적으로 회수하는 프로세스를 가비지 컬렉션이라고합니다.

Python의 가비지 수집기는 프로그램 실행 중에 실행되며 객체의 참조 수가 0에 도달하면 트리거됩니다. 객체를 가리키는 별칭의 수가 변경되면 객체의 참조 수가 변경됩니다.

개체의 참조 횟수는 새 이름이 할당되거나 컨테이너 (목록, 튜플 또는 사전)에 배치 될 때 증가합니다. 객체의 참조 횟수는 del 로 삭제 되거나 참조가 다시 할당되거나 참조가 범위를 벗어나면 감소합니다. 객체의 참조 횟수가 0이되면 Python은 자동으로이를 수집합니다.

a = 40      # Create object <40>
b = a       # Increase ref. count  of <40> 
c = [b]     # Increase ref. count  of <40> 

del a       # Decrease ref. count  of <40>
b = 100     # Decrease ref. count  of <40> 
c[0] = -1   # Decrease ref. count  of <40>

일반적으로 가비지 수집기가 고아 인스턴스를 파괴하고 해당 공간을 회수하는시기를 알 수 없습니다. 그러나 클래스는 인스턴스가 파괴 되려고 할 때 호출되는 소멸 자라고 하는 특수 메서드 __del __ ()을 구현할 수 있습니다 . 이 방법은 인스턴스에서 사용하는 비 메모리 리소스를 정리하는 데 사용할 수 있습니다.

이 __del __ () 소멸자는 파괴 될 인스턴스의 클래스 이름을 출력합니다.

#!/usr/bin/python3

class Point:
   def __init__( self, x=0, y=0):
      self.x = x
      self.y = y
   def __del__(self):
      class_name = self.__class__.__name__
      print (class_name, "destroyed")

pt1 = Point()
pt2 = pt1
pt3 = pt1
print (id(pt1), id(pt2), id(pt3))   # prints the ids of the obejcts
del pt1
del pt2
del pt3

위의 코드가 실행되면 다음과 같은 결과가 생성됩니다.

140338326963984 140338326963984 140338326963984
Point destroyed

Note− 이상적으로는 별도의 파일에 클래스를 정의한 다음 import 문을 사용하여 주 프로그램 파일로 가져와야 합니다.

위의 예에서 Point 클래스의 정의가 point.py에 포함되어 있고 다른 실행 코드가 없다고 가정 합니다.

#!/usr/bin/python3
import point

p1 = point.Point()

클래스 상속

처음부터 시작하는 대신 새 클래스 이름 뒤에 괄호 안에 부모 클래스를 나열하여 기존 클래스에서 파생하여 클래스를 만들 수 있습니다.

자식 클래스는 부모 클래스의 속성을 상속하며 이러한 속성을 자식 클래스에 정의 된 것처럼 사용할 수 있습니다. 자식 클래스는 부모의 데이터 멤버와 메서드를 재정의 할 수도 있습니다.

통사론

파생 클래스는 부모 클래스와 매우 유사하게 선언됩니다. 그러나 상속 할 기본 클래스 목록은 클래스 이름 다음에 제공됩니다.

class SubClassName (ParentClass1[, ParentClass2, ...]):
   'Optional class documentation string'
   class_suite

#!/usr/bin/python3

class Parent:        # define parent class
   parentAttr = 100
   def __init__(self):
      print ("Calling parent constructor")

   def parentMethod(self):
      print ('Calling parent method')

   def setAttr(self, attr):
      Parent.parentAttr = attr

   def getAttr(self):
      print ("Parent attribute :", Parent.parentAttr)

class Child(Parent): # define child class
   def __init__(self):
      print ("Calling child constructor")

   def childMethod(self):
      print ('Calling child method')

c = Child()          # instance of child
c.childMethod()      # child calls its method
c.parentMethod()     # calls parent's method
c.setAttr(200)       # again call parent's method
c.getAttr()          # again call parent's method

위의 코드가 실행되면 다음과 같은 결과가 생성됩니다.

Calling child constructor
Calling child method
Calling parent method
Parent attribute : 200

비슷한 방식으로 다음과 같이 여러 부모 클래스에서 클래스를 구동 할 수 있습니다.

class A:        # define your class A
.....

class B:         # define your calss B
.....

class C(A, B):   # subclass of A and B
.....

issubclass () 또는 isinstance () 함수를 사용하여 두 클래스와 인스턴스의 관계를 확인할 수 있습니다.

  • 그만큼 issubclass(sub, sup) 부울 함수는 주어진 서브 클래스가 True를 반환합니다. sub 실제로 슈퍼 클래스의 하위 클래스입니다. sup.

  • 그만큼 isinstance(obj, Class)objClass 클래스 의 인스턴스이거나 Class 의 하위 클래스 인스턴스 인 경우 부울 함수는 True를 반환합니다.

메서드 재정의

언제든지 부모 클래스 메서드를 재정의 할 수 있습니다. 부모의 메서드를 재정의하는 한 가지 이유는 하위 클래스에서 특수하거나 다른 기능을 원할 수 있기 때문입니다.

#!/usr/bin/python3

class Parent:        # define parent class
   def myMethod(self):
      print ('Calling parent method')

class Child(Parent): # define child class
   def myMethod(self):
      print ('Calling child method')

c = Child()          # instance of child
c.myMethod()         # child calls overridden method

위의 코드가 실행되면 다음과 같은 결과가 생성됩니다.

Calling child method

기본 오버로딩 방법

다음 표는 자신의 클래스에서 재정의 할 수있는 몇 가지 일반적인 기능을 나열합니다.

Sr. 아니. 방법, 설명 및 샘플 호출
1

__init__ ( self [,args...] )

생성자 (선택적 인수 포함)

샘플 호출 : obj = className (args)

2

__del__( self )

소멸자, 개체 삭제

샘플 호출 : del obj

__repr__( self )

평가 가능한 문자열 표현

샘플 호출 : repr (obj)

4

__str__( self )

인쇄 가능한 문자열 표현

샘플 호출 : str (obj)

5

__cmp__ ( self, x )

개체 비교

샘플 호출 : cmp (obj, x)

연산자 오버로딩

2 차원 벡터를 표현하기 위해 Vector 클래스를 만들었다 고 가정합니다. 더하기 연산자를 사용하여 추가하면 어떻게됩니까? 대부분의 경우 파이썬은 당신에게 소리를 지 릅니다.

그러나 클래스에서 __add__ 메서드를 정의하여 벡터 추가를 수행 할 수 있으며 더하기 연산자는 예상대로 동작합니다.

#!/usr/bin/python3

class Vector:
   def __init__(self, a, b):
      self.a = a
      self.b = b

   def __str__(self):
      return 'Vector (%d, %d)' % (self.a, self.b)
   
   def __add__(self,other):
      return Vector(self.a + other.a, self.b + other.b)

v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)

위의 코드가 실행되면 다음과 같은 결과가 생성됩니다.

Vector(7,8)

데이터 숨기기

개체의 속성은 클래스 정의 외부에서 표시 될 수도 있고 표시되지 않을 수도 있습니다. 이중 밑줄 접두사로 속성의 이름을 지정해야합니다. 그러면 해당 속성이 외부인에게 직접 표시되지 않습니다.

#!/usr/bin/python3

class JustCounter:
   __secretCount = 0
  
   def count(self):
      self.__secretCount += 1
      print (self.__secretCount)

counter = JustCounter()
counter.count()
counter.count()
print (counter.__secretCount)

위의 코드가 실행되면 다음과 같은 결과가 생성됩니다.

1
2
Traceback (most recent call last):
   File "test.py", line 12, in <module>
      print counter.__secretCount
AttributeError: JustCounter instance has no attribute '__secretCount'

Python은 클래스 이름을 포함하도록 이름을 내부적으로 변경하여 해당 멤버를 보호합니다. object._className__attrName 과 같은 속성에 액세스 할 수 있습니다 . 마지막 줄을 다음과 같이 바꾸면 작동합니다.

.........................
print (counter._JustCounter__secretCount)

위의 코드가 실행되면 다음과 같은 결과가 생성됩니다.

1
2
2