[python] 파이썬은 강하게 타이핑됩니까?

파이썬은 강력한 유형의 언어라는 링크를 발견했습니다.

그러나 나는 당신이 할 수없는 강력한 유형의 언어로 생각했습니다 :

bob = 1
bob = "bob"

강력한 형식의 언어가 런타임에 형식 변경을 허용하지 않는다고 생각했습니다. 어쩌면 나는 강하거나 약한 유형에 대한 잘못된 (또는 너무 단순한) 정의를 얻었을 것입니다.

그렇다면 파이썬은 강력하거나 약한 유형의 언어입니까?



답변

파이썬은 강력하고 역동적으로 타이핑됩니다.

  • 강력한 타이핑은 값의 유형이 예기치 않은 방식으로 변경되지 않음을 의미합니다. Perl에서와 같이 숫자 만 포함 된 문자열은 마술처럼 숫자가되지 않습니다. 모든 유형의 변경에는 명시적인 변환이 필요합니다.
  • 동적 유형 지정은 변수에 유형이있는 정적 유형 지정과 달리 런타임 객체 (값)에 유형이 있음을 의미합니다.

당신의 예는

bob = 1
bob = "bob"

변수에 유형이 없기 때문에 작동합니다. 모든 개체의 이름을 지정할 수 있습니다. 이후 bob=1에는을 type(bob)반환 int하지만 이후 bob="bob"에는을 반환합니다 str. ( type이것은 일반 함수이므로 인수를 평가 한 다음 값의 유형을 반환합니다.)

이것을 약하고 정적으로 타이핑 한 C의 오래된 방언과는 대조적으로, 포인터와 정수는 거의 상호 교환 가능합니다. (현대 ISO C는 대부분의 경우 변환이 필요하지만 기본적으로 컴파일러는 여전히 관대합니다.)

강력한 타이핑과 약한 타이핑은 부울 선택보다 연속체라고 덧붙여 야합니다. C ++는 C보다 타이핑이 더 강력하지만 (더 많은 변환이 필요함) 포인터 캐스트를 사용하여 유형 시스템을 전복시킬 수 있습니다.

파이썬과 같은 동적 언어에서 형식 시스템의 강점은 기본 형식과 라이브러리 함수가 다른 형식에 어떻게 반응하는지에 따라 결정됩니다. 예를 들어 +오버로드되어 두 개의 숫자 또는 두 개의 문자열에서 작동하지만 문자열과 숫자는 작동 하지 않습니다. 이것은 +구현 되었을 때 만들어진 디자인 선택 이지만 언어의 의미론을 따라야 할 필요는 없습니다. 실제로 +사용자 정의 유형에 과부하가 걸리면 암시 적으로 모든 것을 숫자로 변환 할 수 있습니다.

def to_number(x):
    """Try to convert function argument to float-type object."""
    try: 
        return float(x) 
    except (TypeError, ValueError): 
        return 0 

class Foo:
    def __init__(self, number): 
        self.number = number

    def __add__(self, other):
        return self.number + to_number(other)

클래스의 인스턴스 Foo를 다른 객체에 추가 할 수 있습니다.

>>> a = Foo(42)
>>> a + "1"
43.0
>>> a + Foo
42
>>> a + 1
43.0
>>> a + None
42

비록 강력한 형식의 파이썬 유형의 개체 추가 완전히 괜찮 것을 관찰 intfloat반환 형식의 개체 float(예를 들어, int(42) + float(1)반환 43.0). 반면에 Haskell 유형의 불일치로 인해 다음을 시도하면 불평 할 것 (42 :: Integer) + (1 :: Float)입니다. 이로 인해 Haskell은 엄격하게 형식화 된 언어이며 형식이 완전히 분리되어 있고 형식 클래스를 통해 제어되는 오버로드 형식 만 가능합니다.


답변

기존의 모든 답변을 놓친 것으로 생각되는 중요한 문제가 있습니다.


