Type of an instance variable - python

Suppose that I have a class like this
class Employee:
pass
I create two objects for Employee as below
john = Employee()
rob = Employee()
..and create instance variables
john.age = 12
rob.age = '15'
The compiler accepts both and prints the age (john's age in int and rob's age in string). How is this logical? The same data attribute having different type in each object.
Thanks.

Be sure to understand this fundamental principle: in Python, variables don't have types. Values have types. This is the essence of Python's being a dynamically-typed language similarly to Lisp and Javascript, but unlike C, C++ and Java.
>>> foo = 5 # foo now holds a value of type int
>>> foo = 'hello' # foo now holds a value of type string
Here's an excerpt from Wikipedia's entry on typing in Python:
Python uses duck typing and has typed
objects but untyped variable names.
Type constraints are not checked at
compile time; rather, operations on an
object may fail, signifying that the
given object is not of a suitable
type. Despite being dynamically typed,
Python is strongly typed, forbidding
operations that are not well-defined
(for example, adding a number to a
string) rather than silently
attempting to make sense of them.
Do read more on this subject (especially what Duck Typing is) if you want to learn Python.
P.S. This issue is totally orthogonal to attributes of objects. Attributes are just other "variables" in Python, which also can hold values. These values can be of different types.

Because by saying rob.age you are not creating a class-wide data attribute that has a specific type; you are merely creating an instance-local, instance-specific attribute that refers to a concrete entity, the string '15'. To create a class-wide attribute you would have to say Employee.age = … or set age inside the class Employee: block. By setting the attribute to a descriptor, I suppose you could check its type every time it is set and restrict it to an integer or string or whatever; but in general, either a class attribute or an instance attribute is just a name for an object, and all Python cares is that .age names an object.
And note that Python could not really guess what you mean anyway. If you say that john.age is 12, you seem to want Python to guess that all other .age attributes should also be numbers. But why shouldn't Python go even further, and guess that they are integers — or better yet, that they are positive even integers? I really do not think it would be reasonable in any case for Python to extrapolate from a single assignment to some kind of guess as to how you will treat that attribute in all other instances of the class.

