경기도 인공지능 개발 과정/Python

Python 클래스와 객체

agingcurve 2022. 5. 28. 14:56
반응형

학습목표

  1. 클래스와 오브젝트에 대해 이해한다.
  2. 클래스를 정의하고 활용 할 수 있다.

class란?

  • 실세계의 것을 모델링하여 속성(attribute)와 행위(method)를 갖는 데이터 타입이다.
  • python에서의 string, int, list, dict.. 모두가 다 클래스로 존재한다.
  • 예를들어 학생이라는 클래스를 만든다면, 학생을 나타내는 속성과 학생이 행하는 행동을 함께 정의 할 수 있음
  • 사용하고자하는 데이터(변수)와 데이터를 다루는 연산(함수)를 하나로 캡슐화(encapsulation)하여 클래스로 표현한다.

object 란?

  • 클래스로 생성되어 구체화된 객체(인스턴스)이다.
  • 파이썬의 모든 것(int, str, list..etc)은 객체(인스턴스)이다.
  • 실제로 class가 인스턴스화 되어 메모리에 상주하는 상태를 의미한다.
  • class가 설계도, object는 실제로 설계도를 기반으로 만든 것을 말한다.

class 선언하기

  • 객체를 생성하기 위해선 객체의 설계도가 되는 class를 미리 선언해야 한다.
In [1]:
class Person:
    pass
In [2]:
class MyClass:
    '이것은 나의 클래스 입니다.'
    pass
In [3]:
MyClass.__doc__
Out[3]:
'이것은 나의 클래스 입니다.'
In [4]:
str.__doc__
Out[4]:
"str(object='') -> str\nstr(bytes_or_buffer[, encoding[, errors]]) -> str\n\nCreate a new string object from the given object. If encoding or\nerrors is specified, then the object must expose a data buffer\nthat will be decoded using the given encoding and error handler.\nOtherwise, returns the result of object.__str__() (if defined)\nor repr(object).\nencoding defaults to sys.getdefaultencoding().\nerrors defaults to 'strict'."
In [5]:
list.__doc__
Out[5]:
'Built-in mutable sequence.\n\nIf no argument is given, the constructor creates a new empty list.\nThe argument must be an iterable if specified.'
In [6]:
Person.__doc__
In [9]:
class Person:
    '''이것은 사람을 추상화 한 
    클래스 입니다.'''
    name = 'kang'
    def greet(self):
        print('hello~~')
        
kang = Person()
kang.greet()
kim = Person()
kim.name = 'kim'
print(kim.name)
hello~~
kim
In [10]:
Person.__doc__
Out[10]:
'이것은 사람을 추상화 한 \n    클래스 입니다.'
In [11]:
Person.__dict__
Out[11]:
mappingproxy({'__module__': '__main__',
              '__doc__': '이것은 사람을 추상화 한 \n    클래스 입니다.',
              'name': 'kang',
              'greet': <function __main__.Person.greet(self)>,
              '__dict__': <attribute '__dict__' of 'Person' objects>,
              '__weakref__': <attribute '__weakref__' of 'Person' objects>})
In [12]:
kang.__dict__
Out[12]:
{}
In [13]:
kim.__dict__
Out[13]:
{'name': 'kim'}

__init__(self)

  • 생성자, 클래스 인스턴스가 생성될 때 호출된다.
  • self인자는 항상 첫번째에 오며 자기 자신을 가리키다.
  • 이름이 꼭 self일 필요는 없지만, 관례적으로 self로 사용한다.
  • 생성자에서는 해당 클래스가 다루는 데이터를 정의한다.
    • 이 데이터를 멤버 변수(member variable) 또는 속성(attribute)라고 함
In [18]:
class Pen:
    def __init__(self):
        self.color = 'black'
    def draw(self):
        print(self.color,'색으로 그려요!! ' )
p1 = Pen()
print(p1.color)
black
In [21]:
class Pen:
    def __init__(self,color):
        self.color = color   #color 초기화 
    def draw(self):
        print(self.color,'색으로 그려요!! ' )
p2 = Pen('red')
p3 = Pen('blue')

name = 'kang'  #name 변수 초기화
a = 0 # a 변수 초기화 

#Pen...  속성 color  
In [22]:
p2.color