타이핑이 약하다는 것은 기본 표현에 대한 액세스를 허용한다는 의미입니다. C에서는 문자에 대한 포인터를 만든 다음 정수에 대한 포인터로 사용하고 싶다고 컴파일러에 알릴 수 있습니다.

char sz[] = "abcdefg";
int *i = (int *)sz;

32 비트 정수를 가진 리틀 엔디안 플랫폼 i에서는 숫자 0x64636261와 의 배열이 0x00676665됩니다. 실제로 포인터 자체를 적절한 크기의 정수로 캐스트 할 수도 있습니다.

intptr_t i = (intptr_t)&sz;

물론 이것은 시스템의 어느 곳에서나 메모리를 덮어 쓸 수 있음을 의미합니다. *

char *spam = (char *)0x12345678
spam[0] = 0;

물론 현대 OS는 가상 메모리와 페이지 보호를 사용하므로 내 프로세스의 메모리를 덮어 쓸 수 있지만 C와 관련하여 Classic Mac OS 또는 Win16으로 코딩 한 사람이 말할 수있는 것과 같은 보호 기능을 제공하는 것은 없습니다.

전통적인 리스프는 비슷한 종류의 해커를 허용했다. 일부 플랫폼에서는 더블 워드 부동 소수점과 죄수 셀이 동일한 유형이며, 다른 하나를 기대하는 함수에 하나만 전달하면 “작동”할 수 있습니다.

오늘날 대부분의 언어는 C와 Lisp만큼 약하지는 않지만 여전히 많은 언어가 유출되어 있습니다. 예를 들어, 확인되지 않은 “다운 캐스트”가있는 OO 언어 *는 유형 누출입니다. 본질적으로 컴파일러에게 “이것이 안전하다는 것을 알 수있는 충분한 정보를주지 않았다는 것을 알고 있습니다. 형식 시스템의 요점은 컴파일러가 항상 안전한 정보를 알기에 충분한 정보를 가지고 있다는 것입니다.

* 체크 다운 캐스트는 체크를 런타임으로 옮기기 때문에 언어 유형 시스템을 더 약하게 만들지 않습니다. 그렇다면 하위 유형 다형성 (일명 가상 또는 완전 동적 함수 호출)은 유형 시스템을 위반하는 것과 같으며 아무도 그렇게 말하고 싶지 않다고 생각합니다.

이런 의미에서 “스크립팅”언어는 거의 없습니다. Perl 또는 Tcl에서도 문자열을 가져 와서 바이트를 정수로 해석 할 수는 없습니다. * CPython (및 다른 언어의 많은 다른 인터프리터의 경우)에서도 실제로 지속되는 경우 주목할 가치가 있습니다. 사용할 수있는 ctypes최대로드 libpython, 객체의 캐스팅 idA를 POINTER(Py_Object)하고, 누출 타입 시스템을 강제로. 이것이 유형 시스템을 약하게 만들지 여부는 사용 사례에 따라 다릅니다. 보안을 위해 언어 내 제한 실행 샌드 박스를 구현하려는 경우 이러한 종류의 이스케이프를 처리해야합니다.

* struct.unpack바이트를 읽는 것과 같은 함수를 사용하여 “C가 이러한 바이트를 나타내는 방법”에서 새로운 int를 빌드 할 수 있지만 분명히 누출되지는 않습니다. Haskell조차도 가능합니다.


한편, 암시 적 변환은 실제로 약하거나 새는 유형의 시스템과는 다릅니다.

Haskell조차도 모든 언어에는 정수를 문자열이나 부동 소수점으로 변환하는 기능이 있습니다. 그러나 일부 언어는 자동으로 이러한 변환 중 일부를 자동으로 수행합니다. 예를 들어 C에서 a를 원하는 함수를 호출하고이 함수를 float전달 int하면 변환됩니다. 이것은 예기치 않은 오버플로와 같은 버그로 이어질 수 있지만 약한 유형의 시스템에서 얻는 것과 같은 종류의 버그는 아닙니다. 그리고 C는 실제로 약해지지 않습니다. Haskell에 int와 float를 추가하거나 float를 문자열에 연결할 수도 있습니다. 더 명확하게 수행하면됩니다.

