可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I\'ve come across links that say Python is a strongly typed language.
However, I thought in strongly typed languages you couldn\'t do this :
bob = 1
bob = \"bob\"
I thought a strongly typed language didn\'t accept type-changing at run-time. Maybe I\'ve got a wrong (or too simplist) definition of strong/weak types.
So, is Python a strongly or weakly typed language?
回答1:
Python is strongly, dynamically typed.
- Strong typing means that the type of a value doesn\'t suddenly change. A string containing only digits doesn\'t magically become a number, as may happen in Perl. Every change of type requires an explicit conversion.
- Dynamic typing means that runtime objects (values) have a type, as opposed to static typing where variables have a type.
As for your example
bob = 1
bob = \"bob\"
This works because the variable does not have a type; it can name any object. After bob=1
, you\'ll find that type(bob)
returns int
, but after bob=\"bob\"
, it returns str
. (Note that type
is a regular function, so it evaluates its argument, then returns the type of the value.)
Contrast this with older dialects of C, which were weakly, statically typed, so that pointers and integers were pretty much interchangeable. (Modern ISO C requires conversions in many cases, but my compiler is still lenient about this by default.)
I must add that the strong vs. weak typing is more of a continuum than a boolean choice. C++ has stronger typing than C (more conversions required), but the type system can be subverted by using pointer casts.
The strength of the type system in a dynamic language such as Python is really determined by how its primitives and library functions respond to different types. E.g., +
is overloaded so that it works on two numbers or two strings, but not a string and an number. This is a design choice made when +
was implemented, but not really a necessity following from the language\'s semantics. In fact, when you overload +
on a custom type, you can make it implicitly convert anything to a number:
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
(The only language that I know that is completely strongly typed, aka strictly typed, is Haskell, where types are entirely disjoint and only a controlled form of overloading is possible via type classes.)
回答2:
There are some important issues that I think all of the existing answers have missed.
Weak typing means allowing access to the underlying representation. In C, I can create a pointer to characters, then tell the compiler I want to use it as a pointer to integers:
char sz[] = \"abcdefg\";
int *i = (int *)sz;
On a little-endian platform with 32-bit integers, this makes i
into an array of the numbers 0x64636261
and 0x00676665
. In fact, you can even cast pointers themselves to integers (of the appropriate size):
intptr_t i = (intptr_t)&sz;
And of course this means I can overwrite memory anywhere in the system.*
char *spam = (char *)0x12345678
spam[0] = 0;
* Of course modern OS\'s use virtual memory and page protection so I can only overwrite my own process\'s memory, but there\'s nothing about C itself that offers such protection, as anyone who ever coded on, say, Classic Mac OS or Win16 can tell you.
Traditional Lisp allowed similar kinds of hackery; on some platforms, double-word floats and cons cells were the same type, and you could just pass one to a function expecting the other and it would \"work\".
Most languages today aren\'t quite as weak as C and Lisp were, but many of them are still somewhat leaky. For example, any OO language that has an unchecked \"downcast\",* that\'s a type leak: you\'re essentially telling the compiler \"I know I didn\'t give you enough information to know this is safe, but I\'m pretty sure it is,\" when the whole point of a type system is that the compiler always has enough information to know what\'s safe.
* A checked downcast doesn\'t make the language\'s type system any weaker just because it moves the check to runtime. If it did, then subtype polymorphism (aka virtual or fully-dynamic function calls) would be the same violation of the type system, and I don\'t think anyone wants to say that.
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…
* You can use a function like struct.unpack
to read the bytes and build a new int out of \"how C would represent these bytes\", but that\'s obviously not leaky; even Haskell allows that.
Meanwhile, implicit conversion is really a different thing from a weak or leaky type system.
Every language, even Haskell, has functions to, say, convert an integer to a string or a float. But some languages will do some of those conversions for you automatically—e.g., in C, if you call a function that wants a float
, and you pass it in int
, it gets converted for you. This can definitely lead to bugs with, e.g., unexpected overflows, but they\'re not the same kinds of bugs you get from a weak type system. And C isn\'t really being any weaker here; you can add an int and a float in Haskell, or even concatenate a float to a string, you just have to do it more explicitly.
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.
回答3:
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.
回答4:
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
回答5:
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
回答6:
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\'
回答7:
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.
回答8:
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.
回答9:
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
}
回答10:
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...