내가 (최소한) 가장 좋아하는 Python 단점
14319 단어 python
선언이 실행됩니다
이것은 무슨 일이 일어나고 있는지 생각한 후에는 의미가 있지만 처음에는 틀리기 쉽다고 생각합니다.
한 가지 예는 다음과 같습니다.
class MyClass:
def __init__(self, data={}):
self._data = data
def set(self, k, v):
self._data[k] = v
def get(self, k):
return self._data.get(d)
def remove(self, k):
self._data.pop(k, None)
def get_count(self):
return len(self._data.keys())
A = MyClass()
A.get_count() # 0
A.set('a', 1)
A.get_count() # 1
B = MyClass()
B.get_count() # 1
A.remove('a')
A.get_count() # 0
B.get_count() # 0
추가로 실험해 보면
_data
의 내용이 MyClass
의 두 인스턴스 간에 동기화된 상태로 유지되고 있음을 알 수 있습니다.하지만 흥미롭게도:
C = MyClass({})
C.get_count() # 0
일어난 일은 파이썬이 파일을 한 줄씩 실행하여 클래스 및 함수 정의를 가져오는 것입니다. 즉,
data
메서드의 기본값 __init__
이 실제로 인스턴스화됩니다. 기본값을 사용하는 클래스의 모든 인스턴스는 동일한 객체에서 변경 및 읽어서 효과적으로 클래스 변수가 됩니다.이것은 다음에 의해 확인됩니다.
A._data is B._data # True
이것을 피하려면 다음과 같은 둔한 일을 해야 합니다.
class MyClass:
def __init__(self, data=None):
if data is None:
self._data = {}
else:
self._data = data
...
루프 변수의 범위
많은 언어와 달리 Python의 "루프 변수"는 루프가 종료된 후에도 로컬 범위에 유지됩니다. 이로 인해 예기치 않은 동작이 발생할 수 있습니다.
def fun():
i = 0
arr = [1, 2, 3]
# lots of code
for i in range(len(arr)):
# do some stuff
# more code
return arr[i]
fun() # returns 3
이 예제는 상당히 인위적이지만, 일반적인 아이디어는 루프 변수의 이러한 동작이 이상하고 추적하기 어려운 버그(이전에 선언된 로컬 변수를 섀도잉하는 이 예제 포함)로 이어질 수 있다는 것입니다.
또 다른 합병증: 반복할 항목이 없으면 루프 변수가 전혀 할당되지 않습니다. 예를 들어 아래
main()
의 첫 번째 줄은 오류 없이 실행되지만 두 번째 줄은 NameError: name 'x' is not defined
가 발생합니다.def fun(l):
for x in l:
print(x)
return x
def main():
fun([1, 2, 3])
fun([])
다른 해석 및 중괄호가 아닌 언어조차도 이러한 문제를 피합니다. 루비:
3.times do |x|
print x
end
x # NameError (undefined local variable or method `x' for main:Object)
함수 체이닝은 어렵다
데이터 구조 작업과 관련하여 Python에서 제공하는 함수와 메서드는 매우 일관적이지 않습니다. 목록을 예로 들어 보겠습니다.
List
클래스에는 제자리에서 변경하는 메서드가 있지만 많은 작업의 경우 새 목록을 반환하고 고유한 구문을 갖는 목록 이해를 사용해야 합니다. 다른 작업의 경우 filter
및 map
(목록 클래스의 메서드가 아님) 함수를 사용할 수 있습니다. 그리고 목록 작업을 위한 함수인 join
가 목록 메서드가 아닌 문자열 메서드라는 사실과 같이 다른 흩어져 있는 불일치가 있습니다.예로서:
def slugify(string, bad_words):
words = string.split()
words = [w.lower() for w in words if w.isalpha() and w not in bad_words]
return "-".join(words)
slugify("My test 1 string", set(["dang", "heck"])) # "my-test-string"
Python에 익숙한 사람들에게는 이것이 자연스러워 보일 수 있지만 여전히 코드는 함수가 수행하는 각 변환을 이해하기 위해 주의 깊게 읽어야 합니다(그리고 이것은 간단한 예를 위한 것입니다).
다른 언어에서는 이런 종류의 코드가 더 자연스럽습니다. 예를 들어 Ruby에는 연결을 허용하는 보다 일관된 방법이 있습니다.
def slugify(string, bad_words)
string.split()
.map(&:downcase)
.select { |w| w.match(/^[[:alpha:]]+$/) }
.select { |w| !bad_words.include? w }
.join("-")
end
slugify("My dang test 1 string", Set["dang", "heck"]) # "my-test-string"
기능적 세계의 예로서, Clojure는 일관된 API와 스레딩 매크로
->
및 ->>
를 사용하여 기능 체인을 강력하게 지원합니다.(defn slugify [string bad-words]
(->> (str/split string #" ")
(filter #(re-matches #"^[a-zA-Z]*$" %))
(remove bad-words)
(map str/lower-case)
(str/join "-")
)
)
(slugify "My dang test 1 string" (set '("dang" "heck"))) ; "my-test-string"
Reference
이 문제에 관하여(내가 (최소한) 가장 좋아하는 Python 단점), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/cselig/my-least-favorite-python-quirks-54j3텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)