It's fundamentally what you get when you have a dynamically typed language.
Type is determined at runtime not at declaration.
It has advantages and disadvantages, but I believe the advantages outweigh its disadvantages in most development contexts.
(It's what Ruby, Python, PHP, etc. do)

Python's compiler does not care what type of value you bind to an attribute/name, nor does it have to; Python's dynamic nature means that the important type checks (which are usually actually attribute checks) are done at runtime.

The term "variable" is confusioning in Python.

Related

Why does TypeVar and TypedDict require repeating the variable name as a string?

In Python typing, why do I have to write T = TypeVar("T") instead of just T = TypeVar()? Any static analyzer is able to read the variable name without requiring the string parameter. The string parameter only matters for getting the name of the type variable in runtime. As far as I know, this is only used in the type variable repr:
>>> T = TypeVar("T")
>>> S = TypeVar("U")
>>> T
~T
>>> S
~U
There are two (related) things I'd like to understand:
In what context would I need this repr? Specifically, because of type erasure, the repr will never tell me anything about the actual value of the type variable, only its name. I've never seen this name used for anything in runtime, even for debugging or introspection purposes. In what kind of situations is it useful?
Why is the runtime name mandatory (not only by convention, but as a type-checking rule)? If I don't care about runtime behaviour of the type variable, why am I required to even specify a runtime name to it, and why would this name be tied to the name of the runtime variable the TypeVar is assigned to?
Especially for debugging, it's good to be able to know which type variable you're dealing with when a type variable ends up somewhere it shouldn't. For example, if you end up with a type variable in a list, or if some code gets passed a type variable somehow when it was supposed to be working with a real type object, it's way more useful if printing it gives at least some hint of which type variable you're working with, instead of just telling you "this is a type variable". (You can also check which module it comes from by inspecting its __module__ attribute, although this is unfortunately completely undocumented.)
It's also good for interactive exploration. If you examine a class and find it's generic in Key and Value, or Shape and Dtype, that tells you a lot more than if you find it's generic in <typing.TypeVar object at 0x7fb64d197a00>.
Even if there weren't immediate, concrete use cases for having a name available at runtime, they still probably would have put in the name argument just for consistency, and in case any future use cases came up.

What do we call assigning different types of objects to a variable in Python?

I need to know, what is it called, assigning different types of objects to a variable, in Python. For example,
a = 2
a = 'string'
That is know as "dynamic typing" (as in the type of the variable is dynamic).
It's different from other languages like Java that use "static typing", where the variable must remain a single type.

What does "Everything" mean when someone says "Everything in Python is an object."?

I constantly see people state that "Everything in Python is an object.", but I haven't seen "thing" actually defined. This saying would lead me to believe that all tokens of any kind are also considered to be objects, including operators, punctuators, whitespace, etc. Is that actually the case? Is there a more concise way of stating what a Python object actually is?
Thanks
Anything that can be assigned to a variable is an object.
That includes functions, classes, and modules, and of course int's, str's, float's, list's, and everything else. It does not include whitespace, punctuation, or operators.
Just to mention it, there is the operator module in the standard library which includes functions that implement operators; those functions are objects. That doesn't mean + or * are objects.
I could go on and on, but this is simple and pretty complete.
Some values are obviously objects; they are instances of a class, have attributes, etc.
>>> i = 3
>>> type(i)
<type 'int'>
>>> i.denominator
1
Other values are less obviously objects. Types are objects:
>>> type(int)
<type 'type'>
>>> int.__mul__(3, 5)
15
Even type is an object (of type type, oddly enough):
>>> type(type)
<type 'type'>
Modules are objects:
>>> import sys
>>> type(sys)
<type 'module'>
Built-in functions are objects:
>>> type(sum)
<type 'builtin_function_or_method'>
In short, if you can reference it by name, it's an object.
What is generally meant is that most things, for example functions and methods are objects. Modules too. Classes (not just their instances) themselves are objects. and int/float/strings are objects. So, yes, things generally tend to be objects in Python. Cyphase is correct, I just wanted to give some examples of things that might not be immediately obvious as objects.
Being objects then a number of properties are observable on things that you would consider special case, baked-in stuff in other languages. Though __dict__, which allows arbitrary attribute assignment in Python, is often missing on things intended for large volume instantiations like int.
Therefore, at least on pure-Python objects, a lot of magic can happen, from introspection to things like creating a new class on the fly.
Kinda like turtles all the way down.
You're not going to find a rigorous definition like C++11's, because Python does not have a formal specification like C++11, it has a reference manual like pre-ISO C++. The Data model chapter is as rigorous as it gets:
Objects are Python’s abstraction for data. All data in a Python program is represented by objects or by relations between objects. (In a sense, and in conformance to Von Neumann’s model of a “stored program computer,” code is also represented by objects.)
Every object has an identity, a type and a value. An object’s identity never changes once it has been created; you may think of it as the object’s address in memory. …
The glossary also has a shorter definition:
Any data with state (attributes or value) and defined behavior (methods).
And it's true that everything in Python has methods and (other) attributes. Even if there are no public methods, there's a set of special methods and values inherited from the object base class, like the __str__ method.
This wasn't true in versions of Python before 2.2, which is part of the reason we have multiple words for nearly the same thing—object, data, value; type, class… But from then on, the following kinds of things are identical:
Objects.
Things that can be returned or yielded by a function.
Things that can be stored in a variable (including a parameter).
Things that are instances of type object (usually indirectly, through a subclass or two).
Things that can be the value resulting from an expression.
Things represented by pointers to PyObject structs in CPython.
… and so on.
That's what "everything is an object" means.
It also means that Python doesn't have "native types" and "class types" like Java, or "value types" and "reference types" like C#; there's only one kind of thing, objects.
This saying would lead me to believe that all tokens of any kind are also considered to be objects, including operators, punctuators, whitespace, etc. Is that actually the case?
No. Those things don't have values, so they're not objects.1
Also, variables are not objects. Unlike C-style variables, Python variables are not memory locations with a type containing a value, they're just names bound to a value in some namespace.2 And that's why you can't pass around references to variables; there is no "thing" to reference.3
Assignment targets are also not objects. They sometimes look a lot like values, and even the core devs sometimes refer to things like the a, b in a, b = 1, 2 loosely as a tuple object—but there is no tuple there.4
There's also a bit of apparent vagueness with things like elements of a numpy.array (or an array.array or ctypes.Structure). When you write a[0] = 3, the 3 object doesn't get stored in the array the way it would with a list. Instead, numpy stores some bytes that Python doesn't even understand, but that it can use to do "the same thing a 3 would do" in array-wide operations, or to make a new copy of the 3 object if you later ask for a[0] = 3.
But if you go back to the definition, it's pretty clear that this "virtual 3" is not an object—while it has a type and value, it does not have an identity.
1. At the meta level, you can write an import hook that can act on imported code as a byte string, a decoded Unicode string, a list of token tuples, an AST node, a code object, or a module, and all of those are objects… But at the "normal" level, from within the code being imported, tokens, etc. are not objects.
2. Under the covers, there's almost always a string object to represent that name, stored in a dict or tuple that represents the namespace, as you can see by calling globals() or dir(self). But that's not what the variable is.
3. A closure cell is sort of a way of representing a reference to a variable, but really, it's the cell itself that's an object, and the variables at different scopes are just a slightly special kind of name for that cell.
4. However, in a[0] = 3, although a[0] isn't a value, a and 0 are, because that assignment is equivalent to the expression a.__setitem__(0, 3), except that it's not an expression.

How does Python language know about the type of identifiers?

I recently faced this question..
How does python identifies the type of an identifier?
For example
a=5
b=6
c=a+b
the value of c is 11
Where as
x="hello"
y="world"
z=x+y
the value of z is "helloworld"
How does Python distinguishes these two cases?
In Python, types are not associated with variable names, but with values. The name 'a' does not hold any type information, it's the value '1' that holds that information (namely that it's an 'int' class).
This is a contract to C and Java, where types are associated with variable names.
This is exactly the difference between the Curry-style typing system and Church-style system.
http://en.wikipedia.org/wiki/Simply_typed_lambda_calculus#Intrinsic_vs._extrinsic_interpretations
C and Java use Church typing (variable name has a type) while Python and JavaScript use Curry typing (value has a type).
Check the __add__ method for classes.
What really happens is that the __add__ method of the object is called:
a + b is really a.__add__(b)
Check also diveintopython for special method names.
From the doc:
The int type implements the numbers.Integral abstract base class.
Likewise, strings are instances of the str class.
The python interpreter does not identify the types of identifier. Rather, it identifies the types of the objects referred to by the identifiers. The identifiers or names you declare does not hold the objects but rather refer to the objects and these objects, as pointed out by the previous answers, holds type information about themselves. These python objects are implemented as PyObject structure in C, which has a field PyObject *ob_type pointing to their types (being PyObject as well).
With the background above, now here is what happens when python runs your script.
i = 1: it creates an object for the numeric 1 from the int type.
A name i is bound to the int object created just now. By "bound to" I means inserting an entry into the global dictionary (you can see it by globals()).
Whatever operations you perform on i is forwarded to the object it refers to (being int(1) currently) as #valjeanval42 has explained.
Since the objects always know their types, which are the main source of information about what operations they support, python can correctly handle the i variable not whether it is assigned to 1 or '1' (being a str).
Static language like C++ or Java do things vastly differently than a dynamic language like python, as you would have expected. In short, they manage matter of types at compile time while python does it at run time.