p2.draw()
p3.draw()
red 색으로 그려요!! 
blue 색으로 그려요!! 
In [1]:
class Person:
    def __init__(self,name):
        print('person의 생성자 실행!@!!')
        self.name = name
        self.age = 1
        
        
knag = Person('kang')
kim = Person('kim')
print('이름',knag.name)
print('나이',knag.age)

print('이름',kim.name)
print('나이',kim.age)
person의 생성자 실행!@!!
person의 생성자 실행!@!!
이름 kang
나이 1
이름 kim
나이 1
In [37]:
class Person:
    def __init__(self,name,age=1):
        print('person의 생성자 실행!@!!')
        self.name = name
        self.age = age
kk = Person('carami',20)
print('이름',kk.name)
print('나이',kk.age)

mm = Person('mmas')
print('이름',mm.name)
print('나이',mm.age)
person의 생성자 실행!@!!
나이 carami

self

  • 파이썬의 method는 항상 첫번째 인자로 self를 전달한다.
  • self는 현재 해당 메쏘드가 호출되는 객체 자신을 가리킨다.
  • 반드시 이름이 self일 필요는 없으나 관례적으로 self를 사용한다.
  • 위치는 항상 맨 첫번째 parameter이다.
In [38]:
#속성으로 name과 speed를 갖는 Car 클래스를 정의하세요. 


class Car:
    def __init__(self):
        self.name = 'None'
        self.speed = 0
#본인이 갖고 싶은 차를 생성해 보세요. 

sonata = Car()
sonata.name = 'sonota'
sonata.speed = 100 

print(sonata.name, sonata.speed)
sonota 100
In [41]:
# 위의 Car 클래스에 차의 이름과 속도를 알려주는 info 라는 이름의 메소드를 정의하세요. 

class Car:
    def __init__(self):
        self.name = 'None'
        self.speed = 0
    def info(self):
        print(f'내 차의 이름은 {self.name} 이고, 현재 속도는 {self.speed} 입니다. ')
        
sonata = Car()
sonata.name = 'sonota'
sonata.speed = 100 

sonata.info()
내 차의 이름은 sonota 이고, 현재 속도는 100 입니다. 
In [43]:
dir()
Out[43]:
['Car',
 'In',
 'MyClass',
 'Out',
 'Pen',
 'Person',
 '_',
 '_10',
 '_11',
 '_12',
 '_13',
 '_17',
 '_3',
 '_39',
 '_4',
 '_40',
 '_42',
 '_5',
 '__',
 '___',
 '__builtin__',
 '__builtins__',
 '__doc__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 '_dh',
 '_i',
 '_i1',
 '_i10',
 '_i11',
 '_i12',
 '_i13',
 '_i14',
 '_i15',
 '_i16',
 '_i17',
 '_i18',
 '_i19',
 '_i2',
 '_i20',
 '_i21',
 '_i22',
 '_i23',
 '_i24',
 '_i25',
 '_i26',
 '_i27',
 '_i28',
 '_i29',
 '_i3',
 '_i30',
 '_i31',
 '_i32',
 '_i33',
 '_i34',
 '_i35',
 '_i36',
 '_i37',
 '_i38',
 '_i39',
 '_i4',
 '_i40',
 '_i41',
 '_i42',
 '_i43',
 '_i5',
 '_i6',
 '_i7',
 '_i8',
 '_i9',
 '_ih',
 '_ii',
 '_iii',
 '_oh',
 'exit',
 'get_ipython',
 'kang',
 'kim',
 'kk',
 'knag',
 'mm',
 'p1',
 'p2',
 'p3',
 'quit',
 'sonata']
In [39]:
dir(sonata)
Out[39]:
['__class__',
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__le__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 'name',
 'speed']

mehtod 정의

  • 파이썬에서는 메서드의 첫번째 매개변수 이름은 관례적으로 self를 사용한다.
  • obj.method() 형태로 호출된다.
In [45]:
#Counter 클래스를 정의 하세요.  멤버변수는 num 을 갖고 있고,  
#메소드는 num을 1씩 증가시키는 메소드, num을 0으로 초기화 하는 메소드,  
#현재 num 의 값을 알려주는 메서드 를 정의 하세요. 

