Is a list a variable? - python

I am new to python and i was just reading up about lists. I have been trying to find out if a list is a variable
e.g. Hello = []
This is because I read that you assign a variable by using the '=' sign. Or, am I just assigning the empty list a name in the example above.

No. A list is an object. You assign a list to a name-reference with =.
Thus a = [1,2] produces a which is a name-reference (a pointer essentially) to the underlying list object which you see by looking at globals().
>>> a = [1,2]
>>> globals()
{'a': [1, 2], '__builtins__': <module '__builtin__' (built-in)>, '__package__': None, '__name__': '__main__', '__doc__': None}
A list is an instance of a ListType, which is a subclass of an object.
>>> import types
>>> types.ListType.mro()
[<type 'list'>, <type 'object'>]
>>> object
<type 'object'>
>>> b = types.ListType()
>>> b
[]

In Python, the concept of object is quite important (as other users might have pointed out already, I am being slow!).
You can think of list as a list (or actually, an Object) of elements. As a matter of fact, list is a Variable-sized object that represents a collection of items. Python lists are a bit special because you can have mixed types of elements in a list (e.g. strings with int)But at the same time, you can also argue,"What about set, map, tuple, etc.?". As an example,
>>> p = [1,2,3,'four']
>>> p
[1, 2, 3, 'four']
>>> isinstance(p[1], int)
True
>>> isinstance(p[3], str)
True
>>>
In a set, you can vary the size of the set - yes. In that respect, set is a variable that contains unique items - if that satisfies you....
In this way, a map is also a "Variable" sized key-value pair where every unique key has a value mapped to it. Same goes true for dictionary.
If you are curious because of the = sign - you have already used a keyword in your question; "Assignment". In all the high level languages (well most of them anyway), = is the assignment operator where you have a variable name on lhs and a valid value (either a variable of identical type/supertype, or a valid value).

The line:
Hello = []
creates a new, empty list object (instance of the list class), and assigns a reference to that object to the name (or "identifier") Hello.
You can then access that list object via the name Hello (as long as it is accessible in the current scope), e.g.:
Hello.append('World')
Lists are mutable, i.e. they can be changed in-place, in this case by appending (adding) a new string object to the list referenced by the name Hello. This may be what you meant by "variable".
For more on names in Python, see http://nedbatchelder.com/text/names.html.
For more on lists (and Python's other built-in sequence types), see the official docs.

Python lists are Data structure which enables you to hold a collection of data items. Data structures are objects or programming types which enable you to store any kind of data been integer, string etc. in memory or permanently on hard disk.
In your case, you have defined a list structure - which will store collection of data items referenced by the symbol hello. The symbol hello is termed as variable in programming.
Using a variable, you can reference your list from any part of your program to locate and access its member items.
Example:
hello = [1, 3, 100]
Calling hello with its Nth index starting at 0 will access and return the value placed within the Nth index location.
print hello[0]
Which will output 1 .
See Array data structure for more examples.

Related

When a tuple is reassigned to a new address, is the value at the old address cleared?

I was trying to figure out how memory allocation works with regards to a tuple in python.
skills = ("Python", "pandas", "scikit-learn")
print(id(skills))
This gives me a value of 140555133913704
I modify this tuple to create a new one
skills += ("ml","dl")
print(id(skills))
The new address is 140555133738680
Is the tuple object at 140555133913704 deleted and the address cleared?
Is modifying a tuple less or more space efficient as compared to modifying a list?
everything besides primitives in python is an object so when you type:
skills = ("Python", "pandas", "scikit-learn")
you are creating a tuple object and the reference to that is going to be stored in the skills variable you declared.
in the second step, you make another tuple object with the value of the last tuple in addition to "ml" and "dl" now you have the new object's reference in your skills variable.
what happened to the last one? well, it is still there but now it is an unreferenced object and the python garbage collector will clear that.
about lists, a list in python is also an object and is stored with the data of it and a "len" attribute which indicates the length of the array so if you append something to a list this will happen again although lists are mutable objects! (I actually got suspicious about this and tried it myself and it changed:) ) so again, the garbage collector will remove the unreferenced object after a while.
>>> list = [1,2,3]
>>> id(list)
2214374343624
>>> list = list + [2,3]
>>> list
[1, 2, 3, 2, 3]
>>> id(list)
2214472730440
It is because tuples are immutable and they cannot be changed. In your example adding tuple to a tuple will create a new tuple and assigns it to same name. It will not change the tuple object originally referenced by that name.
The tuple object at 140555133913704 will not be deleted. It will have previous value i-e, ("Python", "pandas", "scikit-learn")
Tuples are more space-efficient than lists. Lists are over-allocated to make appending faster.