How does Python differentiate between the different data types?

Sorry if this is quite noobish to you, but I'm just starting out to learn Python after learning C++ & Java, and I am wondering how in the world I could just declare variables like id = 0 and name = 'John' without any int's or string's in front! I figured out that perhaps it's because there are no ''s in a number, but how would Python figure that out in something like def increase(first, second) instead of something like int increase(int first, int second) in C++?!
The literal objects you mention carry (pointers to;-) their own types with them of course, so when a name's bound to that object the problem of type doesn't arise -- the object always has a type, the name doesn't -- just delegates that to the object it's bound to.
There's no "figuring out" in def increase(first, second): -- name increase gets bound to a function object, names first and second are recorded as parameters-names and will get bound (quite possibly to objects of different types at various points) as increase gets called.
So say the body is return first + second -- a call to increase('foo', 'bar') will then happily return 'foobar' (delegating the addition to the objects, which in this case are strings), and maybe later a call to increase(23, 45) will just as happily return 68 -- again by delegating the addition to the objects bound to those names at the point of call, which in this case are ints. And if you call with incompatible types you'll get an exception as the delegated addition operation can't make sense of the situation -- no big deal!
Python is dynamically typed: all variables can refer to an object of any type. id and name can be anything, but the actual objects are of types like int and str. 0 is a literal that is parsed to make an int object, and 'John' a literal that makes a str object. Many object types do not have literals and are returned by a callable (like frozenset—there's no way to make a literal frozenset, you must call frozenset.)
Consequently, there is no such thing as declaration of variables, since you aren't defining anything about the variable. id = 0 and name = 'John' are just assignment.
increase returns an int because that's what you return in it; nothing in Python forces it not to be any other object. first and second are only ints if you make them so.
Objects, to a certain extent, share a common interface. You can use the same operators and functions on them all, and if they support that particular operation, it works. It is a common, recommended technique to use different types that behave similarly interchangably; this is called duck typing. For example, if something takes a file object you can instead pass a cStringIO.StringIO object, which supports the same method as a file (like read and write) but is a completely different type. This is sort of like Java interfaces, but does not require any formal usage, you just define the appropriate methods.
Python uses the duck-typing method - if it walks, looks and quacks like a duck, then it's a duck. If you pass in a string, and try to do something numerical on it, then it will fail.
Have a look at: http://en.wikipedia.org/wiki/Python_%28programming_language%29#Typing and http://en.wikipedia.org/wiki/Duck_typing
When it comes to assigning literal values to variables, the type of the literal value can be inferred at the time of lexical analysis. For example, anything matching the regular expression (-)?[1-9][0-9]* can be inferred to be an integer literal. If you want to convert it to a float, there needs to be an explicit cast. Similarly, a string literal is any sequence of characters enclosed in single or double quotes.
In a method call, the parameters are not type-checked. You only need to pass in the correct number of them to be able to call the method. So long as the body of the method does not cause any errors with respect to the arguments, you can call the same method with lots of different types of arguments.
In Python, Unlike in C++ and Java, numbers and strings are both objects. So this:
id = 0
name = 'John'
is equivalent to:
id = int(0)
name = str('John')
Since variables id and name are references that may address any Python object, they don't need to be declared with a particular type.

Categories

Resources