Confusion in file functioning and append function using Python - python

I have two questions for an exam.
t2=("A","B","Hello")
alist=["Barney",["Wilma"]]
print(alist[1].append(t2))
answer:
None
I thought it would be [“Wilma”,(“A”,”B”,”Hello”)]
AND
file has:
James,8,9
Sonia,7,6
Clark,4,5
code:
endofprogram=False
try:
infile=open("names.txt",”r”)
except IOError:
print("Error reading file")
endofprogram=True
if endofprogram==False:
for line in infile:
line.strip('\n')
alist=line.split(',')
print(alist)
Answer
['James','8','9\n']
['Sonia','7','6\n']
['Clark','4','5\n']
Why is '\n' still there?
LASTLY:
def change(aList):
aList=aList.pop()
aList.append(5)
return
def main():
mylist=[1,2,[3]]
change(mylist)
print(mylist)
main()
Answer:
[1,2]
Why is this the answer? shouldn't it be [1,2,5]?

list.append is an in-place operation, it modifies the list in-place and returns None.
>>> lst = []
>>> repr(lst.append(1)) #returns None
'None'
>>> lst #list modified
[1]
Strings are immutable, you need to re-assign the result of .strip() call back to a variable.
line = line.strip('\n') #re-assign the new returned string to a variable.
alist = line.split(',')
You re-assigned aList to a different list, so the .append() call won't affect the originally passed list.
def change(aList):
aList = aList.pop() #Now aList points to [3] not to `[1, 2, [3]]`
aList.append(5)
You can simply use the assignment statement here:
aList[-1] = 5

list.append() is an operation which returns None because it modifies the list in place. You must print the actual list to get the output you expect.
line.strip("\n") does strip the newline, but it never gets saved anywhere. Strings are immutable in python, thus str.strip() returns a new string with the characters stripped. The correct way to use it is to say line = line.strip("\n").
Example 1:
>>> alist[1].append(t2)
>>> print alist
['Barney', ['Wilma', ('A', 'B', 'Hello')]]
Example 2:
>>> line = "Foo\n"
>>> line.strip("\n")
'Foo'
>>> line
'Foo\n'
>>> line = line.strip("\n")
>>> line
'Foo'

The append function returns nothing, thus the None result. It only appends to the list.
The strip function only removes characters at the end & beginning. If you are working on Windows, the actual line ending may well be \n\r, making the last character \r. That is not removed by your strip command.
Your third problem is because in the change function, the aList value is lost as soon the function Change exists. You should do:
def Change(l):
l.pop()
l.append(5)
In Python, an assignment does not change any underlying variable. Instead, the name is bound to a new value. Thus, after the line alIst = aList.pop(), aList points to [3], but is no longer linked the the myList object. After the append function, aList points to [3, 5], but this object is garbage collected as soon as Change returns.

Related

Why can't a list be constructed and modified in the same line?

For example, why is a not equal to b?
a = [1]
a.append(2)
print(a) # [1, 2]
b = [1].append(2)
print(b) # None
The syntax for b doesn't look wrong to me, but it is. I want to write one-liners to define a list (e.g. using a generator expression) and then append elements, but all I get is None.
It's because:
append, extend, sort and more list function are all "in-place".
What does "in-place" mean? it means it modifies the original variable directly, some things you would need:
l = sorted(l)
To modify the list, but append already does that, so:
l.append(3)
Will modify l already, don't need:
l = l.append(3)
If you do:
l = [1].append(2)
Yes it will modify the list of [1], but it would be lost in memory somewhere inaccessible, whereas l will become None as we discovered above.
To make it not "in-place", without using append either do:
l = l + [2]
Or:
l = [*l, 2]
The one-liner for b does these steps:
Defines a list [1]
Appends 2 to the list in-place
Append has no return, so b = None
The same is true for all list methods that alter the list in-place without a return. These are all None:
c = [1].extend([2])
d = [2, 1].sort()
e = [1].insert(1, 2)
...
If you wanted a one-liner that is similar to your define and extend, you could do
c2 = [1, *[2]]
which you could use to combine two generator expressions.
All built-in methods under class 'List' in Python are just modifying the list 'in situ'. They only change the original list and return nothing.
The advantage is, you don't need to pass the object to the original variable every time you modify it. Meanwhile, you can't accumulatively call its methods in one line of code such as what is used in Javascript. Because Javascript always turns its objects into DOM, but Python not.

