In Python, suppose one wants to test whether the variable x is a reference to a list object. Is there a difference between if type(x) is list: and if type(x) == list:? This is how I understand it. (Please correct me if I am wrong)
type(x) is listtests whether the expressionstype(x)andlistevaluate to the same object andtype(x) == listtests whether the two objects have equivalent (in some sense) values.type(x) == listshould evaluate toTrueas long asxis a list. But cantype(x)evaluate to a different object from whatlistrefers to?
What exactly does the expression list evaluate to? (I am new to Python, coming from C++, and still can't quite wrap my head around the notion that types are also objects.) Does list point to somewhere in memory? What data live there?
The "one obvious way" to do it, that will preserve the spirit of "duck typing" is
isinstance(x, list). Rather, in most cases, one's code won't be specific to a list, but could work with any sequence (or maybe it needs a mutable sequence). So the recomendation is actually:Now, going into your specific questions:
listin Python points to a class. A class that can be inherited, extended, etc...and thanks to a design choice of Python, the syntax for creating an instance of a class is indistinguishable from calling a function. So, when teaching Python to novices, one could just casually mention thatlistis a "function" (I prefer not, since it is straightout false - the generic term for both functions and classes in regards to that they can be "called" and will return a result iscallable)Being a class,
listdoes live in a specific place in memory - the "where" does not make any difference when coding in Python - but yes, there is one single place in memory where a class, which in Python is also an object, an instance oftype, exists as a data structure with pointers to the various methods that one can use in a Python list.As for:
That is correct:
isis a special operator that unlike others cannot be overriden for any class and checks for object itentity - in the cPython implementation, it checks if both operands are at the same memory address (but keep in mind that that address, though visible through the built-in functionid, behaves as if it is opaque from Python code). As for the "sense" in which objects are "equal" in Python: one can always override the behavior of the==operator for a given object, by creating the special named method__eq__in its class. (The same is true for each other operator - the language data model lists all available "magic" methods). For lists, the implemented default comparison automatically compares each element recursively (calling the.__eq__method for each item pair in both lists, if they have the same size to start with, of course)Not if "x" is a list proper: type(x) will always evaluate to
list. But==would fail if x were an instance of a subclass oflist, or another Sequence implementation: that is why it is always better to compare classes using the builtinsisinstanceandissubclass.