그래서 우리가 인수로 메소드에 보내는 코드의 모든 숫자는 매직 넘버로 간주됩니까? 나에게 있어서는 안됩니다. 나는 어떤 숫자가 사용자 길이의 최소 길이라고 말하고 코드에서 “6”을 사용하기 시작한다고 생각합니다 … 그렇다면 유지 보수 문제가 있고 여기서 “6”은 마법의 숫자입니다 …. 인수 중 하나가 예를 들어 컬렉션의 i 번째 멤버로 정수를 허용하는 메소드를 호출하는 경우 해당 메소드 호출에 “0”을 전달합니다.이 경우에는 “0”을 마술로 볼 수 없습니다. 번호. 어떻게 생각해?
답변
문맥 상 숫자의 의미가 매우 분명 하다면 이것이 “마법의 숫자”문제라고 생각하지 않습니다.
예제 : 처음부터 토큰까지 문자열의 하위 문자열을 가져 오려고하는데 코드가 다음과 같습니다 (상상 언어 및 라이브러리).
s := substring(big_string, 0, findFirstOccurence(SOME_TOKEN, big_string));
이러한 맥락에서 숫자 0의 의미는 충분히 명확합니다. 나는 당신이 START_OF_SUBSTRING
그것을 정의 하고 0으로 설정할 수 있다고 가정 하지만,이 경우에는 과잉 일 것이라고 생각합니다 (하위 문자열의 시작이 0이 아니라는 것을 알고 있다면 그것은 올바른 접근법 일 것입니다. 당신의 상황).
다른 예는 숫자가 짝수인지 홀수인지 확인하려는 경우 일 수 있습니다. 쓰기:
isEven := x % 2;
다음과 같이 이상하지 않습니다.
TWO := 2;
isEven := x % TWO;
음수 테스트
MINUS_ONE := -1;
isNegativeInt := i <= MINUS_ONE;
나에게 이상하다고 느낀다.
isNegativeInt := i <= -1;
답변
bool hasApples = apples > 0;
명백한 영은 부재를 의미합니다. “absenceValue”라는 변수보다 0이 이해하기 쉽습니다.
for(int i=0; i < arr.length; i++)
0이 시작 위치라는 것은 명백합니다. “firstPosition”이라는 변수에 혼동 될 것입니다. 그러한 변수는 시작 위치가 변할 수 있는지 궁금하게 만듭니다.
답변
무언가를 지속적으로 선언해야하는지 결정할 때 세 가지 핵심 요소를 제안합니다.
- 숫자가 정확하고 간결하게 표현 가능한 것입니까?
- 값을 변경해야하는 적절한 시나리오가 있지만 코드를 다시 작성할 필요는 없습니다.
- 숫자를 보는 사람이 명명 된 상수를 보는 사람보다 더 빠르거나 덜 빨리 인식 할 수 있습니까?
숫자 리터럴은 불필요하게 장황하거나 불필요하게 부정확하거나 둘 다일 수 있으므로 pi와 같은 것은 숫자 리터럴이 아니라 명명 된 상수로 작성해야합니다. 캐시의 슬롯 수와 같은 것은 이름을 사용하는 상수 여야하며 (아래 참고 참조) 캐시를 사용하는 모든 코드를 수정하지 않고도 캐시를 확장 할 수 있습니다. 명령문에서 숫자 “4”, “28”및 “29”와 같은 if ((year % 4)==0) FebruaryDays = 29; else FebruaryDays = 28;
것은 상수보다 이름을 지정하지 않아야합니다. 표현식은보다 확실히 읽을 수 있기 때문 if ((year % YearsBetweenLeapYears)==0) FebruaryDays = FebruaryDaysInLeapYear; else FebruaryDays = FebruaryDaysInNonLeapYear;
입니다. 표준 관리자는 해당 연도의 2100 년 2 월 길이가 위의 공식과 일치하지 않음을 나타냅니다. 이러한 날짜를 올바르게 처리하는 데 방해가됩니다 (예 : 정수 오버플로 또는 다른 문제로 코드가 트립되지 않습니다).
규칙 # 2의 중요한 경고는 경우에 따라 코드가 명명 된 상수로 쉽게 표현할 수없는 방식으로 하드 코딩 된 숫자에 의존 할 수 있다는 것입니다. 예를 들어, 이산 파라미터로 전달 된 두 벡터의 교차 곱을 계산하는 방법은 3 차원 벡터에 사용될 때만 의미가 있습니다. 필요한 치수 수는 루틴을 완전히 다시 쓰지 않고 의미있게 변경할 수있는 값이 아닙니다. 3 차원 4 차원 벡터의 교차 곱을 계산할 필요가 있다고하더라도, 값 “3”에 대해 명명 된 상수를 사용하면 그러한 요구를보다 쉽게 충족시킬 수있을 것입니다.
답변
이것은 모든 원칙과 마찬가지로 정도의 문제입니다. 일반적으로 소스 코드의 숫자 리터럴은 더 큰 것으로 의심됩니다. 10과 같은 최대 길이 또는 0x587FB0과 같은 메모리 주소는 분명히 나쁜 습관입니다. 조만간이 값을 두 번 이상 반복하여 비 호환성 및 미묘한 오류가 발생할 수있는 위험이 발생할 수 있습니다. 변경되었습니다.
스케일의 다른 끝에 0이 있습니다. 여전히 용의자이지만 그다지 많지는 않습니다. 센티넬 값으로 0을 사용하고 있습니까? 그런 다음 상수가 의미를 설명 할 수 있기 때문에 대신 기호 상수를 사용해야합니다 . “0은 성공적인 완료를 의미합니다”와 같은 매우 문화적인 계약입니까? 아마 괜찮을 것입니다. “컬렉션의 첫 번째 항목”을 의미합니까? 그것은 무해 할 수 있지만, 다른 방법이 있다면 first()
선호 할 것입니다.
답변
문맥 상 명백하지 않은 이름없는 숫자는 모두 마법의 숫자입니다. 문맥에서 즉시 명백한 의미를 갖는 숫자를 정의하는 것은 조금 바보입니다.
django (python web framework)에서 다음과 같은 원시 숫자로 일부 데이터베이스 필드를 정의 할 수 있습니다.
firstname = models.CharField(max_length=40)
middlename = models.CharField(max_length=40)
lastname = models.CharField(max_length=40)
말하는 것보다 더 명확하고 권장되는 방법
MAX_LENGTH_NAME = 40
...
firstname = models.CharField(max_length=MAX_LENGTH_NAME)
middlename = models.CharField(max_length=MAX_LENGTH_NAME)
lastname = models.CharField(max_length=MAX_LENGTH_NAME)
길이를 변경할 필요가 없기 때문에 항상 max_length
필드 의 길이와 비교할 수 있습니다 . 응용 프로그램을 처음 배포 한 후 필드 길이를 변경해야하는 경우 django 코드에서 필드 당 정확히 한 위치에서 변경 한 다음 DB의 스키마를 변경하기 위해 마이그레이션을 추가로 작성해야합니다. max_length
객체 유형의 정의 된 필드 를 참조해야하는 경우 직접 수행 할 수 있습니다. 해당 필드가 Person
클래스 를 정의한 경우 Person._meta.get_field('firstname').max_length
에는max_length
사용 중 (한 곳에 정의 됨). 여러 필드에 동일한 40이 사용되었다는 사실은 독립적으로 변경하고 싶기 때문에 관련이 없습니다. 이름의 길이는 중간 이름 또는 성의 길이에 의존해서는 안됩니다. 이들은 별도의 값이며 독립적으로 변경 될 수 있습니다.
배열 인덱스는 종종 이름이없는 숫자를 사용할 수 있습니다. 파이썬 사전에 넣을 데이터의 CSV 파일이 있고 행의 첫 번째 요소를 사전으로 key
쓰면 다음과 같습니다.
mydict = {}
for row in csv.reader(f):
mydict[row[0]] = row[1:]
물론 나는 이름 index_column = 0
을 짓고 다음과 같은 것을 할 수 있습니다.
index_col = 0
mydict = {}
for row in csv.reader(f):
mydict[row[index_col]] = row[:index_col] + row[index_col+1:]
또는 더 나쁜 정의 after_index_col = index_col + 1
를 제거하기 위해 정의 index_col+1
하지만 내 관점에서 코드가 명확하지는 않습니다. 또한 index_col
이름을 지정하면 열이 0이 아니더라도 (그래서 row[:index_col] +
부분) 코드를 작동시키는 것이 좋습니다 .