Initializing a list and appending in one line

How can I initialize a list, if it is not already initialized and append to it in one line. For example,
function example(a=None):
a = a or []
a.append(1)
return another_function(a)
How can I combine those two statements in the function into one?
I am looking for something like this, but that does not work:
function example(a):
a = (a or []).append(1)
return another_function(a)
EDIT: I don't reference a elsewhere, it is just being passed from function to function. Practically just value is important, so it is OK if it is another object with the right value. I also added a default value of None.
def example(a):
return a + [1] if a else [1]
>>> example([1,2,3])
[1, 2, 3, 1]
>>> example([])
[1]

What is the difference between appending to an empty list and reassigning it?

If we create an empty list then we can fill this list by either appending "something"
list_ex1 = []
list_ex1.append(1)
print(list_ex1)
[1]
or we can reassign an empty list as the same "something".
list_ex2 = []
list_ex2 = [1]
print(list_ex2)
[1]
Great, we get the same result. However, there must be some very different happenings going on in the background. This became obvious when I was using tkinter to create a simple UI with some buttons on it.
def Multi_Import_Match(imp):
imp_fill = []
win = Tk()
win.title('Select Name')
win.geometry("500x100")
b = []
def but_call(imp):
imp_fill.append(imp) # Here is where the problem became apparent!!
win.destroy()
for i in range(0,len(imp)):
b.append(Button(win, text=imp[i], command=lambda i=i: but_call(imp[i])))
b[i].pack()
mainloop()
return imp_fill
I struggled for a while to get the expected output from my UI when using imp_fill = imp but it only returned an empty list. With imp_fill.append(imp) the code worked perfectly and returned my desired string. Why is it that the append works and the reassignment does not?
NB: the variable imp was a small list of strings.
The issue here is scope. Python will search outer levels of scope if it can't find a local definition for a name. That's why this can work:
val = "hello"
def print_val():
print(val)
print_val()
# hello
This becomes more confusing with lists though, as they're mutable. That means that if you append to a list from within a function, you are affecting it in the original scope. See this:
val = []
def print_val():
val.append("hello")
print(val)
print(val)
# []
print_val()
# ['hello']
print(val)
# ['hello']
The list is originally empty, but after calling print_val the list is appended to. This affects the actual list, which in turn means that when you just print it normally it has 'hello' in it.
In your case, if you just did the equivalent of val = ['hello'] inside the function, that only affects the value of val within the function, and nothing happens to the original scoped name. The solution is to either use return [val] to get the value from the function's scope or to use append as you did, which modifies the actual value that exists outside the function.
The difference comes from the fact that a list is a mutable object. So other references to same object are changed accordingly when you modify the object, but are left alone when you affect the reference to a different object
Let's use your example with an alternate reference:
>>> list_ex1 = []
>>> old = list_ex1
>>> list_ex1.append(1)
>>> print(list_ex1)
[1]
>>> old
[1]
>>> old is list_ex1
True
>>> list_ex2 = []
>>> old2 = list_ex2
>>> list_ex2 = [1]
>>> print(list_ex2)
[1]
>>> old2
[]
>>> old2 is list_ex2
False
In your example modifying the list with append also modifies the original object, where as affecting it only changes a local copy and leave the original object untouched.
First off, from a reading of this code, you should really change the argument name for the but_call() function to avoid confusion. The argument seems to be an element of the list imp, not your variable imp itself. Clarity is the key here.
Secondly, you are right that the statements are different:
imp_fill = imp replaces the pre-existing value of fill_imp ([] at start but changes every time this statement is executed) with that of imp (whatever it may be - list, str, int, object, ...)
imp_fill = [imp] replaces the pre-existing value of fill_imp with a list which has one element - the value of imp
imp_fill.append(imp) takes the pre-existing list and expands it by 1 element, which is the value of imp
So:
>>> a = [2]
>>> a = [9, 5]
>>> print(a)
[9, 5]
>>> a = [2]
>>> a = 943
>>> print(a)
943
>>> a = [2]
>>> a.append(98)
>>> print(a)
[2, 98]