class Counter:
    def __init__(self):
        self.num = 0
        
    def increment(self):
        self.num += 1
    
    def reset(self):
        self.num = 0
        
    def currentValue(self):
        print('현재값은:', self.num)

c = Counter()
c.currentValue()
c.increment()
c.increment()
c.currentValue()
c.reset()
c.currentValue()
현재값은: 0
현재값은: 2
현재값은: 0
In [ ]:
 
In [ ]:
 

비공개속성

In [11]:
class Person:
    def __init__(self):
        self.__name = 'kang' #비공개 속성
        self.age = 20
        
    def getName(self):
        return self.__name
    def __setName(self,name): #비공개메서드 
        self.__name = name
    def sName(self,name):
        #다른구현이 필요하다면 구현.. 
        self.__setName(name)
k = Person()
# print(k.__name)
print(k.age)
print(k.getName())
k.sName('carami')
print(k.getName())
20
kang
carami
In [ ]:
 

클래스 속성 VS 인스턴스 속성

In [13]:
class Bag:
    def __init__(self):
        self.items = []
    
    def putItem(self,item):
        self.items.append(item)

        
cbag = Bag()
cbag.putItem('candy')
cbag.putItem('book')
cbag.putItem('pen')

kbag = Bag()
kbag.putItem('phone')

print('kbag',kbag.items)

print('cbag', cbag.items)
kbag ['phone']
cbag ['candy', 'book', 'pen']
In [14]:
class Bag:
    items = []
    name = ''
    
    def putItem(self,item):
        self.items.append(item)
        name = "dfjdk"
        
cbag = Bag()
cbag.putItem('candy')
cbag.putItem('book')
cbag.putItem('pen')

kbag = Bag()
kbag.putItem('phone')

print('kbag',kbag.items)

print('cbag', cbag.items)
kbag ['candy', 'book', 'pen', 'phone']
cbag ['candy', 'book', 'pen', 'phone']

method type

  • instance method - 객체로 호출된다.
    • 메서드는 객체가 생성될때 만들어진다.
  • class method(static method) - class로 호출
    • 클래스 메서드의 경우 객체가 생성되기 전에 미리 생성됨으로 객체를 통해 호출하지 않는다.
In [15]:
class Cal:
    def add(self,a,b):
        print(a+b)
cal = Cal()
cal.add(1,2)
3
In [17]:
class Cal:
    @staticmethod
    def add(a,b):
        print(a+b)

Cal.add(1,2)
3
In [24]:
class Cal:
    result = 0
    def __init__(self):
        self.name = 'test'
    @classmethod
    def cls_add(cls,a,b):
        cls.result= a + b 
        print(cls.name)
        return cls.result
    @staticmethod
    def add(a,b):       
        return a+b
    
Cal.add(2,3)
Cal.cls_add(2,3)

c = Cal() # 객체 생성...  c는 인스턴스 
c.name 
------------------------------------------
AttributeErrorTraceback (most recent call last)
Input In [24], in <cell line: 15>()
     12         return a+b
     14 Cal.add(2,3)
---> 15 Cal.cls_add(2,3)

Input In [24], in Cal.cls_add(cls, a, b)
      5 @classmethod
      6 def cls_add(cls,a,b):
      7     cls.result= a + b 
----> 8     print(cls.name)
      9     return cls.result

AttributeError: type object 'Cal' has no attribute 'name'
In [ ]:
 
In [ ]:
 

Class Inheritance (상속)

  • 다른 클래스의 기능을 그대로 물려받을 수 있다.
  • 기존 클래스에 기능 일부를 추가하거나, 변경하여 새로운 클래스를 정의한다.
  • 코드를 재사용할 수 있게된다.
  • 상속 받고자 하는 대상인 기존 클래스는 (Parent, Super, Base class 라고 부른다.)
  • 상속 받는 새로운 클래스는(Child, Sub, Derived class 라고 부른다.)
  • 의미적으로 is-a관계를 갖는다
In [25]:
class Parent:
    def __init__(self):
        self.i = 10

class Child(Parent): #상속!!   
    pass

c = Child()
print(c.i)
10
In [34]:
class Parent:
    def __init__(self):
        print('Parent생성자 실행')
        self.i = 10

class Child(Parent): #상속!!   
    def __init__(self):
        self.i = 20
        print('Child 생성자 실행')
    def test(self):
        pass
        
