파이썬 문법 overview
인덴트, 네이밍 컨벤션, 타입힌트, 리스트 컴프리핸션, 제너레이터, range, enumerate, // 나눗셈 연산자, print, pass, locals 에 대하여 전반적으로 살펴보겠습니다
인덱스
공백 4칸을 원칙으로 한다.
네이밍 컨벤션
파이썬의 변수명 네이밍컨벤션은 자바와 달리 각 단어를 밑줄(_)로 구분하여 표기하는 스테이크 케이스를 따른다.
ex. my_class
↔ 카멜 케이스 : 대소문자를 구별하여 표기하는 방식
ex.MyClass
타입힌트
파이썬은 대표적인 동적 타이핑 언어이지만, 타입을 지정할 수 있는 타입힌트가 PEP 484에서 추가되었다. 파이썬 버전 3.5부터 사용할 수 있다.
기존에는 타입 힌트를 사용하지 않았지만(이는 빠르게 정의하여 사용할 수 있다는 장점이 있다) 함수의 파라미터 a에는 숫자를 넘겨야 하는지, 문자를 넘겨야 하는지 전혀 알 수 없으며, 이 함수의 리턴값(타입)이 무엇인지도 알 수 없다.
이는 나중에 프로젝트의 규모가 커지게 되면 가독성을 떨어뜨리게 되며 무엇보다 버그유발의 주범이 된다.
a: str ="1"
b: int = 1
def fn(a: int) -> bool:
return True
이처럼 타입 힌트를 사용하게 되면 이제 fn()함수의 파라미터가 a가 정수형임을 분명하게 알 수 있으며 리턴 값으로 True 또는 False를 리턴할 것이라는 점도 확실히 알 수 있다.
이점🎈
- 명시적 선언으로 인해 가독성이 좋아짐
- 버그 발생 확률 줄일 수 있다.
(주의) 강제 규약이 아니다 보니, 여전히 동적으로 할당될 수 있음.
리스트 컴프리헨션
1. map함수
map은 리스트의 요소를 지정된 함수로 처리해주는 함수이다(map은 원본 리스트를 변경하지 않고 새 리스트를 생성한다).
- list(map(함수,리스트))
- tuple(map(함수,투플))
함수는 단순히 형변환도 가능하다 ( int,str 등 )
# map 적용 안했을때
a=[1.2,3.3,4.5]
for i in range(len(a)) :
a[i]=int(a[i])
print(a)
# map 적용 했을때
b= list(map(int,a))
print(b)
map()의 출력결과는 iterator이기 때문에 아래와 같이 맞는 결과인지 확인 할 수 없다. next를 이용하여 하나씩 확인해보아도 되지만 대부분 형변환(list나 tuple등)을 하여 결과를 확인한다.
target=[2.2,3.3,4.4]
hello=map(lambda x: x+1, target)
print(hello)
print(list(hello))
2. filter 함수
map함수와 사용방법은 동일하나, 함수의 값이 참이냐 거짓이냐에 따라 해당요소를 포함할 지 결정한다
# filter 적용 안했을 때
target = [ 1,2,3,4,5,6,7 ]
new=[]
def is_even(num: int) -> bool:
if num%2 ==0 :
return True
else :
return False
for i in target :
if is_even(i):
new.append(i)
print(new)
# filter 적용 했을 때
target=[1,2,3,4,5,6]
a= filter(lambda x: x%2==0, target)
print(a)
print(list(a))
#print(list(a[2])) 이건 안됨..
b=list(filter(lambda x: x%2==0, target))
print(b)
print(b[2])
3. 리스트 컴프리헨션
기존 리스트를 기반으로 새로운 리스트를 만들어내는 구문
(딕셔너리도 가능)
# 리스트 컴프리헨션을 사용한 경우
[n*2 for n in range(1, 10+1) if n%2 ==1 ]
# 리스트 컴프리헨션을 사용하지 않은 경우
a = []
for n in range(1,10+1):
if n%2 == 1 :
a.append(n*2)
제너레이터
루프의 iteration 동작을 제어할 수 있는 루틴 형태
ex. 임의의 조건으로 숫자 1억개를 만들어내는 프로그램 작성
- 제너레이터 x : 메모리 어딘가에 숫자 1억 개를 보관해야 함
- 제너레이터 o : 단순히 제너레이터만 생성해두고 필요할 때 언제든 생성 가능
yield 구문을 사용하면 제너레이터를 리턴할 수 있음.
↔ 기존의 함수는 return 구분을 맞닥뜨리면 값을 리턴하고 모든 함수의 동작 종료
def get_natural_number() :
n=0
while True :
n +=1
yield n
get_natural_number()
#output : <generator object get_natural_number at 0x7fb01d6ffb50>
만약 다음 값을 생성하려면 next()로 추출하면 된다. 예를 들어 100개의 값을 생성하고 싶다면 다음과 같이 100번동안 next()를 수행하면 된다.
g=get_natural_number()
for _ in range(0,100):
print(next(g))
아울러 제너레이터는 다음과 같이 여러 타입의 값을 하나의 함수에서 생성하는 것도 가능하다.
def generator() :
yield 1
yield 'string'
yield True
g= generator()
g
# 출력 : <generator object generator at 0x7fb01d5d2c50>
print(next(g))
print(next(g))
print(next(g))
# 출력 : (차례대로) 1, 'string', True
range
제너레이터 방식을 활용하는 대표적인 함수로 range()가 있다.
print(list(range(5)))
print(range(5))
print(type(range(5)))
for i in range(5):
print(i,end=' ')
a=[n for n in range(10000)]
# 출력 : 0부터 10000까지의 값이 모두 저장되어 출력
b= range(10000)
# 출력 : range(0,10000)
a
b
a는 이미 생성된 값이 담겨있고, b는 생성해야 한다는 조건만 존재한다.
이제 둘 사이의 메모리 점유율을 비교해보면 range 클래스를 리턴하는 방식의 장점이 쉽게 와닿을 것이다.
import sys
sys.getsizeof(a)
# 출력 : 87632
sys.getsizeof(b)
# 출력 : 48
enumerate
순서가 있는 자료형(list,tupel,set등)을 인덱스를 포함한 emurate객체로 리턴한다.
a=[1,2,3,2,45,2,5]
a
b=list(enumerate(a))
# list()로 결과를 추출할 수 있는데, 인덱스를 자동으로 부여해주기 때문에 매우 편리하게 사용할 수 있다.
print(b)
# 출력 : [(0,1),(1,2),(2,3),(3,2),(4,45),(5,2),(6,5) ]
print(b[4])
# 출력 : (4,45)
# enumerate를 사용하지 않는다면?
for i in range(len(a)):
print(i,a[i])
# 불필요한 a[i] 조희작업과 전체길이를 조회해야한다는 점이 있다.
// 나눗셈 연산자
- //연산자는 몫을 구하는 연산자이다
5//3 # int(5//3)과 동일한 표현식이다.
# 출력 : 1
5/3
# 출력 : 1.66666...
5%3
# 출력 : 2
divmod(5,3) #몫과 나머지를 한 번에 구할 때
# 출력 : (1,2)
print('A1','A2') #자동 띄어쓰기로 값을 구분해줌
# 출력 : A1 A2
print('A1','A2', sep=',') # 구분자를 콤마(,)로 지정해줄 수도 있다.
# 출력 : A1,A2
# print()는 항상 줄바꿈을 해준다.
print('aa', end=' ')
print('bb')
# 출력 : aa bb
# 리스트를 출력할 때는 join()으로 묶어서 처리한다.
a = ['A', 'B']
print(' '.join(a))
# format과 f-string 방법
print('{0}:{1}'.format(2,"str"))
print(f'{2}:{"str"}')
# 출력 : 2:'str'
pass
코딩을 하다보면 일단 코드의 전체 골격을 잡아놓고 내부에서 처리할 내용은 차근차근 생각하며 만들겠다는 의도로 다음과 같이 코딩하는 경우가 있다.
class MyClass(object):
def method_a(self):
pass
def method_b(self):
pass
구글 파이썬 스타일 가이드
함수의 기본값으로 가변객체(mutable object)를 사용하지 않아야 한다. 함수가 객체를 수정하면 기본값이 변경되기 때문이다. 따라서 다름과 같이 기본값으로 []나 {}를 사용하는 것은 지양해야 한다.
# 지양
def foo(a,b=[]):
pass
def foo(a,b ={}):
pass
대신 다음과 같이 불변 객체(immutable object)를 사용한다. None을 명시적으로 할당하는 것도 좋은 방법이다.
#지향
def foo(a,b=None):
pass
def foo(a,b=None):
if b==None:
b=[]
pass
Ture, False를 판별할 때는 암시적(implicit)인 방법을 사용하는 편이 간결하고 가독성이 좋다.
ex. len(users) ==0 은 not users 로 충분하다
그러나 정수를 처리할 때는 암시적이기 보다는 직접 비교하는 편(명시적 작성)이 덜 위험하다. 모듈로 연산 결과가 0인 것을 정수로 처리하지 않고 암시적 거짓 여부로 판별하는 위험하기 때문이다.
Author And Source
이 문제에 관하여(파이썬 문법 overview), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@rhdmstj17/파이썬-고급-문법-overview저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)