when a python list iteration is and is not a reference

Could someone please offer a concise explanation for the difference between these two Python operations in terms of modifying the list?
demo = ["a", "b", "c"]
for d in demo:
d = ""
print demo
#output: ['a', 'b', 'c']
for c in range(len(demo)):
demo[c] = ""
print demo
#output: ['', '', '']
In other words, why doesn't the first iteration modify the list? Thanks!
The loop variable d is always a reference to an element of the iterable object. The question is not really a matter of when or when isn't it a reference. It is about the assignment operation that you are performing with the loop.
In the first example, you are rebinding the original reference of an element in the object, with another reference to an empty string. This means you don't actually do anything to the value. You just assign a new reference to the symbol.
In the second example, you are performing an indexing operation and assigning a new reference to the value at that index. demo remains the same reference, and you are replacing a value in the container.
The assignment is really the equivalent of: demo.__setitem__(c, "")
a = 'foo'
id(a) # 4313267976
a = 'bar'
id(a) # 4313268016
l = ['foo']
id(l) # 4328132552
l[0] = 'bar'
id(l) # 4328132552
Notice how in the first example, the object id has changed. It is a reference to a new object. In the second one, we index into the list and replace a value in the container, yet the list remains the same object.
In the first example, the variable d can be thought of a copy of the elements inside the list. When doing d = "", you're essentially modifying a copy of whatever's inside the list, which naturally won't change the list.
In the second example, by doing range(len(demo)) and indexing the elements inside the list, you're able to directly access and change the elements inside the list. Therefore, doing demo[c] would modify the list.
If you do want to directly modify a Python list from inside a loop, you could either make a copy out the list and operate on that, or, preferably, use a list comprehension.
So:
>>> demo = ["a", "b", "c"]
>>> test = ["" for item in demo]
>>> print test
["", "", ""]
>>> demo2 = [1, 5, 2, 4]
>>> test = [item for item in demo if item > 3]
>>> print test
[5, 4]
When you do d = <something> you are making the variable d refer to <something>. This way you can use d as if it was <something>. However, if you do d = <something else>, d now points to <something else> and no longer <something> (the = sign is used as the assignment operator). In the case of demo[c] = <something else>, you are assigning <something else> to the (c+1)th item in the list.
One thing to note, however, is that if the item d has self-modifying methods which you want to call, you can do
for d in demo:
d.<some method>()
since the list demo contains those objects (or references to the objects, I don't remember), and thus if those objects are modified, the list is modified too.

How do I get the last element of a list?

How do I get the last element of a list?
Which way is preferred?
alist[-1]
alist[len(alist) - 1]
some_list[-1] is the shortest and most Pythonic.
In fact, you can do much more with this syntax. The some_list[-n] syntax gets the nth-to-last element. So some_list[-1] gets the last element, some_list[-2] gets the second to last, etc, all the way down to some_list[-len(some_list)], which gives you the first element.
You can also set list elements in this way. For instance:
>>> some_list = [1, 2, 3]
>>> some_list[-1] = 5 # Set the last element
>>> some_list[-2] = 3 # Set the second to last element
>>> some_list
[1, 3, 5]
Note that getting a list item by index will raise an IndexError if the expected item doesn't exist. This means that some_list[-1] will raise an exception if some_list is empty, because an empty list can't have a last element.
If your str() or list() objects might end up being empty as so: astr = '' or alist = [], then you might want to use alist[-1:] instead of alist[-1] for object "sameness".
The significance of this is:
alist = []
alist[-1] # will generate an IndexError exception whereas
alist[-1:] # will return an empty list
astr = ''
astr[-1] # will generate an IndexError exception whereas
astr[-1:] # will return an empty str
Where the distinction being made is that returning an empty list object or empty str object is more "last element"-like then an exception object.
You can also do:
last_elem = alist.pop()
It depends on what you want to do with your list because the pop() method will delete the last element.
The simplest way to display last element in python is
>>> list[-1:] # returns indexed value
[3]
>>> list[-1] # returns value
3
there are many other method to achieve such a goal but these are short and sweet to use.
In Python, how do you get the last element of a list?
To just get the last element,
without modifying the list, and
assuming you know the list has a last element (i.e. it is nonempty)
pass -1 to the subscript notation:
>>> a_list = ['zero', 'one', 'two', 'three']
>>> a_list[-1]
'three'
Explanation
Indexes and slices can take negative integers as arguments.
I have modified an example from the documentation to indicate which item in a sequence each index references, in this case, in the string "Python", -1 references the last element, the character, 'n':
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5
-6 -5 -4 -3 -2 -1
>>> p = 'Python'
>>> p[-1]
'n'
Assignment via iterable unpacking
This method may unnecessarily materialize a second list for the purposes of just getting the last element, but for the sake of completeness (and since it supports any iterable - not just lists):
>>> *head, last = a_list
>>> last
'three'
The variable name, head is bound to the unnecessary newly created list:
>>> head
['zero', 'one', 'two']
If you intend to do nothing with that list, this would be more apropos:
*_, last = a_list
Or, really, if you know it's a list (or at least accepts subscript notation):
last = a_list[-1]
In a function
A commenter said:
I wish Python had a function for first() and last() like Lisp does... it would get rid of a lot of unnecessary lambda functions.
These would be quite simple to define:
def last(a_list):
return a_list[-1]
def first(a_list):
return a_list[0]
Or use operator.itemgetter:
>>> import operator
>>> last = operator.itemgetter(-1)
>>> first = operator.itemgetter(0)
In either case:
>>> last(a_list)
'three'
>>> first(a_list)
'zero'
Special cases
If you're doing something more complicated, you may find it more performant to get the last element in slightly different ways.
If you're new to programming, you should avoid this section, because it couples otherwise semantically different parts of algorithms together. If you change your algorithm in one place, it may have an unintended impact on another line of code.
I try to provide caveats and conditions as completely as I can, but I may have missed something. Please comment if you think I'm leaving a caveat out.
Slicing
A slice of a list returns a new list - so we can slice from -1 to the end if we are going to want the element in a new list:
>>> a_slice = a_list[-1:]
>>> a_slice
['three']
This has the upside of not failing if the list is empty:
>>> empty_list = []
>>> tail = empty_list[-1:]
>>> if tail:
... do_something(tail)
Whereas attempting to access by index raises an IndexError which would need to be handled:
>>> empty_list[-1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
But again, slicing for this purpose should only be done if you need:
a new list created
and the new list to be empty if the prior list was empty.
for loops
As a feature of Python, there is no inner scoping in a for loop.
If you're performing a complete iteration over the list already, the last element will still be referenced by the variable name assigned in the loop:
>>> def do_something(arg): pass
>>> for item in a_list:
... do_something(item)
...
>>> item
'three'
This is not semantically the last thing in the list. This is semantically the last thing that the name, item, was bound to.
>>> def do_something(arg): raise Exception
>>> for item in a_list:
... do_something(item)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 1, in do_something
Exception
>>> item
'zero'
Thus this should only be used to get the last element if you
are already looping, and
you know the loop will finish (not break or exit due to errors), otherwise it will point to the last element referenced by the loop.
Getting and removing it
We can also mutate our original list by removing and returning the last element:
>>> a_list.pop(-1)
'three'
>>> a_list
['zero', 'one', 'two']
But now the original list is modified.
(-1 is actually the default argument, so list.pop can be used without an index argument):
>>> a_list.pop()
'two'
Only do this if
you know the list has elements in it, or are prepared to handle the exception if it is empty, and
you do intend to remove the last element from the list, treating it like a stack.
These are valid use-cases, but not very common.
Saving the rest of the reverse for later:
I don't know why you'd do it, but for completeness, since reversed returns an iterator (which supports the iterator protocol) you can pass its result to next:
>>> next(reversed([1,2,3]))
3
So it's like doing the reverse of this:
>>> next(iter([1,2,3]))
1
But I can't think of a good reason to do this, unless you'll need the rest of the reverse iterator later, which would probably look more like this:
reverse_iterator = reversed([1,2,3])
last_element = next(reverse_iterator)
use_later = list(reverse_iterator)
and now:
>>> use_later
[2, 1]
>>> last_element
3
To prevent IndexError: list index out of range, use this syntax:
mylist = [1, 2, 3, 4]
# With None as default value:
value = mylist and mylist[-1]
# With specified default value (option 1):
value = mylist and mylist[-1] or 'default'
# With specified default value (option 2):
value = mylist[-1] if mylist else 'default'
lst[-1] is the best approach, but with general iterables, consider more_itertools.last:
Code
import more_itertools as mit
mit.last([0, 1, 2, 3])
# 3
mit.last(iter([1, 2, 3]))
# 3
mit.last([], "some default")
# 'some default'
Another method:
some_list.reverse()
some_list[0]
Here is the solution for your query.
a=["first","second","second from last","last"] # A sample list
print(a[0]) #prints the first item in the list because the index of the list always starts from 0.
print(a[1]) #prints second item in list
print(a[-1]) #prints the last item in the list.
print(a[-2]) #prints the second last item in the list.
Output:
>>> first
>>> second
>>> last
>>> second from last
list[-1] will retrieve the last element of the list without changing the list.
list.pop() will retrieve the last element of the list, but it will mutate/change the original list. Usually, mutating the original list is not recommended.
Alternatively, if, for some reason, you're looking for something less pythonic, you could use list[len(list)-1], assuming the list is not empty.
You can also use the code below, if you do not want to get IndexError when the list is empty.
next(reversed(some_list), None)
Ok, but what about common in almost every language way items[len(items) - 1]? This is IMO the easiest way to get last element, because it does not require anything pythonic knowledge.
Strange that nobody posted this yet:
>>> l = [1, 2, 3]
>>> *x, last_elem = l
>>> last_elem
3
>>>
Just unpack.
You can use ~ operator to get the ith element from end (indexed from 0).
lst=[1,3,5,7,9]
print(lst[~0])
Accessing the last element from the list in Python:
1: Access the last element with negative indexing -1
>> data = ['s','t','a','c','k','o','v','e','r','f','l','o','w']
>> data[-1]
'w'
2. Access the last element with pop() method
>> data = ['s','t','a','c','k','o','v','e','r','f','l','o','w']
>> data.pop()
'w'
However, pop method will remove the last element from the list.
METHOD 1:
L = [8, 23, 45, 12, 78]
print(L[len(L)-1])
METHOD 2:
L = [8, 23, 45, 12, 78]
print(L[-1])
METHOD 3:
L = [8, 23, 45, 12, 78]
L.reverse()
print(L[0])
METHOD 4:
L = [8, 23, 45, 12, 78]
print(L[~0])
METHOD 5:
L = [8, 23, 45, 12, 78]
print(L.pop())
All are outputting 78
To avoid "IndexError: list index out of range", you can use this piece of code.
list_values = [12, 112, 443]
def getLastElement(lst):
if len(lst) == 0:
return 0
else:
return lst[-1]
print(getLastElement(list_values))
Pythonic Way
So lets consider that we have a list a = [1,2,3,4], in Python List can be manipulated to give us part of it or a element of it, using the following command one can easily get the last element.
print(a[-1])
You can also use the length to get the last element:
last_elem = arr[len(arr) - 1]
If the list is empty, you'll get an IndexError exception, but you also get that with arr[-1].
If you use negative numbers, it will start giving you elements from last of the list
Example
lst=[1,3,5,7,9]
print(lst[-1])
Result
9
If you do my_list[-1] this returns the last element of the list. Negative sequence indexes represent positions from the end of the array. Negative indexing means beginning from the end, -1 refers to the last item, -2 refers to the second-last item, etc.
You will just need to take the and put [-1] index. For example:
list=[0,1,2]
last_index=list[-1]
print(last_index)
You will get 2 as the output.
You could use it with next and iter with [::-1]:
>>> a = [1, 2, 3]
>>> next(iter(a[::-1]))
3
>>>
array=[1,2,3,4,5,6,7]
last_element= array[len(array)-1]
last_element
Another simple solution
Couldn't find any answer mentioning this. So adding.
You could try some_list[~0] also.
That's the tilde symbol

Categories