k = Child()
print(k.i)
p = Parent()
Child 생성자 실행
20
Parent생성자 실행
In [ ]:
 
In [ ]:
 
In [53]:
class Person:
    def __init__(self,name):
        self.name = name
    def eat(self, food):
        print('{}은 {}를 먹습니다.'.format(self.name,food))
In [51]:
class Student(Person):
#     def __init__(self):
#         self.name = 'student'
    pass
    
#Student클래스에 __init__ 메서드가 없다면, 부모 클래스의 __init__메서드를 실행한다.  

s = Student('carami')  #부모클래스의 __init__메서드는 name 을 원하므로, Student객체를 생성할때... name을 알려줘야한다. 
s.eat('밥')
carami은 밥를 먹습니다.
In [52]:
class Student(Person):
    def __init__(self): #Student클래스가 __init__ 메서드를 가진경우는 Person의 __init__ 메소드는 실행되지 않는다. 
        self.name = 'student' 
        
kang = Student()
s.eat('빵')
carami은 빵를 먹습니다.

method override

  • 부모 클래스의 method를 재정의(override)한다.
  • 하위 클래스(자식 클래스) 의 인스턴스로 호출시, 재정의된 메소드가 호출된다.
In [55]:
class Person:
    def __init__(self,name):
        self.name = name
    def eat(self, food):
        print('{}은 {}를 먹습니다.'.format(self.name,food))
        
    
class Student(Person):
    def __init__(self,name):
        self.name = name
    def eat(self, food):
        print('{}은 {}를 맛있게 먹습니다.'.format(self.name,food))
carami = Student('carami')
carami.eat('밥')
carami은 밥를 맛있게 먹습니다.

super

  • 하위클래스(자식 클래스)에서 부모클래스의 method를 호출할 때 사용한다.
In [58]:
class Parent:
    def hello(self):
        print('안녕')
        print('나는 여기에 복잡하고')
        print('어려운 것들을 많이 구현하고 있어요~~ ')
        
class Child(Parent):
    def hello(self):
        super().hello()
        print('오늘은 날씨가 좋네요~~^^')
    def study(self):
        print('공부를 재밌게 해요~~')
        
kim = Child()
kim.hello()
안녕
나는 여기에 복잡하고
어려운 것들을 많이 구현하고 있어요~~ 
오늘은 날씨가 좋네요~~^^
In [65]:
class Person:
    def __init__(self,name):
        print('Person의 __init__실행')
        self.name = name
        self.age = 20
        
    def eat(self, food):
        print('{}은 {}를 먹습니다.'.format(self.name,food))
        
class Student(Person):
    def __init__(self, name,schoolName):     
        print('Student 의 __init__ 실행')
#         self.name = name
        super().__init__(name)
        self.schoolName = schoolName
        
    def sayHello(self):
        print('안녕~~~!!')
        
kim = Student('kim','kkk')
kim.eat('candy')
kim.sayHello()
        
        
Student 의 __init__ 실행
Person의 __init__실행
kim은 candy를 먹습니다.
안녕~~~!!

다중상속

In [72]:
class P1:
    def hello(self):
        print('hello p111111111111111111')
class P2:
#     def hello(self):
#         print('hello p222222222222222222')
    pass
class C(P1):
    def hello2(self):
        print('hello cccccccccccccccccccc')
class D(C,P2):
    pass

test = D()
test.hello()
hello p111111111111111111
In [73]:
print(D.mro())
[<class '__main__.D'>, <class '__main__.C'>, <class '__main__.P1'>, <class '__main__.P2'>, <class 'object'>]

추상클래스

In [80]:
from abc import * 

class 새(metaclass = ABCMeta):
    def 먹다(self):
        print('맛있게 먹어요.')
    def 날다(self):
        print('하늘을 날아요')
    @abstractmethod
    def 노래하다(self):
        pass
    
#추상클래스는 미완성 클래스다.  때문에 객체를 생성 할 수없다. 
# a = 새()

class 앵무새(새):
    def 노래하다(self):
        print('앵무새가 노래해요~')

봄봄 = 앵무새()