Detecting recursive nested list in Python

Say I create a recursive nested list in Python like this:
>>> a = [1,2]
>>> a += [a]
Some properties:
len(a) is 3
a[2] is a is True
What happens when you print out a? This appears:
>>> a
[1, 2, [...]]
Similarly:
>>> a[2]
[1, 2, [...]]
Why? How does Python "know" the recursion within the list? How is the recursion detected?
When Python constructs the repr of a builtin object such as a list it uses two internal functions: Py_ReprEnter(PyObject *), and Py_ReprLeave(PyObject *).
The first of these functions checks we are already handling the repr for the specified object (i.e. looks to see whether it is currently remembering that object). If not it remembers the object and returns 0. In that case the repr code prints the object then calls Py_ReprLeave which removes the object from the set that are currently being tracked.
If Py_ReprEnter is already tracking the object it returns non 0 and in that case the list repr code prints [...].

python tuple immutable but set type attribute can be changed

I understand that a namedtuple in python is immutable and the values of its attributes cant be reassigned directly
N = namedtuple("N",['ind','set','v'])
def solve()
items=[]
R = set(range(0,8))
for i in range(0,8):
items.append(N(i,R,8))
items[0].set.remove(1)
items[0].v+=1
Here last like where I am assigning a new value to attribute 'v' will not work. But removing the element '1' from the set attribute of items[0] works.
Why is that and will this be true if set attribute were of List type
Immutability does not get conferred on mutable objects inside the tuple. All immutability means is you can't change which particular objects are stored - ie, you can't reassign items[0].set. This restriction is the same regardless of the type of that variable - if it was a list, doing items[0].list = items[0].list + [1,2,3] would fail (can't reassign it to a new object), but doing items[0].list.extend([1,2,3]) would work.
Think about it this way: if you change your code to:
new_item = N(i,R,8)
then new_item.set is now an alias for R (Python doesn't copy objects when you reassign them). If tuples conferred immutability to mutable members, what would you expect R.remove(1) to do? Since it is the same set as new_item.set, any changes you make to one will be visible in the other. If the set had become immutable because it has become a member of a tuple, R.remove(1) would suddenly fail. All method calls in Python work or fail depending on the object only, not on the variable - R.remove(1) and new_item.set.remove(1) have to behave the same way.
This also means that:
R = set(range(0,8))
for i in range(0,8):
items.append(N(i,R,8))
probably has a subtle bug. R never gets reassigned here, and so every namedtuple in items gets the same set. You can confirm this by noticing that items[0].set is items[1].set is True. So, anytime you mutate any of them - or R - the modification would show up everywhere (they're all just different names for the same object).
This is a problem that usually comes up when you do something like
a = [[]] * 3
a[0].append(2)
and a will now be [[2], [2], [2]]. There are two ways around this general problem:
First, be very careful to create a new mutable object when you assign it, unless you do deliberately want an alias. In the nested lists example, the usual solution is to do a = [[] for _ in range(3)]. For your sets in tuples, move the line R = ... to inside the loop, so it gets reassigned to a new set for each namedtuple.
The second way around this is to use immutable types. Make R a frozenset, and the ability to add and remove elements goes away.
You mutate the set, not the tuple. And sets are mutable.
>>> s = set()
>>> t = (s,)
>>> l = [s]
>>> d = {42: s}
>>> t
(set([]),)
>>> l
[set([])]
>>> d
{42: set([])}
>>> s.add('foo')
>>> t
(set(['foo']),)
>>> l
[set(['foo'])]
>>> d
{42: set(['foo'])}

What is the difference between curly brace and square bracket in Python?

what is the difference between curly brace and square bracket in python?
A ={1,2}
B =[1,2]
when I print A and B on my terminal, they made no difference. Is it real?
And sometimes, I noticed some code use {} and [] to initialize different variables.
E.g. A=[], B={}
Is there any difference there?
Curly braces create dictionaries or sets. Square brackets create lists.
They are called literals; a set literal:
aset = {'foo', 'bar'}
or a dictionary literal:
adict = {'foo': 42, 'bar': 81}
empty_dict = {}
or a list literal:
alist = ['foo', 'bar', 'bar']
empty_list = []
To create an empty set, you can only use set().
Sets are collections of unique elements and you cannot order them. Lists are ordered sequences of elements, and values can be repeated. Dictionaries map keys to values, keys must be unique. Set and dictionary keys must meet other restrictions as well, so that Python can actually keep track of them efficiently and know they are and will remain unique.
There is also the tuple type, using a comma for 1 or more elements, with parenthesis being optional in many contexts:
atuple = ('foo', 'bar')
another_tuple = 'spam',
empty_tuple = ()
WARNING_not_a_tuple = ('eggs')
Note the comma in the another_tuple definition; it is that comma that makes it a tuple, not the parenthesis. WARNING_not_a_tuple is not a tuple, it has no comma. Without the parentheses all you have left is a string, instead.
See the data structures chapter of the Python tutorial for more details; lists are introduced in the introduction chapter.
Literals for containers such as these are also called displays and the syntax allows for procedural creation of the contents based of looping, called comprehensions.
They create different types.
>>> type({})
<type 'dict'>
>>> type([])
<type 'list'>
>>> type({1, 2})
<type 'set'>
>>> type({1: 2})
<type 'dict'>
>>> type([1, 2])
<type 'list'>
These two braces are used for different purposes. If you just want a list to contain some elements and organize them by index numbers (starting from 0), just use the [] and add elements as necessary. {} are special in that you can give custom id's to values like a = {"John": 14}. Now, instead of making a list with ages and remembering whose age is where, you can just access John's age by a["John"].
The [] is called a list and {} is called a dictionary (in Python). Dictionaries are basically a convenient form of list which allow you to access data in a much easier way.
However, there is a catch to dictionaries. Many times, the data that you put in the dictionary doesn't stay in the same order as before. Hence, when you go through each value one by one, it won't be in the order you expect. There is a special dictionary to get around this, but you have to add this line from collections import OrderedDict and replace {} with OrderedDict(). But, I don't think you will need to worry about that for now.

Does assigning another variable to a string make a copy or increase the reference count

On p.35 of "Python Essential Reference" by David Beazley, he first states:
For immutable data such as strings, the interpreter aggressively
shares objects between different parts of the program.
However, later on the same page, he states
For immutable objects such as numbers and strings, this assignment
effectively creates a copy.
But isn't this a contradiction? On one hand he is saying that they are shared, but then he says they are copied.
An assignment in python never ever creates a copy (it is technically possible only if the assignment for a class member is redefined for example by using __setattr__, properties or descriptors).
So after
a = foo()
b = a
whatever was returned from foo has not been copied, and instead you have two variables a and b pointing to the same object. No matter if the object is immutable or not.
With immutable objects however it's hard to tell if this is the case (because you cannot mutate the object using one variable and check if the change is visible using the other) so you are free to think that indeed a and b cannot influence each other.
For some immutable objects also Python is free to reuse old objects instead of creating new ones and after
a = x + y
b = x + y
where both x and y are numbers (so the sum is a number and is immutable) may be that both a and b will be pointing to the same object. Note that there is no such a guarantee... it may also be that instead they will be pointing to different objects with the same value.
The important thing to remember is that Python never ever makes a copy unless specifically instructed to using e.g. copy or deepcopy. This is very important with mutable objects to avoid surprises.
One common idiom you can see is for example:
class Polygon:
def __init__(self, pts):
self.pts = pts[:]
...
In this case self.pts = pts[:] is used instead of self.pts = pts to make a copy of the whole array of points to be sure that the point list will not change unexpectedly if after creating the object changes are applied to the list that was passed to the constructor.
It effectively creates a copy. It doesn't actually create a copy. The main difference between having two copies and having two names share the same value is that, in the latter case, modifications via one name affect the value of the other name. If the value can't be mutated, this difference disappears, so for immutable objects there is little practical consequence to whether the value is copied or not.
There are some corner cases where you can tell the difference between copies and different objects even for immutable types (e.g., by using the id function or the is operator), but these are not useful for Python builtin immutable types (like strings and numbers).
No, assigning a pre-existing str variable to a new variable name does not create an independent copy of the value in memory.
The existence of unique objects in memory can be checked using the id() function. For example, using the interactive Python prompt, try:
>>> str1 = 'ATG'
>>> str2 = str1
Both str1 and str2 have the same value:
>>> str1
'ATG'
>>> str2
'ATG'
This is because str1 and str2 both point to the same object, evidenced by the fact that they share the same unique object ID:
>>> id(str1)
140439014052080
>>> id(str2)
140439014052080
>>> id(str1) == id(str2)
True
Now suppose you modify str1:
>>> str1 += 'TAG' # same as str1 = str1 + 'TAG'
>>> str1
ATGTAG
Because str objects are immutable, the above assignment created a new unique object with its own ID:
>>> id(str1)
140439016777456
>>> id(str1) == id(str2)
False
However, str2 maintains the same ID it had earlier:
>>> id(str2)
140439014052080
Thus, execution of str1 += 'TAG' assigned a brand new str object with its own unique ID to the variable str1, while str2 continues to point to the original str object.
This implies that assigning an existing str variable to another variable name does not create a copy of its value in memory.

Categories