답변:
파이썬은 강력하고 역동적으로 타이핑됩니다.
당신의 예는
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
비록 강력한 형식의 파이썬 유형의 개체 추가 완전히 괜찮 것을 관찰 int
및 float
반환 형식의 개체 float
(예를 들어, int(42) + float(1)
반환 43.0
). 반면에 Haskell 유형의 불일치로 인해 다음을 시도하면 불평 할 것 (42 :: Integer) + (1 :: Float)
입니다. 이로 인해 Haskell은 엄격하게 형식화 된 언어이며 형식이 완전히 분리되어 있고 형식 클래스를 통해 제어되는 오버로드 형식 만 가능합니다.
True
또는 로 변환되는 것이 없기 때문에 반례가 아닙니다 False
. 그러나 숫자 승진은 어떻습니까? 1.0 + 2
비록 Perl 또는 C에서와 마찬가지로 Python에서도 잘 작동합니다 "1.0" + 2
. @jbrendel에 동의합니다. 이것은 실제로 암시 적 변환이 아니라 오버로드 일뿐입니다. 그러나 같은 의미에서 Perl도 암시 적 변환을 수행하지 않습니다. 함수가 매개 변수 유형을 선언하지 않은 경우 암시 적 변환이 발생하지 않습니다.
if isValid(value) - 1
누출 될 수 있습니다. 부울은 정수로 강제 변환되며,이 값은 진리 값으로 평가됩니다. False - 1
진실이되고 거짓 True - 1
이되어 디버그하기 어려운 2 계층 오류가 발생합니다. 이런 의미에서 파이썬은 대부분 강력하게 타이핑됩니다. 유형 강제는 일반적으로 논리적 오류를 유발하지 않습니다.
기존의 모든 답변을 놓친 것으로 생각되는 중요한 문제가 있습니다.
타이핑이 약하다는 것은 기본 표현에 대한 액세스를 허용한다는 의미입니다. 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
, 객체의 캐스팅 id
A를 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)
. 2
Perl 또는 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은 그렇지 않습니다.
char sz[]
char에 대한 포인터가 아니며 char의 배열이며 할당에서 포인터로 부패합니다.
'strongly typed' 와 'dynamically typed'를 혼동하고 있습니다.
1
string을 추가 하여 유형을 변경할 수는 없지만 '12'
변수에 저장할 유형을 선택하고 프로그램 런타임 중에 유형을 변경할 수 있습니다.
동적 타이핑의 반대는 정적 타이핑입니다. 변수 유형 의 선언은 프로그램 수명 동안 변경되지 않습니다. 강력한 타이핑의 반대는 약한 타이핑입니다. 값 의 유형은 프로그램 수명 동안 변경 될 수 있습니다.
파이썬의 타이핑은 동적 이므로 문자열 변수를 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
할 수 operator+
있습니까?
이미 몇 번 대답되었지만 파이썬은 강력한 유형의 언어입니다.
>>> 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
약간 관련이 있지만 고급입니다.
"3"*4
파이썬에서도 할 수 있습니다 . 물론 결과는 "3333"
입니다. 어느 쪽이든 변환하고 있다고 말하지 않을 것입니다. 물론 그것은 의미론을 주장하는 것일 수 있습니다.
float
의 조합 밖으로 float
와 int
는 암시 적으로 형식을 변환 있다고. float과 int 사이에는 자연스런 관계가 있으며 실제로 계층 구조 유형이 이를 설명합니다. 파이썬 이 잘 정의 된 것과 동일한 방식으로 Javascript가 고려 '3'+4
하고 'e'+4
잘 정의 된 작업 이라고 주장 할 수 있다고 생각 3.0 + 4
하지만, 그 시점에는 강력하거나 약한 유형과 같은 것이 없습니다. 작업.
Python 변수는 값을 나타내는 대상 객체에 대한 형식화되지 않은 참조를 저장합니다.
모든 할당 작업은 유형이 지정되지 않은 참조를 할당 된 객체에 할당하는 것을 의미합니다. 즉, 객체는 원본 및 새로운 (계산 된) 참조를 통해 공유됩니다.
값 유형은 참조 값이 아닌 대상 객체에 바인딩됩니다. 값이있는 작업이 수행되면 (런타임) (강한) 유형 검사가 수행됩니다.
다시 말해, 변수 (기술적으로)에는 유형이 없습니다. 변수 유형에 대해 정확하게 생각하고 싶다면 생각하는 것이 합리적이지 않습니다. 그러나 참조는 자동으로 역 참조되며 실제로 대상 객체의 유형으로 생각합니다.
"강력한 입력"이라는 용어에는 명확한 정의가 없습니다.
그러므로이 용어의 사용은 당신이 말하는 사람에 따라 다릅니다.
변수 유형이 명시 적으로 선언되거나 정적으로 유형이 지정되지 않은 언어는 고려하지 않습니다.
강력한 타이핑은 변환을 방해하지 않습니다 (예 : 정수에서 문자열로 "자동으로"변환). 할당을 배제합니다 (예 : 변수 유형 변경).
다음 코드가 컴파일 (해석)되면 언어가 강력하지 않습니다.
Foo = 1 Foo = "1"
강력한 형식의 언어에서 프로그래머는 형식을 "의지"할 수 있습니다.
예를 들어, 프로그래머가 선언을 보면
UINT64 kZarkCount;
그리고 20 줄 후에도 kZarkCount는 중간 코드를 검사하지 않고도 (같은 블록에서 발생하는 한) 여전히 UINT64라는 것을 알고 있습니다.
이 간단한 예제는 강력한 타이핑과 동적 타이핑의 차이점을 설명해야한다고 생각합니다.
>>> tup = ('1', 1, .1)
>>> for item in tup:
... type(item)
...
<type 'str'>
<type 'int'>
<type 'float'>
>>>
자바:
public static void main(String[] args) {
int i = 1;
i = "1"; //will be error
i = '0.1'; // will be error
}
class testme(object):
''' A test object '''
def __init__(self):
self.y = 0
def f(aTestMe1, aTestMe2):
return aTestMe1.y + aTestMe2.y
c = testme #get a variable to the class
c.x = 10 #add an attribute x inital value 10
c.y = 4 #change the default attribute value of y to 4
t = testme() # declare t to be an instance object of testme
r = testme() # declare r to be an instance object of testme
t.y = 6 # set t.y to a number
r.y = 7 # set r.y to a number
print(f(r,t)) # call function designed to operate on testme objects
r.y = "I am r.y" # redefine r.y to be a string
print(f(r,t)) #POW!!!! not good....
위의 내용은 장기간에 걸쳐 큰 시스템에서 유지 관리 불가능한 코드의 악몽을 만듭니다. 원하는 것을 호출하지만 변수 유형을 "동적으로"변경하는 기능은 나쁜 생각입니다.