Python이 잘못된 인수 개수로 함수 호출을 허용하는 이유는 무엇입니까?


80

Python은 저의 첫 번째 동적 언어입니다. 최근에 잘못된 수의 인수를 잘못 제공하는 함수 호출을 코딩했습니다. 함수가 호출되었을 때 예외로 인해 실패했습니다. 동적 언어에서도 소스 파일을 구문 분석 할 때 이러한 종류의 오류가 감지 될 수있을 것으로 예상했습니다.

동일한 변수가 다른 시간에 모든 유형의 값을 포함 할 수 있기 때문에 함수가 호출 될 때까지 실제 인수 의 유형 을 알 수 없다는 것을 이해합니다 . 그러나 인수 의 는 소스 파일이 구문 분석되는 즉시 알려집니다. 프로그램이 실행되는 동안에는 변경되지 않습니다.

그래서 이것은 철학적 인 질문이 아닙니다.

이것을 Stack Overflow의 범위로 유지하기 위해 다음과 같은 질문을 표현하겠습니다. 코드가 실제로 실행될 때까지 함수 호출에서 인수 수 확인을 지연해야하는 Python이 제공하는 기능이 있습니까?


17
이름이 런타임에 완전히 다른 함수를 참조하면 어떻게됩니까?
jonrsharpe

반론으로, 호출 f(*args)을 위한 인수의 수는 구문 분석 단계에서 알 수 없습니다.
Łukasz Rogalski

3
유형 이론에서 함수의 경우 값의 유형에는 인수의 수가 포함됩니다.
PyRulez

9
실제로 호출을 시도 할 때까지 호출 할 함수를 파이썬은 어떻게 알 수 있습니까? 파이썬의 함수에 이름이있는 것과는 다릅니다. (비꼬는 것이 아님)
user253751

1
@immibis : 글쎄요. 그들은 이름이 있습니다. 그러나 그들은 그 이름에 특별히 붙어 있지 않습니다 . def foo(): whateverhas로 정의 된 함수 foo.__name__ == 'foo'이지만 그렇다고해서 foo = some_other_function또는 bar = foo.
user2357112 모니카 지원

답변:


146

파이썬은 어떤 객체를 호출하게 될지 미리 알 수 없습니다. 왜냐하면 동적이기 때문에 함수 객체를 교체 할 수 있기 때문 입니다. 언제든지. 그리고 이러한 각 객체는 서로 다른 수의 인수를 가질 수 있습니다.

다음은 극단적 인 예입니다.

import random

def foo(): pass
def bar(arg1): pass
def baz(arg1, arg2): pass

the_function = random.choice([foo, bar, baz])
print(the_function())

위의 코드는 예외가 발생할 확률이 3 분의 2입니다. 하지만 파이썬은 그것이 사실인지 아닌지 선험적을 알 수 없습니다!

그리고 동적 모듈 가져 오기, 동적 함수 생성, 기타 호출 가능한 개체 ( __call__메서드가있는 모든 개체를 호출 할 수 있음) 또는 모든 인수 ( *args**kwargs)를 시작하지 않았습니다 .

그러나이를 더욱 명확하게하기 위해 질문에 다음과 같이 진술합니다.

프로그램이 실행되는 동안에는 변경되지 않습니다.

파이썬이 아니라 모듈이로드되면 함수 객체를 포함하여 모듈 네임 스페이스의 모든 객체를 삭제, 추가 또는 교체 할 수 있습니다.


가되지 않을 수도 있습니다, 그래서 내가 전에 함수 테이블을 본 적이 악 있도록. 아 잠깐, 테이블의 함수는 *인수를 사용하지 않습니다 .... 그리고 이것은 파이썬 이므로 .... 네, 꽤 극단적입니다.
Ray Toal

3
이제 티셔츠입니다. (만약이 속성을 추가하는 방법을 알아낼 수 당신이 그것을 원하는 경우에, 저에게, 나는 아마 그것을 알아낼 수 있습니다..)
PyRulez

@PyRulez : 정규식 구문 분석 게시물유니콘 모양 사본이있는 티셔츠가 URL을 사용합니다. 추가 https://stackoverflow.com/a/34567789하고 끝낼 수 있습니다.
Martijn Pieters

4
@PyRulez :하지만 이것은 단지 디스패치 목록 일뿐입니다. 점은 당신이 개체로 기능을 사용할 수 있음을 설명하기 위해, 당신은 하나라고 앞을 알 수 없다. 그렇지 않으면 합리적으로 일반적인 기술 입니다.
Martijn Pieters

사용자가 원래 문제를 해결하는 데 도움이 될 수 있습니다. 코드가 실행되기 전에 실수를 감지하면 정적 검증 도구의 사용을 언급 할 수 있습니다.
Xavier Combelle

35

전달되는 인수의 수는 알려져 있지만 실제로 호출되는 함수는 알려져 있지 않습니다. 이 예를 참조하십시오.

def foo():
    print("I take no arguments.")

def bar():
    print("I call foo")
    foo()

이것은 분명해 보일 수 있지만 "fubar.py"라는 파일에 넣어 보겠습니다. 이제 대화 형 Python 세션에서 다음을 수행합니다.

>>> import fubar
>>> fubar.foo()
I take no arguments.
>>> fubar.bar()
I call foo
I take no arguments.

그것은 분명했습니다. 이제 재미있는 부분입니다. 0이 아닌 양의 인수가 필요한 함수를 정의합니다.

>>> def notfoo(a):
...    print("I take arguments!")
...

이제 우리는 원숭이 패치 라고하는 것을 합니다. 실제로 모듈 에서 함수 를 대체 할 수 있습니다 .foofubar

>>> fubar.foo = notfoo

이제 우리가를 호출 할 때 bar, a TypeError가 발생합니다. foo이제 이름 은 이전에 알려진 원래 함수 대신 위에서 정의한 함수를 참조합니다 foo.

>>> fubar.bar()
I call foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/horazont/tmp/fubar.py", line 6, in bar
    foo()
TypeError: notfoo() missing 1 required positional argument: 'a'

따라서 이와 같은 상황에서도 호출 된 함수 foo가 인수를 취하지 않는다는 것이 매우 명백해 보일 수 있지만 , Python foo은 해당 소스 행을 실행할 때 실제로 호출되는 함수 임을 알 수만 있습니다 .

이것은 Python의 속성으로 강력하게 만들지 만 속도가 느려집니다. 사실, 성능 향상을 위해 모듈을 읽기 전용으로 만드는 것은 얼마 전에 python-ideas 메일 링리스트 에서 논의 되었지만 실제 지원을 얻지 못했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.