IT story

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

hot-time 2020. 4. 29. 08:12
반응형

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


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

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

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 x to a number."""
    if x is None:
        return 0
    # more special cases here
    else:
        return float(x)  # works for numbers and strings

class Foo(object):
    def __add__(self, other):
        other = to_number(other)
        # now do the addition

(완전히 타이핑 된 완전히 강하게 타이핑 된 언어는 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 언어 *는 유형 누출입니다. 본질적으로 컴파일러에게 "이것이 안전하다는 것을 알 수있는 충분한 정보를주지 않았다는 것을 알고 있습니다. 형식 시스템의 요점은 컴파일러가 항상 안전한 정보를 알기에 충분한 정보를 가지고 있다는 것입니다.

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

Very few "scripting" languages are weak in this sense. Even in Perl or Tcl, you can't take a string and just interpret its bytes as an integer.* But it's worth noting that in CPython (and similarly for many other interpreters for many languages), if you're really persistent, you can use ctypes to load up libpython, cast an object's id to a POINTER(Py_Object), and force the type system to leak. Whether this makes the type system weak or not depends on your use cases—if you're trying to implement an in-language restricted execution sandbox to ensure security, you do have to deal with these kinds of escapes…

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


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

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

And with dynamic languages, this is pretty murky. There's no such thing as "a function that wants a float" in Python or Perl. But there are overloaded functions that do different things with different types, and there's a strong intuitive sense that, e.g., adding a string to something else is "a function that wants a string". In that sense, Perl, Tcl, and JavaScript appear to do a lot of implicit conversions ("a" + 1 gives you "a1"), while Python does a lot fewer ("a" + 1 raises an exception, but 1.0 + 1 does give you 2.0*). It's just hard to put that sense into formal terms—why shouldn't there be a + that takes a string and an int, when there are obviously other functions, like indexing, that do?

* Actually, in modern Python, that can be explained in terms of OO subtyping, since isinstance(2, numbers.Real) is true. I don't think there's any sense in which 2 is an instance of the string type in Perl or JavaScript… although in Tcl, it actually is, since everything is an instance of string.


Finally, there's another, completely orthogonal, definition of "strong" vs. "weak" typing, where "strong" means powerful/flexible/expressive.

For example, Haskell lets you define a type that's a number, a string, a list of this type, or a map from strings to this type, which is a perfectly way to represent anything that can be decoded from JSON. There's no way to define such a type in Java. But at least Java has parametric (generic) types, so you can write a function that takes a List of T and know that the elements are of type T; other languages, like early Java, forced you to use a List of Object and downcast. But at least Java lets you create new types with their own methods; C only lets you create structures. And BCPL didn't even have that. And so on down to assembly, where the only types are different bit lengths.

So, in that sense, Haskell's type system is stronger than modern Java's, which is stronger than earlier Java's, which is stronger than C's, which is stronger than BCPL's.

So, where does Python fit into that spectrum? That's a bit tricky. In many cases, duck typing allows you to simulate everything you can do in Haskell, and even some things you can't; sure, errors are caught at runtime instead of compile time, but they're still caught. However, there are cases where duck typing isn't sufficient. For example, in Haskell, you can tell that an empty list of ints is a list of ints, so you can decide that reducing + over that list should return 0*; in Python, an empty list is an empty list; there's no type information to help you decide what reducing + over it should do.

* In fact, Haskell doesn't let you do this; if you call the reduce function that doesn't take a start value on an empty list, you get an error. But its type system is powerful enough that you could make this work, and Python's isn't.


You are confusing 'strongly typed' with 'dynamically typed'.

I cannot change the type of 1 by adding the string '12', but I can choose what types I store in a variable and change that during the program's run time.

The opposite of dynamic typing is static typing; the declaration of variable types doesn't change during the lifetime of a program. The opposite of strong typing is weak typing; the type of values can change during the lifetime of a program.


According to this wiki Python article Python is both dynamically and strongly typed (provides a good explanation too).

Perhaps you are thinking about statically typed languages where types can not change during program execution and type checking occurs during compile time to detect possible errors.

This SO question might be of interest: Dynamic type languages versus static type languages and this Wikipedia article on Type Systems provides more information


TLDR;

Python's typing is Dynamic so you can change an int variable to a string

x = 'somestring'
x = 50

Python typing is Strong so you can't merge types:

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

In weakly-typed Javascript this happens...

 'x'+3 = 'x3'

Regarding Type Inference

Java forces you to explicitly declare your object types

int x = 50

Kotlin uses inference to realize it's an int

x = 50

But because both languages use static types, x can't be changed from an int. Neither language would allow a dynamic change like

x = 50
x = 'now a string'

It's already been answered a few times, but Python is a strongly typed language:

>>> 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'

The following in JavaScript:

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

That's the difference between weak typing and strong typing. Weak types automatically try to convert from one type to another, depending on context (e.g. Perl). Strong types never convert implicitly.

Your confusion lies in a misunderstanding of how Python binds values to names (commonly referred to as variables).

In Python, names have no types, so you can do things like:

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

And names can be bound to anything:

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

For further reading:

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

and the slightly related but more advanced:

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


A Python variable stores an untyped reference to the target object that represent the value.

Any assignment operation means assigning the untyped reference to the assigned object -- i.e. the object is shared via the original and the new (counted) references.

The value type is bound to the target object, not to the reference value. The (strong) type checking is done when an operation with the value is performed (run time).

In other words, variables (technically) have no type -- it does not make sense to think in terms of a variable type if one wants to be exact. But references are automatically dereferenced and we actually think in terms of the type of the target object.


The term "strong typing" does not have a definite definition.

Therefore, the use of the term depends on with whom you're speaking.

I do not consider any language, in which the type of a variable is not either explicitly declared, or statically typed to be strongly typed.

Strong typing doesn't just preclude conversion (for example, "automatically" converting from an integer to a string). It precludes assignment (i.e., changing the type of a variable).

If the following code compiles (interprets), the language is not strong-typed:

Foo = 1 Foo = "1"

In a strongly typed language, a programmer can "count on" a type.

For example, if a programmer sees the declaration,

UINT64 kZarkCount;

and he or she knows that 20 lines later, kZarkCount is still a UINT64 (as long as it occurs in the same block) - without having to examine intervening code.


I just discovered a superb concise way to memorize it:

Dynamic/static typed experssion; strongly/weakly typed value.


i think, this simple example should you explain the diffs between strong and dynamic typing:

>>> tup = ('1', 1, .1)
>>> for item in tup:
...     type(item)
...
<type 'str'>
<type 'int'>
<type 'float'>
>>>

java:

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....

The above would create a nightmare of unmaintainable code in a large system over a long period time. Call it what you want, but the ability to "dynamically" change a variables type is just a bad idea...

참고URL : https://stackoverflow.com/questions/11328920/is-python-strongly-typed

반응형