그리고 역동적 인 언어의 경우 이것은 매우 어둡습니다. 파이썬이나 펄에서 “float을 원하는 함수”와 같은 것은 없습니다. 그러나 유형이 다른 여러 가지 기능을 수행하는 오버로드 된 함수가 있으며, 문자열을 다른 것에 추가하는 것이 “문자열을 원하는 함수”라는 강력한 직관적 의미가 있습니다. 그런 의미에서, 펄,은 Tcl, 자바 스크립트는 암시 적 변환 (을 많이 할 표시 "a" + 1를 제공 "a1"파이썬은 많은 적은 않지만 (,) "a" + 1예외가 발생하지만, 1.0 + 1당신이 줄 않습니다 2.0*). +인덱싱과 같은 다른 기능이있을 때 문자열과 int를 사용 하는 것이 없는 이유는 무엇입니까?

* 실제로 현대 파이썬에서는 OO 하위 유형 지정으로 설명 할 수 있습니다 isinstance(2, numbers.Real). 2Perl 또는 JavaScript에서 문자열 유형의 인스턴스가 어떤 의미인지는 생각하지 않습니다 … 비록 Tcl에서는 모든 것이 문자열의 인스턴스 이기 때문에 실제로입니다 .


마지막으로 “strong”과 “weak”입력에 대한 완전히 직교적인 또 다른 정의가 있습니다. 여기서 “strong”은 강력 / 유연성 / 표현을 의미합니다.

예를 들어 Haskell을 사용하면 숫자, 문자열,이 유형의 목록 또는 문자열에서이 유형으로의 맵인 유형을 정의 할 수 있습니다. 이는 JSON에서 디코딩 할 수있는 모든 것을 완벽하게 나타내는 방법입니다. Java에서 이러한 유형을 정의 할 방법이 없습니다. 그러나 최소한 Java에는 파라 메트릭 (일반) 유형이 있으므로 T 목록을 사용하고 요소가 T 유형임을 알고있는 함수를 작성할 수 있습니다. 초기 Java와 같은 다른 언어에서는 객체 목록과 다운 캐스트를 사용해야했습니다. 그러나 최소한 Java를 사용하면 자체 메소드를 사용하여 새 유형을 작성할 수 있습니다. C 만 구조를 만들 수 있습니다. 그리고 BCPL에는 그조차 없었습니다. 그리고 유일한 유형은 비트 길이가 다른 어셈블리입니다.

따라서 하스켈의 유형 시스템은 현대의 Java보다 강력하며, 이는 이전의 Java보다 강력하며, C보다 강력하며 BCPL보다 강력합니다.

그렇다면 파이썬은 그 스펙트럼에서 어디에 적합합니까? 조금 까다 롭습니다. 대부분의 경우 오리 타이핑을 사용하면 Haskell에서 할 수있는 모든 작업과 할 수없는 일을 시뮬레이션 할 수 있습니다. 물론 컴파일 타임 대신 런타임시 오류가 발생하지만 여전히 발생합니다. 그러나 오리 타이핑이 충분하지 않은 경우가 있습니다. 예를 들어, Haskell에서 빈 ints 목록은 int 목록이라고 말할 수 있으므로 +해당 목록 을 줄이면 0 *이 반환 되도록 결정할 수 있습니다 . 파이썬에서 빈 목록은 빈 목록입니다. 축소 할 작업을 결정하는 데 도움이되는 유형 정보 +는 없습니다.

* 사실, Haskell은 이것을 허용하지 않습니다. 빈 목록에서 시작 값을 갖지 않는 reduce 함수를 호출하면 오류가 발생합니다. 그러나 유형 시스템은 이 작업을 수행 할 있을만큼 강력하지만 Python은 그렇지 않습니다.


답변

‘strongly typed’‘dynamically typed’를 혼동하고 있습니다.

