본문 바로가기
Programing/TIP

[Programing] 깔끔한 코드 짜는 10가지 규칙

by 꾸압 2021. 3. 5.
def get_librosa_mfcc(filepath, n_mfcc = 40, del_silence = False, input_reverse = True):
    if filepath.split('.')[-1] == 'pcm':
        pcm = np.memmap(filepath, dtype='h', mode='r')
        sig = np.array([float(x) for x in pcm])
    elif filepath.split('.')[-1] == 'wav':
        sig, _ = librosa.core.load(filepath, sr=16000)
    else:
        raise ValueError("Invalid format !!")
    if del_silence:
        non_silence_ids = librosa.effects.split(sig, top_db=30)
        sig = np.concatenate([sig[start:end] for start, end in non_silence_ids])
    mfcc = librosa.feature.mfcc(sig, sr=16000, hop_length=160, n_mfcc=n_mfcc, n_fft=400, window='hamming')
    if input_reverse:
        mfcc = mfcc[:,::-1]
    return torch.FloatTensor( np.ascontiguousarray( np.swapaxes(mfcc, 0, 1) ) )

[출처] [좋은 코딩 습관] 깔끔한 코드 짜는 10가지 규칙|작성자 Sooftware

1) 변수, 클래스명에는 동사를 넣지 않는다

class: FeatureExtract (X)
class: FeatureExtractor (O)

var: work (X)
var: worker (O)

var: log (X)
var: logger (O)

변수, 클래스 명은 다음과 같이

count, worker_num, image, user ... 등

숫자, ~을 하는 객체, ~한 여부 (bool) 등이기 때문에

동사보다는 명사가 가장 잘 어울린다.

 

2) 함수명에는 동사를 넣는다

function: feature() (X)
function: get_feature() (O)

function: trainer() (X)
function: train() (O)

반면, 함수의 경우 ~을 하는 행동을 정의한다.

feature를 받아오는 함수라고 하면, feature() 보다는 get_feature() 과 같이 ~하다 라는

의미가 담긴 명명이 잘 어울린다.

 

3) 변수 명에 굳이 관사를 넣지 않는다

var: a_cat (X)
var: cat (O)

가장 좋은 변수 명은 짧으면서도 효과적으로 의도를 전달하는 변수명이다.

굳이 관사를 넣어 변수 명이 길어 질 필요가 없다.

 

관사를 넣는다고 의도 전달이 더 명확하게 되는 것도 아니므로

변수 이름, 함수 이름, 클래스 이름에 특수한 경우를 제외하고는 

굳이 관사를 넣지 않는다.

 

4) 변수 이름에 전치사는 최대한 생략

var: the_number_of_worker (X)
var: worker_num (O)

number_of_worker 같이 전치사를 넣는 경우가 있다.

그러나 단순히 의도만 표현하는데 굳이 문법을 갖출 필요는 없다.

'number_of_worker' 보다는 'worker_num'이 의미가 같으며 더 간결하다.

 

참고로 수를 세거나 숫자를 표기하는 변수는 some_num, count_some, cnt_some 형식을 많이 사용한다.

class: Seq2seq
function: sentence_to_id()
var: char2id

위와 같이 'to' 는 함수나 변수에서 자주 쓰이는데 이는 짧지만 의도를 잘 전달하는 단어이기에 그렇다.

더불어 to 의 경우 2(two) 와 발음의 유사성으로 _to_ 라는 네 글자를 2라는 한 글자로 줄여 char_to_id 가 char2id 처럼 쓰인다.

 

5) 단수와 복수를 구분

items = [1,2,3,4,5]
for item in items:
    print(item)

단수와 복수를 구분해놓으면 코드 읽기가 편하다

단수형이면 어떤 값 혹은 객체가 하나인 자료형, 복수형이라면 여러 값 혹은 객체가 들어 있는 자료형으로 구분 가능하다.

 

6) 사용하는 언어의 암묵적 Rule을 지킨다

CamelCase: Java
snake_cake: c
Hybrid: python

어떤 언어를 사용 시, 대부분 프로그래머가 지키는 암묵적 Rule이 있다.

프로그램 실행이나 결과에 영향을 주는건 아니지만, 타인의 코드를 더 읽기 편하게 하거나 사용하기 용이하게 하는 규칙이다.

 

예시로 Java의 CamelCase와 C언어의 snake_case가 있다.

camel case는 단어&단어 사이를 대문자로 구분하는 방법으로, Java에서 변수, 함수, 클래스 명 모두 camel case를 권장한다.

반면 c언어는 snake case를 자주 사용하며, 단어&단어 사이를 ' _ ' 로 구분한다.

CamelCase Example

var: raiseValueError
var: sentenceToId

snake_case Example

var: raise_value_error
var: sentence_to_id

 

