# 숫자 list를 가지고 제곱한 list를 생성 li=[i for i in range(10000)] #0부터 9999까지의 숫자를 가지고 list를 생성 temp=[] for x in li: temp.append(x*x) print(temp)
def f(x): return x*x #한줄이면 lambda로 바꿀 수 있다. temp=list(map(f,li)) #함수를 먼저주고 데이터를 뒤에다 줘야한다. print(temp)
temp =list(map(lambda x: x*x, li)) #함수의 내용이 한줄이기에 람다로 처리 가능 print(temp)
ar=["Hello", "mino", "5894"] def f(x): if len(x)>3: return x[0:3]+"..." return x temp=list(map(f,ar)) print(temp)
ar1=["a","b","c",None] #결측치 여부 확인 print(None in ar1) #in : 앞에 애가 뒤에 애 안에 있니?(탐색) #결측치 제거 def f1(x): return x!=None ar1=list(filter(f1,ar1)) print(ar1) #이름이 3자 이상인 데이터만 추출 def f2(x): return len(x)>=3 #None type은 len사용 불가야 #결국 결측값을 지워야 하겠구나! result=list(filter(f2,ar1)) print(result) #문자열 비교 가능? def f3(x): return x[0]>="아" and x[0]<"자" result3=list(filter(f3,ar1)) print(result3) #ar1=list(filter(lambda x: x!None, ar1)) #result=list(filter(lambda x: len(x)>=3, ar1)) #result3=list(filter(lambda x: x[0]>="아" and x[0]<"자", ar1))
# 데이터가 collection에 포험되어 있는지 확인 : in(반대는 not in) ar=["1","2","3"] kwlist=["2"] #ar에서 kwlist에 있는거 뺴고 list생성 ar_new=list(filter(lambda x: x not in kwlist, ar)) print(ar_new) #글자의 개수를 세서 하거나, 공백을 제거하였을 때 kwlist에 있는지
from functools import reduce result=reduce(lambda x, y : x*y, [1,2,3,4]) print(result)
key=["초등학교","중학교","고등학교"] value=["a초등학교","b중학교","c고등학교"] print(list(zip(key,value))) print(dict(zip(key,value)))
진짜 단순히 묶어주는 역할입니다.
def outer(): outer_data="함수 외부에서 만든 데이터" def inner(): print(outer_data) inner() outer()
이 구문은 에러가 나지 않습니다.
inner를 호출할 때 outer_data는 함수 회부에 있는 oute_data로 해석이 되기 때문입니다.
def outer(): outer_data="함수 외부에서 만든 데이터" def inner(): print(outer_data) outer_data="함수 내부에서 만든 데이터" inner() outer() UnboundLocalError: local variable 'outer_data' referenced before assignment
이 코드는 에러
outer_data가 만들어지기 전에 사용되었다고 해석해서 에러가 발생합니다.
def outer(): outer_data="함수 외부에서 만든 데이터" def inner(): outer_data="함수 내부에서 만든 데이터" print(outer_data) inner() print(outer_data) outer()
과연 outer에 있는 출력은?
함수 외부에서 만든 데이터 가 출력이 된다.
왜냐? outer에서 불렀기 때문이다.
def outer(): outer_data="함수 외부에서 만든 데이터" def inner(): nonlocal outer_data # 함수 내부에 데이터를 생성하지 않고 # 외부 데이터 사용하기 위해 이름을 다시 등록 outer_data="함수 내부에서 만든 데이터" print(outer_data) inner() print(outer_data) outer()
이렇게 된다면 outer_data는 inner에서 만들어 지는 것이 아니다.
결과물도 "함수 내부" 가 2번 나올 것이다.
outer_data="로컬에서 만든 데이터" def outer(): def inner(): global outer_data # 함수 내부에 데이터를 생성하지 않고 # 외부 데이터 사용하기 위해 이름을 다시 등록 outer_data="함수 내부에서 만든 데이터" print(outer_data) inner() print(outer_data) outer()
이렇게 한다면 inner에서 nonlocal이 아닌 global로 바꿔야 한다. 왜냐하면 블록 밖에 있는 전역변수를 가져와 쓰는 것이기 때문이다.
def outer(): data=0 #data=data+1 #outer에서 만들어진 것이기 때문에, #outer에서만 사용 가능합니다.
def outer(): data=0 #자신을 감싸고 있는 #함수의 데이터를 수정하는 함수 def inner(): nonlocal data data=data+1 print(data) return inner #함수 호출해서 리턴하는 함수를 변수에 저장 closure=outer() closure() closure()
이렇게 접근하면 closure를 이용해서 쉽게 접근 가능합니다.
def commonConcern1(): print("공통 관심 사항_1") def commonConcern2(): print("공통 관심 사항_2") def businessLogic(): print("비즈니스 로직") def transaction(): commonConcern1() businessLogic() commonConcern2() #이렇게 한다면 나 혼자 일하면 되는거고 #businessLogic 일때만 같이하면 된다. #이것이 모듈화 프로그래밍이다. #이후에는 또 파일까지 쪼개게 된다.
이렇게 쪼개서 작업하는 것을 AoP이다.
왜 이것을 하는지 정말 중요해
어떤 업무 로직 앞에 무엇인가를 해야 한다면 이걸 다 뜯어고쳐?
아니다
def deco(func): print("hello Wolrd!") func() # 이제부터 businessLogic 이라는 함수를 호출하면 # deco라는 함수를 수행 # 개발자가 작성한 코드 대신에 다른 코드를 불러내는 방식은 # 프록시 패턴이라고 합니다. def commonConcern1(): print("공통 관심 사항_1") def commonConcern2(): print("공통 관심 사항_2") @deco def businessLogic(): print("비즈니스 로직") #업무로직에 프린트 앞에 helloworld를 찍어야 한다는데? businessLogic()
프록시 라고 합니다.
쉽게 보면 @deco를 한거면 deco의 func는 businessLogic이 된것
#고객의 니즈 변경 #업무 로직과 관계가 없는 로깅을 출력하는 코드를 추가하기를 #원하는 방향으로 변경 #유지보수 과정이나 업무 로직과 관련이 없는 코드를 #추가하거나 삭제하는 경우 #업무 로직을 직접 수정하는 것은 예상치 못한 결과를 #만들어 낼 수 있습니다. #이런 경우에는 업루 조기은 손을 대지 않고 기능하도록 #만드는 것이 좋습니다. def urNeeds(func): func() print("로깅") @ urNeeds def businessLogic(): print("업무 로직") businessLogic()
이런 방식의 프로그래밍은 AoP : 관점지향 프로그래밍 이다.
import time #시간 측정을 위해 def clock(func): #decorator가 적용된 함수가 호출되면 #수행될 실제 함수 def clocked(*args): start=time.time() #현재 시간 기록 #업무로직 함수 result=func(*args) end=time.time() elapsed=end-start#함수 수행시간 print(elapsed) #매개변수 확인 print("매개변수:", args) #return 값 확인 print("리턴값 : ", result) return result return clocked @clock def solution(s): #그냥 내가 만든 함수 result=[] word_index=[] word=[] word=s for i in range(len(s)): word_invers=word_index[::-1] if s[i] not in word_index: word_index.append(word[i]) result.append(-1) elif s[i] in word_index: word_index.append(word[i]) idx=word_invers.index(s[i])+1 result.append(idx) return result solution("babamba")
결과는 아래와 같다.
0.0
매개변수: ('babamba',)
리턴값 : [-1, -1, 2, 2, -1, 3, 3]
import time #시간 측정을 위해 import functools #functools로 재귀의 속도 향상을 노려보자 def clock(func): #decorator가 적용된 함수가 호출되면 #수행될 실제 함수 def clocked(*args): start=time.time() #현재 시간 기록 #업무로직 함수 result=func(*args) end=time.time() elapsed=end-start#함수 수행시간 print(elapsed) #매개변수 확인 print("매개변수:", args) #return 값 확인 print("리턴값 : ", result) return result return clocked @functools.lru_cache() #편하다 편해 @clock def fibonacci(n): if n==1 or n==2: return 1 else: return fibonacci(n-1)+fibonacci(n-2) fibonacci(20)
class 클래스이름: 초기화 메서드 생성 메서드 생성
(인스턴스 이름 = )초기화메서드(매개변수)
초기화 메서드의 이름은 클래스이름
인스턴스 이름은 생략 가능하지만, 이름을 만들어 재사용성을 높임
def 메서드이름(인스턴스를 참조 저장할 매개변수, 이후 매개변수나열)): 내용
관례상 인스턴스 참조를 저장할 매개변수의 이름은 self
class이름 .메서드이름(인스턴스,매개변수)
: Unbound 호출인스턴스 .메서드이름(매개변수)
:bound 호출self.method이름(매개변수)
: 클래스 내부의 다른 메서드에서 호출class Student: #인스턴스가 있어야만 호출되는 메서드 def disp(self): print("인스턴스 생성") #인스턴스 생성 mino=Student() mino가 인스턴스가 이난 Student()가 인스턴스이다. #한번만 사용한다면 상관이 없다. #재사용을 위해 이름만 붙일 뿐이다. #bound 호출 - 일반적으로 씁니다. 주로. mino.disp() #unbound 호출 Student.disp(mino)
이걸 죽여패도 모르면 안된다.
self.속성명
으로 데이터를 대입하면 만들어집니다.self.
을 이용하지 않고 만든 속성은 지역변수가 됩니다.인스턴스.속성이름=데이터
코드를 작성하면, 속성이 존재하면 속성의 값을 변경하는 것이고, 속성이 존재하지 않으면 속성이 생성됩니다.class Student: #인스턴스가 있어야만 호출되는 메서드 def disp(self): print("인스턴스 생성") def setName(self, name): self.name=name #self.name은 instance의 속성으로 만들어집니다. #그냥 name을 했으면, 지역변수로 됩니다. #인스턴스 생성 mino=Student() #mino가 인스턴스가 아닌 Student()가 인스턴스이다. mino.setName("mino") mino.score=94 #instance에 score라는 속성 없으면 만들고 있으면 수정 print(mino.score) print(mino.name) #bound 호출 - 일반적으로 씁니다. 주로. mino.disp() #unbound 호출 Student.disp(mino)
python은 동적으로 필요한 속성을 만드는 것을 확인할 수 있다.
class Student: class_data="클래스의 속성" #이 데이터는 클래스가 가지고 있다. mino=Student() print(Student.class_data) #클래스 이름을 이용해서 클래스 속성에 접근 print(mino.class_data) #인스턴스 이름을 이용해서 클래스 속성에 접근 Student.class_data="클래스 데이터를 수정했어요 클래스를 통해서" print(Student.class_data) #클래스 이름을 이용해서 클래스 속성에 접근 print(mino.class_data) #인스턴스 이름을 이용해서 클래스 속성에 접근 mino.class_data="인스턴스를 통해 클래스 데이터를 수정했어요" print(Student.class_data) #클래스 이름을 이용해서 클래스 속성에 접근 print(mino.class_data) #인스턴스 이름을 이용해서 클래스 속성에 접근
인스턴스로 클래스 데이터를 수정하면 인스턴스의 속성값만 바뀌고 클래스에서 호출한 클래스 속성 데이터는 그대로이다.
set1.union(set2)
와Set union(set1,set2)
는 같지만 뭔가 느낌이 다르다.
약간 "내가 동생과 영화를 보러갔다."와 "영화를 보러갔다 나와 동생이."의 느낌 차이이다.
인스턴스는 메서드를 가지고 있지 않다.
메서드는 클래스 안에 만들어두고 공유하는 개념이다.
==연산자는 오버로딩(기능을 변경)이 가능합니다.
그렇기 때문에 어떻게 동작할지 예측하기 어렵습니다.
class Student: class_data="클래스 속성" #인스턴스 생성 후 대입 stu1=Student() #인스턴스 생성 후 대입 stu2=Student() #stu1의 데이터를 대입 stu3=stu1 #이렇게 된다면 stu1이 참조하고 있는 #데이터의 참조를 stu3가 참조합니다. #두개의 인스턴스가 동일한지 여부 확인 print(stu1==stu2) print(stu1==stu3) #내부 데이터가 같은지확인, #id가 달라도 true가 나올 순 있음 #==를 __eq__오버로딩해야함 print(stu1 is stu2)#id가 같은지 확인 print(stu1 is stu3)#참조하기에 id는 같음
getter
이름은 get속성이름으로 하고
매개변수는 일반적으로 없고 속성을 리턴하기만 합니다.
예외적인 경우 :
속성의 자료형이 bool인 경우 get 대신 is를 붙입니다.
속성의 이름의 첫글자는 대문자로 표기,
python에서는 대문자 대신 언더바를 사용하는 경우가 있습니다.
setter
이름은 set속성이름으로 하고
매개변수는 속성과 동일한 자료형의 데이터 1개로 생성
내용은 매개변수로 받은 데이터를 속성에 대입합니다.
속성의 자료형이 Sequantial(list)인 경우 :
인덱스를 받아서 인덱스 번째 데이터를 리턴하는 getter를
추가로 생성하고
인덱스와 데이터 1개를 받아서 인덱스번째 데이터를 수정하는 setter를 생성하기도 합니다.
리스트에서 하나만 수정할 수 있도록 만들 수 있겠지
#이름과 점수를 갖는 객체를 여러개 사용해야한다. class Student: def getName(self): return self.name def setName(self,name): self.name=name def getScore(self): return self.score def setScore(self,score): self.score=score stu1=Student() #setter를 이용한 속성 생성과 설정 stu1.setName("mino") stu1.setScore(100) #getter를 이용한 속성 사용 print(stu1.getName()) print(stu1.getScore()) #최근에 등장한 IDE는 대부분 getter와 setter를 만드는 유틸을 제공
객체지향 언어에서는 속성을 직접 수정하지 말자. 메서드를 통해서 하자
class Student: def disp(): print(data)
이렇게 존재한다고 가정하자
stu1=Student() stu1.data="hi" stu1.disp() stu2=Student() stu2.data="hello" stu2.disp()
instance를 2개 생성하였다.
print(data)
와 stu1, stu2를 생각하면 해당 공간에서는 data가 아닌 stu1, stu2의 데이터가 모두 필요하다.이때, data대신
self.data
를 사용한다면 instance를 method가 전부 보유할 필요는 없어진다.
class Student: class_data=10 stu=Student() print(Student.class_data) print(stu.class_data) stu.class_data=20 print(stu.class_data)
이렇게 존재한다고 해보자.
우선 print(stu.class_data)
를 보면, 인스턴스의 class_data는 아직 존재하지 않아서 class의 속성값을 가져온 것이다.
그래서 print(Student.class_data)
print(stu.class_data)
이 둘의 결과는 우선 같다.
하지만 stu.class_data=20
를 통해서 해당 속성값이 없다면 속성값을 만들어 주기 때문에, 인스턴스의 속성값이 생긴다.
이후 print(stu.class_data)
를 한다면 class의 속성값과는 다르게 나올 것이다.
해당 코드의 구조는 아래와 같다.