빈 목록이있는 기본 매개 변수를 피하는 Pythonic 방법은 무엇입니까?
-
21-08-2019 - |
문제
때로는 빈 목록 인 기본 매개 변수가있는 것 같습니다. 아직 파이썬은 이러한 상황에서 예기치 않은 행동을 제공합니다.
예를 들어 기능이있는 경우 다음과 같습니다.
def my_func(working_list = []):
working_list.append("a")
print(working_list)
처음으로 기본값이라고 불리는 것은 작동하지만 그 후 전화는 기존 목록 (하나의 "각 호출"과 함께 업데이트 된 버전을 인쇄합니다.
그렇다면, 내가 원하는 행동을 얻는 Pythonic 방법은 무엇입니까 (각 통화의 새로운 목록)?
다른 팁
기존 답변은 이미 요청대로 직접 솔루션을 제공했습니다. 그러나 이것은 새로운 Python 프로그래머에게는 매우 일반적인 함정이므로 Python이 왜 이런 식으로 행동하는지 설명을 추가 할 가치가 있습니다.파이썬에 대한 히치하이커 가이드" 처럼 "변이 가능한 기본 인수": http://docs.python-guide.org/en/latest/writing/gotchas/
인용하다: "Python의 기본 인수는 함수가 정의 될 때 한 번 평가됩니다. 함수가 호출 될 때마다 (예 : Ruby). 이것은 돌연변이 가능한 기본 인수를 사용하고 돌연변이하면 기능에 대한 향후 모든 호출에 대해 그 객체를 돌려 놓았다는 것을 의미합니다."
구현하기위한 샘플 코드 :
def foo(element, to=None):
if to is None:
to = []
to.append(element)
return to
이 경우에는 중요하지 않지만 객체 아이덴티티를 사용하여 없음을 테스트 할 수 있습니다.
if working_list is None: working_list = []
부울 운영자가 어떻게 파이썬에서 정의되는지를 활용할 수도 있습니다.
working_list = working_list or []
발신자가 빈 목록 (거짓으로 간주 됨)을 working_list로 제공하고 자신이 준 목록을 수정할 것을 기대하면 예기치 않게 행동 할 것입니다.
기능의 의도가 있다면 수정하다 매개 변수가 전달되었습니다 working_list
, Henryr의 답변을 참조하십시오 (= 없음, 내부에 없음을 확인하십시오).
그러나 인수를 돌연변이하려고하지 않고 목록의 시작점으로 사용하면 간단히 복사 할 수 있습니다.
def myFunc(starting_list = []):
starting_list = list(starting_list)
starting_list.append("a")
print starting_list
(또는이 간단한 경우에 print starting_list + ["a"]
하지만 나는 그것이 단지 장난감 예일 것 같아요)
일반적으로, 당신의 논증을 돌리는 것은 파이썬에서 나쁜 스타일입니다. 물체를 완전히 돌연변이 할 것으로 예상되는 유일한 기능은 객체의 방법입니다. 선택적인 인수를 돌연변이하는 것은 드문 일입니다. 일부 호출에서만 발생하는 부작용은 실제로 최고의 인터페이스입니까?
"출력 인수"의 C 습관에서 그것을하면 완전히 불필요합니다. 항상 여러 값을 튜플로 반환 할 수 있습니다.
중간 목록을 구축하지 않고 긴 결과 목록을 효율적으로 구축하기 위해이 작업을 수행하면 발전기로 작성하고 사용하는 것을 고려하십시오.
result_list.extend(myFunc())
당신이 그것을 부를 때. 이렇게하면 전화 규칙은 매우 깨끗합니다.
옵션을 돌연변이하는 한 패턴 ~이다 재귀 함수의 숨겨진 "메모"arg가 자주 수행됩니다.
def depth_first_walk_graph(graph, node, _visited=None):
if _visited is None:
_visited = set() # create memo once in top-level call
if node in _visited:
return
_visited.add(node)
for neighbour in graph[node]:
depth_first_walk_graph(graph, neighbour, _visited)
나는 주제를 벗어나지 않을 수도 있지만, 당신이 가변적 인 수의 인수를 통과시키고 싶다면, pythonic 방법은 튜플을 통과하는 것입니다. *args
또는 사전 **kargs
. 이것들은 선택 사항이며 구문보다 낫습니다 myFunc([1, 2, 3])
.
튜플을 통과하려면 :
def myFunc(arg1, *args):
print args
w = []
w += args
print w
>>>myFunc(1, 2, 3, 4, 5, 6, 7)
(2, 3, 4, 5, 6, 7)
[2, 3, 4, 5, 6, 7]
사전을 통과하려면 :
def myFunc(arg1, **kargs):
print kargs
>>>myFunc(1, option1=2, option2=3)
{'option2' : 2, 'option1' : 3}
이미 좋은 답변이 제공되었습니다. 예를 들어 기본 빈 목록이있는 클래스를 만들고 싶을 때 더 아름답게 찾을 수있는 다른 구문을 작성하고 싶었습니다.
class Node(object):
def __init__(self, _id, val, parents=None, children=None):
self.id = _id
self.val = val
self.parents = parents if parents is not None else []
self.children = children if children is not None else []
이 스 니펫은 IF Operator 구문을 사용합니다. 나는 특히 콜론 등이없는 깔끔한 작은 1 라이너이기 때문에 특히 그것을 좋아하며 거의 평범한 영어 문장처럼 읽습니다. :)
당신의 경우 당신은 쓸 수 있습니다
def myFunc(working_list=None):
working_list = [] if working_list is None else working_list
working_list.append("a")
print working_list
UCSC Extension 클래스를 수강했습니다 Python for programmer
true of : def fn (data = []) :
a) 모든 통화마다 데이터 목록이 비어 있도록 좋은 아이디어입니다.
b) 호출에 인수를 제공하지 않는 함수에 대한 모든 호출이 빈 목록을 데이터로 얻을 수 있도록 좋은 생각입니다.
c) 데이터가 문자열 목록 인 한 합리적인 아이디어입니다.
d) 기본값이 데이터를 축적하고 기본값이 후속 호출에 따라 변경되기 때문에 나쁜 생각입니다.
대답:
d) 기본값이 데이터를 축적하고 기본값이 후속 호출에 따라 변경되기 때문에 나쁜 생각입니다.