파이썬은 'PEP-8'이라는 권장 형식이 있다. 그러나 권장 사항일 뿐 더 깔끔한 코딩이 가능하다면 규칙을 지킬 필요는 없다.

- 클래스 명은 대문자로 시작하고 CamelCase를 따르며, 함수 명은 snake case를 따른다.

- 클래스 내부에서 사용하는 메소드는 메소드 앞에 ' _ '로 시작한다.

 

7) 보편적으로 사용하는 변수명/규칙 을 사용한다.

temp, obj, worker

some_num, count_some

flag, idx, is_condition

info, freq, token

타인의 코드를 보면 보통 꼭 등장하는 변수 이름이 있다.

- temp : 특정 변수를 임시 저장하는 변수

- flag : 특정 조건이 성립했는지 체크하는 변수

- is_condition : bool 타입 변수에서 쓰는 변수

- some_num : 특정 수를 세거나 표기하는 변수

 

특정 변수 명은 이름만으로 어떤 역할을 할 지 예측 가능한데, 예시로 bool 타입과 int 타입 등이 있다.

자주 사용하는 변수 명이나 형식은 분야에 따라 차이가 있으므로, 같은 분야의 여러 코드를 보면 많은 도움이 된다.

 

8) 상수는 모두 대문자로 표시

var: layer_size = 6 (X)
var: L = 6 (O)
var: main_width = 1024 (X)
var: MAIN_WIDTH = 1024 (O)
var: main_height = 768 (X)
var: MAIN_HEIGHT = 768 (O)

 

불변 값의 상수라면 그 값이 변하지 않음을 표시해줘야 한다.

그에따라 보통 모두 모두 대문자와 _ 로만 구성된 변수는 상수로 통한다. (물론 단어 사이를 구분할 때도 _ 를 쓴다.)

 

9) 변수가 길면 적당히 자른다.

var: total_distance (△)
var: total_dist (O)

var: user_information (△)
var: user_info (O)

var: worker_number (△)
var: worker_num (O)

var: index (△)
var: idx (O)

var: indices (△)
var: ids (O)

var: probability (△)
var: prob (O)

명확한 의도 전달을 위해 자세히 쓰는건 좋지만, 너무 긴건 코드를 복잡하게 한다.

 

10) 로직이 끝나면 한 줄 띄어준다.

같은 함수 내에도 여러 로직이 있다.

변수를 선언 부분, 계산 부분, for 등의 반복문 등이 그렇다.

'하나의 함수를 한 화면 내에 모두 들어오게' 하기 위해 줄 띄우기 없이 모두 붙이는 경우가 있으나, 이는 가독성이 매우 떨어지는 일이다.

 

[예시.1] 한 화면에 모두 채운 경우

def get_librosa_mfcc(filepath, n_mfcc = 40, del_silence = False, input_reverse = True):
    if filepath.split('.')[-1] == 'pcm':
        pcm = np.memmap(filepath, dtype='h', mode='r')
        sig = np.array([float(x) for x in pcm])
    elif filepath.split('.')[-1] == 'wav':
        sig, _ = librosa.core.load(filepath, sr=16000)
    else:
        raise ValueError("Invalid format !!")
    if del_silence:
        non_silence_ids = librosa.effects.split(sig, top_db=30)
        sig = np.concatenate([sig[start:end] for start, end in non_silence_ids])
    mfcc = librosa.feature.mfcc(sig, sr=16000, hop_length=160, n_mfcc=n_mfcc, n_fft=400, window='hamming')
    if input_reverse:
        mfcc = mfcc[:,::-1]
    return torch.FloatTensor( np.ascontiguousarray( np.swapaxes(mfcc, 0, 1) ) )

 

[예시.2] 한 줄씩 띄어쓰는 경우

def get_librosa_mfcc(filepath, n_mfcc = 40, del_silence = False, input_reverse = True):
    if filepath.split('.')[-1] == 'pcm':
        pcm = np.memmap(filepath, dtype='h', mode='r')
        sig = np.array([float(x) for x in pcm])

    elif filepath.split('.')[-1] == 'wav':
        sig, _ = librosa.core.load(filepath, sr=16000)

    else:
        raise ValueError("Invalid format !!")

    if del_silence:
        non_silence_ids = librosa.effects.split(sig, top_db=30)
        sig = np.concatenate([sig[start:end] for start, end in non_silence_ids])

    mfcc = librosa.feature.mfcc(sig, sr=16000, hop_length=160, n_mfcc=n_mfcc, n_fft=400, window='hamming')

    if input_reverse:
        mfcc = mfcc[:,::-1]

    return torch.FloatTensor( np.ascontiguousarray( np.swapaxes(mfcc, 0, 1) ) )

 

 

원본 링크 : blog.naver.com/sooftware/221846090355

댓글