1string을 추가 하여 유형을 변경할 수는 없지만 '12'변수에 저장할 유형을 선택하고 프로그램 런타임 중에 유형을 변경할 수 있습니다.

동적 타이핑의 반대는 정적 타이핑입니다. 변수 유형선언은 프로그램 수명 동안 변경되지 않습니다. 강력한 타이핑의 반대는 약한 타이핑입니다. 의 유형은 프로그램 수명 동안 변경 될 수 있습니다.


답변

위키 기사 에 따르면 파이썬은 동적이고 강력하게 유형화되어 있습니다 (좋은 설명도 제공합니다).

아마도 프로그램 실행 중에 유형을 변경할 수없고 컴파일 시간 동안 유형 검사가 발생하여 가능한 오류를 감지하는 정적 유형 언어 에 대해 생각하고있을 것 입니다.

이 SO 질문은 흥미로울 수 있습니다. 동적 유형 언어와 정적 유형 언어유형 시스템 에 관한이 Wikipedia 기사 는 자세한 정보를 제공합니다.


답변

TLDR;

파이썬의 타이핑은 동적 이므로 문자열 변수를 int로 변경할 수 있습니다

x = 'somestring'
x = 50

파이썬 타이핑은 강력 하므로 유형을 병합 할 수 없습니다 :

'foo' + 3 --> TypeError: cannot concatenate 'str' and 'int' objects

약한 유형의 Javascript에서 이것은 발생합니다 …

 'foo'+3 = 'foo3'

타입 추론에 대하여

Java는 객체 유형을 명시 적으로 선언하도록합니다.

int x = 50

코 틀린 은 추론을 사용하여int

x = 50

그러나 두 언어 모두 정적 유형을 사용하므로에서 언어를 x변경할 수 없습니다 int. 어느 언어도 다음과 같은 동적 변경을 허용하지 않습니다.

x = 50
x = 'now a string'


답변

이미 몇 번 대답되었지만 파이썬은 강력한 유형의 언어입니다.

>>> x = 3
>>> y = '4'
>>> print(x+y)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

JavaScript에서 다음은

var x = 3
var y = '4'
alert(x + y) //Produces "34"

그것은 약한 타이핑과 강한 타이핑의 차이점입니다. 약한 유형은 컨텍스트 (예 : Perl)에 따라 자동으로 한 유형에서 다른 유형으로 변환하려고합니다. 강력한 유형은 절대로 암시 적으로 변환 되지 않습니다 .

혼란은 파이썬이 값을 이름에 묶는 방법에 대한 오해에 있습니다 (일반적으로 변수라고 함).

파이썬에서는 이름에 유형이 없으므로 다음과 같은 작업을 수행 할 수 있습니다.

bob = 1
bob = "bob"
bob = "An Ex-Parrot!"

이름은 무엇이든 바인딩 할 수 있습니다.

>>> def spam():
...     print("Spam, spam, spam, spam")
...
>>> spam_on_eggs = spam
>>> spam_on_eggs()
Spam, spam, spam, spam

더 읽을 거리 :

https://ko.wikipedia.org/wiki/Dynamic_dispatch

약간 관련이 있지만 고급입니다.

http://effbot.org/zone/call-by-object.htm


답변

Python 변수는 값을 나타내는 대상 객체에 대한 형식화되지 않은 참조를 저장합니다.

모든 할당 작업은 유형이 지정되지 않은 참조를 할당 된 객체에 할당하는 것을 의미합니다. 즉, 객체는 원본 및 새로운 (계산 된) 참조를 통해 공유됩니다.

값 유형은 참조 값이 아닌 대상 객체에 바인딩됩니다. 값이있는 작업이 수행되면 (런타임) (강한) 유형 검사가 수행됩니다.

다시 말해, 변수 (기술적으로)에는 유형이 없습니다. 변수 유형에 대해 정확하게 생각하고 싶다면 생각하는 것이 합리적이지 않습니다. 그러나 참조는 자동으로 역 참조되며 실제로 대상 객체의 유형으로 생각합니다.