연습문제

  • 멤버변수 w,h 를 갖는 Shape 클래스를 정의 하시오.
  • Sahpe 클래스는 도형을 그리는 draw()라는 추상 메소드를 포함하게 하세요.
  • Shape을 상속받은 Rect, Circle 클래스를 정의하고, draw()메소드를 적절하게 구현하세요.
  • 이때 Circle는 반지름을 나타내는 멤버변수 r 을 추가해주세요.
  • 도형은 면적을 구하는 메서드도 추가해 보세요.
In [5]:
class Shape(metaclass = ABCMeta):
    def __init__(self,w,h):
        self.w = w
        self.h = h
    @abstractmethod
    def draw(self):
        pass

class Circle(Shape):
    def __init__(self,r):
#         super().__init__(w,h)
        self.r = r
        
    def draw(self):
        print('원을 그려요!! ')
        
    def calculate(self):
        return (self.r**2) *3.14
        
class Rect(Shape):
    def draw(self):
        print('사각형을 그려요!!')
        
    def calculate(self):
        return self.w*self.h
c = Circle(3)
c.draw()
print(c.calculate())
r = Rect(3,4)
r.draw()
print(r.calculate())
원을 그려요!! 
28.26
사각형을 그려요!!
12
In [2]:
from abc import * 
class Shape:
    def __init__(self,w,h):
        self.w = w
        self.h = h
    @abstractmethod 
    def draw(self):
        pass
    
class Rect(Shape):
    def __init__(self,w,h):
        self.w = w
        self.h = h
    def draw(self):
        print("해당사각형의 면적은 {}".format(self.w*self.h))
        
class Circle(Shape):
    def __init__(self,r):
        self.r = r
    def draw(self):
        print("해당원의 면적은 {}".format((self.r**2)*3.14))        
        
        
        
rect = Rect(3,4)
rect.draw()

circle = Circle(4)
circle.draw()
해당사각형의 면적은 12
해당원의 면적은 50.24
In [4]:
print(type(Shape))
<class 'type'>
In [103]:
dir(Shape)
Out[103]:
['__class__',
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__le__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 'draw']

special method

In [127]:
class Shape(metaclass = ABCMeta):
    def __init__(self,w,h):
        self.w = w
        self.h = h
    @abstractmethod
    def draw(self):
        pass

class Circle(Shape):
    def __init__(self,r):
#         super().__init__(w,h)
        self.r = r
        
    def draw(self):
        print('원을 그려요!! ')
        
    def calculate(self):
        return (self.r**2) *3.14
        
class Rect(Shape):
    def draw(self):
        print('사각형을 그려요!!')
        
    def calculate(self):
        return self.w*self.h
    
    def __add__(self,rect):
        new_w = rect.w + self.w
        new_h = rect.h + self.h
        return Rect(new_w,new_h)
    
    def __eq__(self, rect):
        print(self.calculate())
        print(rect.calculate())
        return self.calculate() == rect.calculate()
        
In [128]:
r1 = Rect(2,3)
print(r1.calculate())
6
In [129]:
r2 = Rect(3,2)
print(r2.calculate())
6
In [130]:
r1 == r2
6
6
Out[130]:
True
__add__() # + 연산자로 호출
__sub__() # - 연산자로 호출
__mul__() # * 연산자로 호출
__truediv__() # / 연산자로 호출
In [120]:
new_r = r1 + r2

r3 = r1.__add__(r2)
print(r3.w,r3.h)
print(r3.calculate())
5 5
25
In [119]:
new_r.calculate()

print(new_r.w, new_r.h)
5 5
In [ ]:
dir()
In [11]:
class AbcTest(metaclass=ABCMeta):
#     @abstractmethod
    def test(self):
        pass
    def p(self):
        print('hi')
In [12]:
c = AbcTest()
c.p()
hi
In [99]:
dir(AbcTest)
Out[99]:
['__class__',
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__le__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 'test']
In [101]:
class aaTest(metaclass = ABCMeta):
    pass

class bbTest(aaTest):
    pass

a = bbTest()
 

 

'경기도 인공지능 개발 과정 > Python' 카테고리의 다른 글

Python pymysql 사용하기  (0) 2022.05.28
Python 예외처리  (0) 2022.05.28
Python 파일 입출력  (0) 2022.05.28
Python 함수, lambda 함수  (0) 2022.05.28
Python 조건문과 반복문(While, For)  (0) 2022.05.28