
클래스는 사용자 정의 자료형이다.
인스턴스는 클래스 기반으로 생성된 객체이다.
- method : 클래스 내부에 선언된 함수로 class나 instance를 가지고 호출
- attribute : 클래스나 인스턴스에서 사용하는 데이터
- Accessor : 속성의 값을 사용하기 위해 리턴하거나 설정하는 메서드(권장)
#클래스 생성 class Student: def disp(self): print("인스턴스 메서드") #만들어지기는 클래스에 만들어졌지만 #인스턴스 없이는 호출할 수 없는 메서드 def setName(self, name): self.name=name #name이란 속성이 없으면 만들어서 대입, 존재하면 수정 def getName(self): return self.name stu1=Student() #인스턴스 생성 #메서드 호출 Student.disp(stu1)#첫 자리에 인스턴스를 넣어야함 #클래스가 인스턴스의 메서드 호출 : unbound 호출 stu1.disp()#self에 인스턴스가 대입됨 - bound 호출 Student.setName(stu1,"mino") print(Student.getName(stu1)) print(stu1.getName())
대표적인 속성
__doc__: 함수를 설명하기 위한 속성
__name__: 함수의 이름
생성자를 만드는 이유
- 처음부터 속성을 만들거나 속성을 원하는 값으로 초기화하기 위해
- python에서는 생성자를 만들 때, __init__ 이라는 이름을 사용
#클래스 생성 class Student: #생성자 - 인스턴스를 생성할 떄 호출하는 메서드 #이 메서드에서 속성을 생성해서 속성을 처음부터 #소유하도록 만들어주는 것이 좋습니다. #매개변수를 이용해서 초기화하면, 만들어질 때 #다양한 값으로 초기화가 가능합니다. def __init__(self,name="noname"): #필수 요소는 아니면 기본값을 주고, #필수 요소이면 기본값을 안주고 달라고 한다. #name값을 안주면 noname이 들어감 print("인스턴스 생성") #self.name="기본값" 특정 상수로 생성하는 경우에는 #생성자 내부에서 직접 설정, 권장 x self.name=name#이제 name을 받아서 만듦 #매개변수를 이용해서 초기화 할 때, #매개변수의 기본값을 설정하지 않으면 #인스턴스를 생성할 때, 반드시 매개변수에 값을 대입해야 한다. #소멸자 - 인스턴스가 소멸될 때 호출되는 메서드 def __del__(self): print("인스턴스 소멸") def disp(self): print("인스턴스 메서드") #만들어지기는 클래스에 만들어졌지만 #인스턴스 없이는 호출할 수 없는 메서드 def setName(self, name): self.name=name #name이란 속성이 없으면 만들어서 대입, 존재하면 수정 def getName(self): return self.name stu1=Student("mino2") #인스턴스 생성 #메서드 호출 #Student.disp(stu1)#첫 자리에 인스턴스를 넣어야함 #클래스가 인스턴스의 메서드 호출 : unbound 호출 stu1.disp()#self에 인스턴스가 대입됨 - bound 호출 print(Student.getName(stu1)) print(stu1.getName())
class Student(): #클래스 속성 - 클래스에서 1개만 생성 auto_increment=0 def __init__(self): #메서드 안에서 클래스 속성은 아래와 같이 부른다. Student.auto_increment+=1 self.no=Student.auto_increment stu1=Student() print(stu1.no) stu2=Student() print(stu2.no)
Reference Count 확인하는 방법
- sys 모듈의 getrefcount라는 함수에 인스턴스를 대입하면 됩니다.
- 이때, 1이 증가해서 나오게 되는데, 이는 getrefcount가 한 번 참조해서 그런 것입니다.
class Student(): #클래스 속성 - 클래스에서 1개만 생성 auto_increment=0 def __init__(self): #메서드 안에서 클래스 속성은 아래와 같이 부른다. self.no=Student.auto_increment Student.auto_increment+=1 def __del__(self): print("인스턴스 소멸") stu1=Student() #인스턴스가 생성되고 참조 카운트가 1이 됩니다. stu1=None#참조를 가리키는 변수에 None을 대입하면 #참조 카운트가 1감소하며, 값이 0이 된다면 인스턴스가 소멸됩니다 stu2=Student() #참조 카운트 1 stu3=stu2 # 참조 카운트 2 ( 다른 변수에 참조를 대입) stu2=None # 참조 카운트 1감소 ( 1이라서 소멸은 안됨 ) print("프로그램 종료")
@staticmethod라는 decorator를 이용해서 생성@classmethod라는 decorator를 이용해서 생성class Student(): #클래스 속성 - 클래스에서 1개만 생성 auto_increment=0 def __init__(self): #메서드 안에서 클래스 속성은 아래와 같이 부른다. self.no=Student.auto_increment Student.auto_increment+=1 print(self.no) def __del__(self): print("인스턴스 소멸") @staticmethod def method():#static method는 self가 없다. print("매개변수가 없는 static method") #Student.method() #인스턴스를 만들 필요가 없는 static method #stu1=Student() #인스턴스가 생성되고 참조 카운트가 1이 됩니다. #stu1=None#참조를 가리키는 변수에 None을 대입하면 #참조 카운트가 1감소하며, 값이 0이 된다면 인스턴스가 소멸됩니다 stu2=Student() #참조 카운트 1 stu3=stu2 # 참조 카운트 2 ( 다른 변수에 참조를 대입) stu2=None # 참조 카운트 1감소 ( 1이라서 소멸은 안됨 ) print("프로그램 종료")
class Student(): auto_increment=0 @classmethod def method(self): Student.auto_increment=100 Student.method()
class Student(): #name과 age 속성만 사용하도록 제한하고 싶다. __slots__=["name","age"] stu1=Student() stu1.name="mino" stu1.age=26 stu1.job="student" #이래도 파이썬은 기본적으로 에러가 안남 #하지만 slots로 제한하면 job은 만들 수 없음
class Student(): def __init__(self): self.name="mino" self.__no=1 #이렇게 만들면 인스턴스는 속성에 직접 접근 불가 #메서드를 통해서만 접근 가능 stu1=Student() print(stu1.name) print(stu1.__no)
프로퍼티이름 = property(fget=None, fset=None, fdel=None, doc=None)getter, setter, del 등을 매개변수에 연결하자.
class Student(): def __init__(self, name="noname"): self.__name=name #속성 이름이 __로 시작하기에 인스턴스 접근물가 #접근자 메서드 def getName(self): print("name의 getter 호출") return self.__name def setName(self,name): print("name의 setter 호출") self.__name=name #property #name을 호출하면 getName 메서드가 호출되고, #name에 값을 대입하면 setName 메서드가 호출된다. name=property(fget=getName, fset=setName) stu=Student() stu.setName("mino") print(stu.getName()) stu.name="mino2" print(stu.name)name에 값을 직접 넣는 것(속성을 바로 이용하는 것) 처럼 보이지만,
메서드를 호출하는 것이다.
class Student(): def __init__(self, name="noname"): self.__name=name #속성 이름이 __로 시작하기에 인스턴스 접근물가 #접근자 메서드 @property #getter설정 def name(self): print("name의 getter 호출") return self.__name @name.setter def name(self,name): print("name의 setter 호출") self.__name=name stu=Student() stu.name="mino2" print(stu.name)getter는 property, setter는 이름.setter라고만 하면 된다.
하고 getName, setName이 아닌 property 이름으로 def해주자.
method의 이름은
__이름__입니다.
+는__add__
==는__eq__
하지만 연산자 오버로딩을 할 때, 매개변수의 개수는 변경이 불가능합니다.
class Student: def __init__(self,name="noname"): self.name=name #+ 연산자 오버로딩 def __add__(self,other): return self.name+other.name #name을 결합하겠다. #==연산자 오버로딩 def __eq__(self, other): return self.name==other.name #name만 같으면 같다.(id 확인x) stu1=Student("mino") stu2=Student("mino") #stu1, stu2 는 공간할당을 받고 id가 있는데 # 두 id는 다르다. print(stu1+stu2) # 당연히 안된다. stu3=stu1 print(stu1==stu2) #오버로딩을 하니까 얘는 #True(왜냐면 단순 요소비교) print(stu1 is stu2)
python은 연산자의 기능을 바꿀 수 있다.
class Student: def __init__(self, name="noname", count=8): self.name=name self.count=count def __add__(self, other): return self.count+other.count stu1=Student("사과",3) stu2=Student("포도",2) print(stu1.count+stu2.count)#얘도 나오긴해 print(stu1+stu2) #이러면 끝이긴 해
단일 상속 : 하나의 클래스로부터 물려받는 것
다중 상속 : 두 개 이상의 클래스로부터 물려받는 것
class 클래스이름(상위클래스 이름나열):class Sup: def superMethod(self): print("상위 클래스의 메서드입니다.") #Sup클래스를 상속받는 Sub 클래스 class Sub(Sup): def subMethod(self): print("하위 클래스의 메서드입니다.") #Sub의 인스턴스를 생성해서 필요한 메서드 호출 my=Sub() my.superMethod() #Sub클래스에는 없지만, Sup를 상속받았기 때문에 호출이 가능하다. my.subMethod()
__init__ 함수는 super().__init()__으로 호출__init__ 이외의 함수는 super().메서드이름으로 호출합니다.class Sup: def __init__(self): self.name="noname" def superMethod(self): print("상위 클래스의 메서드입니다.") #Sup클래스를 상속받는 Sub 클래스 class Sub(Sup): #def __init__(self): # self.score=80 def __init__(self): super().__init__()#이 작업이 무조건 필요함 self.score=80 def subMethod(self): print("하위 클래스의 메서드입니다.") #Sub의 인스턴스를 생성해서 필요한 메서드 호출 my=Sub() my.superMethod() #Sub클래스에는 없지만, Sup를 상속받았기 때문에 호출이 가능하다. my.subMethod() print(my.name) #하위 클래스에서 __init__를 생성하면 #상위 클래스의 __init__을 호출하지 않는다. #하위 클래스의 __init__을 만들 때에는 #상위 클래스의 __init__을 호출해주어야 합니다.
오버라이딩을 할 거면 호출해라.
class Sup: def method(self): print("상위 클래스의 메서드") #Sup클래스를 상속받는 Sub 클래스 class Sub(Sup): #상위 클래스에 존재하는 메서드를 하위 클래스에서 #다시 정의 - Overrriding #상위 클래스 안써도 에러는 안나네? def method(self): super().method() #상위 클래스의 메서드 호출은 잊지말자 print("하위 클래스의 메서드") s=Sub() s.method()Q: 하위 클래스에서 상위 클래스 print 빼고 하위 print만 남긴다면 그건 overriding인가?
기능의 확장이어야 하기 때문에 아닐 것 같다.
다중 상속을 했을 때, 메서드를 찾는 순서
클래스이름.mro()
super(클래스이름,self)를 대입해야 합니다.
- 추상 메서드
- 메서드의 내용이 없이 이름만 존재하는 경우
- 메서드 상단에@abstractmethod를 추가하면 추상메소드 생성- 추상 클래스
- 추상 메서드를 소유한 클래스로, 자신의 인스턴스는 생성할 수 없고, 상속을 통해서만 사용하는 클래스
-abc Module import한 뒤, class의 ()안에metaclass=ABCMeta를 추가
import abc #추상 클래스 - 자신의 인스턴스를 생성할 수 없음 class AbstractClass(metaclass=abc.ABCMeta): #추상 메서드 - 내용이 없는 메서드로 #하위 클래스에서 구현해서 사용해야 합니다. @abc.abstractmethod def method(self): pass class Sub(AbstractClass): def __init__(self): print("인스턴스 생성") #추상 클래스를 상속받는 경우, 추상 메서드를 #반드시 implementation해주어야 합니다. #안해주면 에러가 납니다. def method(self): print("추상 메서드 구현") #inst=AbstractClass()#인스턴스 만들 수 없어서 에러! #상속을 통해서만 사용해야 한다. instance=Sub() instance.method()
__getattr__(self,name)메서드를 재정의하면 됩니다.
name에는 호출하는 함수가 전달됩니다.
__iter__메서드와___next___메서드를 재정의해서 구현
원래 Module이라는 단어는 독립적으로 수행되는 코드 블럭이며,
Python에서는 하나의 파일을 Module이라고 합니다.
import 모듈이나 패키지 이름모듈이름 또는 패키지 이름.구성요소이름을 쓰면 됩니다.math 모듈에 있는 abs라는 함수를 사용하고자 한다.
import math
math.abs()하면 됩니다.
python 은 내가 사용하지 않는 모듈을 import해도 오류는 아니지만, 메모리 낭비이다.
from module이나 package이름 import 구성요소
from math import abs
abs()이렇게 사용 가능합니다.
단, math에서 abs만 가져오는 것입니다.
이것을 더 권장합니다.
from 모듈이나 패키지이름 import *
from math import *
abs()
cos()
모든 구성요소를 추가하는 것입니다.
import 모듈이나 패키지 이름 as 다른 이름
import pandas as pd
pandas 패키지를 이름을 pd로 바꿔서 패키지 추가하는 것.
pandas가 아닌 pd로 불려야 합니다.
__import __(모듈이나 패키지이름)으로 사용가능이렇게 하는 것은 지양합시다.
import pandas
import pandas as pd
똑같은 것을 두 번 가지고 오게 됩니다.
import sys
print(sys.modules)
하면 잘 보입니다.
import sys
sys.path
sys.path.append("찾는위치")를 해주면 됩니다.myPI=3.14 def func(message): print(message)
import myMath #myMath 모듈이나 패키지를 import import sys sys.path.append("./") #현재 디렉토리에서 모듈이나 패키지를 검색하도록 설정 myMath.func("모듈을 가져와서 프린트해봤어요") print(myMath.myPI)파일을 나누어 작업을 할 수 있는 것을 확인했습니다.
__init__.py 파일이 존재하면 패키지로 간주합니다.pip install 패키지이름pip install 패키지이름 -upgradepip install 패키지이름=버전pip install 패키지이름>=버전pip install 패키지이름 --user!pip install 패키지이름으로 패키지 설치를 합니다.pip list --format=columns 입력해보면 됩니다.#pip list --format=columns #matplotlib 이 있네요 #없다면? #pip install matplotlib import matplotlib.pyplot as plt fig=plt.figure(figsize=(10,7)) plt.boxplot(([10,87,29,76,88],[20,40,68,1000,87])) plt.grid() plt.show() fig.savefig("graph.png")
#실수 표현의 한계 때문에 2개 연산의 결과가 다르게 나옵니다. print((1234.567+45.67844)+0.0004) print(1234.567+(45.67844+0.0004))이 둘의 결과가 다르다. 결국 실수로 연산하는 것은 매우 위험하다는 것을 알 수 있다.
from decimal import Decimal print((Decimal(1234.567)+Decimal(45.67844))+Decimal(0.0004)) print(Decimal(1234.567)+(Decimal(45.67844)+Decimal(0.0004))) print((Decimal('1234.567')+Decimal('45.67844'))+Decimal('0.0004')) print(Decimal('1234.567')+(Decimal('45.67844')+Decimal('0.0004')))실수를 문자열로 만들어 Decimal 모듈을 사용하면 정확한 결과가 나옴을 확인할 수 있다.
함수
seed(x) : 시드 설정random() : 0부터 1사이의 소수가 리턴randint(min,max) : 숫자 사이의 정수 리턴uniform(min, max) : 숫자 사이의 실수 리턴randrange(시작,끝[, 간격]) gauss(m,sb) : 가우스 분포의 난수shuffle(시퀀스) : 시퀀스를 섞음choice(시퀀스) : 랜덤한 데이터를 리턴합니다.(복원추출)sample(시퀀스,개수) : 랜덤 데이터를 개수만큼 리턴(비복원 추출)이런 것이 나오면 help를 쳐보자. 뭐가 필요한지 직접 확인하기
import random random.seed(42)#seed를 고정해봤어. #help(random.randint) #randint(a, b) method of random.Random instance #Return random integer in range [a, b], #including both end points print(random.randint(1,45)) #seed를 고정하면 고정된 값이 나와 print(random.randint(1,45))
i= input("1부터 45까지의 정수를 공백으로 구분해서 6개 입력하세요") x=i.split(" ") lotto=list(map(lambda e: int(e),x)) lotto.sort() print(lotto) cnt=0 ar=range(1,46) #실행하지마 메모리터진다 while True: cnt+=1 gotcha=random.sample(ar,6) gotcha.sort() print(gotcha) if (lotto==gotcha): break else : print("실패!") print(cnt,"번 만에 로또에 당첨되었어요!")