Differences

This shows you the differences between two versions of the page.

Link to this comparison view

ii:labs:02:tasks:01 [2021/11/07 13:05]
radu.mantu [01. [30p] Intro & data types (mostly)]
ii:labs:02:tasks:01 [2024/10/25 01:48] (current)
radu.mantu
Line 1: Line 1:
-==== 01. [30p] Intro & data types (mostly) ​====+==== 01. [25p] Intro, datatypes and more ====
  
 Up until now, you should have had some interaction with the //C language// (or even, with //C++//). Normally, you would write your code in a source file, compile it with **gcc** and most likely get a few dozen errors. Eventually, you would end up with a binary executable file (i.e.: an [[https://​refspecs.linuxfoundation.org/​elf/​elf.pdf|ELF]]). Up until now, you should have had some interaction with the //C language// (or even, with //C++//). Normally, you would write your code in a source file, compile it with **gcc** and most likely get a few dozen errors. Eventually, you would end up with a binary executable file (i.e.: an [[https://​refspecs.linuxfoundation.org/​elf/​elf.pdf|ELF]]).
Line 73: Line 73:
 </​code>​ </​code>​
  
-Notice how we we accessed the real and imaginary parts of the complex number ''​c''?​ Being able to do this should immediately remind of structures in //C//, or classes in //C++//. We should investigate this further...+Notice how we accessed the real and imaginary parts of the complex number ''​c''?​ Being able to do this should immediately remind of structures in //C//, or classes in //C++//. We should investigate this further...
  
 <code python> <code python>
Line 103: Line 103:
 So the //complex// type has two internal variables that hold the real and imaginary parts of the number. But what's this? It also has a method (i.e.: function) defined. Try to invoke **conjugate()** for ''​c''​. Does it work? Does it change the **imag** and **real** internal variables? So the //complex// type has two internal variables that hold the real and imaginary parts of the number. But what's this? It also has a method (i.e.: function) defined. Try to invoke **conjugate()** for ''​c''​. Does it work? Does it change the **imag** and **real** internal variables?
  
-Well, that was an interesting detour. But let's get back to our numbers. As you might imagine, all the basic arithmetic operators work in python ​pretty much like they would in //C//; even the modulus operator. There are, however, two extra ones that might be useful: //​exponentiation//​ and //floor division//:+Well, that was an interesting detour. But let's get back to our numbers. As you might imagine, all the basic arithmetic operators work in //​Python// ​pretty much like they would in //C//; even the modulus operator. There are, however, two extra ones that might be useful: //​exponentiation//​ and //floor division//:
  
 <code python> <code python>
Line 154: Line 154:
 ...     "​and his comrades would chuckle at the sheer treason of it." ...     "​and his comrades would chuckle at the sheer treason of it."
  
->>>​ the length of the string can be obtained using len()+>>> ​the length of the string can be obtained using len()
 >>>​ len(s) >>>​ len(s)
 230 230
Line 190: Line 190:
 </​code>​ </​code>​
  
-== Arrays ​==+== Lists ==
  
-When you think "array", you might be reminded of the constant-sized arrays in //C//. But arrays ​in //Python// are closer in design to the [[https://​en.cppreference.com/​w/​cpp/​container/​vector|std::​vector]] container from //C++//, in that they can be arbitrarily resized at runtime. One difference, however, is that the elements contained in an array do not have to be of the same type (although it would be preferable if they were).+When you think "list", you might be reminded of the constant-sized arrays in //C//. But lists in //Python// are closer in design to the [[https://​en.cppreference.com/​w/​cpp/​container/​vector|std::​vector]] container from //C++//, in that they can be arbitrarily resized at runtime. One difference, however, is that the elements contained in a list do not have to be of the same type (although it would be preferable if they were).
  
 <code python> <code python>
Line 210: Line 210:
 '​December'​ '​December'​
  
-# here, we display ​all months starting with the one indexed 3rd, up until the 3rd from the end+# here, we extract ​all months starting with the one indexed 3rd, up until the 3rd from the end 
 +# obtaining a subset of a list is called slicing
 >>>​ months[3:​-3] >>>​ months[3:​-3]
 ['​April',​ '​May',​ '​June',​ '​July',​ '​August',​ '​September'​] ['​April',​ '​May',​ '​June',​ '​July',​ '​August',​ '​September'​]
  
-# here, we display ​every second month starting with January +# here, we extract ​every second month starting with January 
-# the z in [x:y:z] is basically ​the iteration step+# the z in [x:y:z] is the iteration step
 # in this case, x and y didn't need to be explicitly stated # in this case, x and y didn't need to be explicitly stated
 >>>​ months[0:​12:​2] >>>​ months[0:​12:​2]
Line 222: Line 223:
 ['​January',​ '​March',​ '​May',​ '​July',​ '​September',​ '​November'​] ['​January',​ '​March',​ '​May',​ '​July',​ '​September',​ '​November'​]
  
-# here, we display ​months ranging from the one indexed 6th to the one indexed 0th, in reverse order+# here, we extract ​months ranging from the one indexed 6th to the one indexed 0th (excluding it), in reverse order
 >>>​ months[6:​0:​-1] >>>​ months[6:​0:​-1]
 +['​July',​ '​June',​ '​May',​ '​April',​ '​March',​ '​February'​]
 </​code>​ </​code>​
  
Line 254: Line 256:
 </​code>​ </​code>​
  
-Let's take a closer look at the final two examples. In the first, we used the //Python// equivalent of the //C// ternary operator: ''​it ** 3 if it % 2 == 0 else None''​. This would roughly translate to ''​(it % 2 == 0) ? pow(it, 3) : None''​. Notice that in this example, we either have to have ''​it ** 3''​ or ''​None''​. In other words, we can't drop the ''​else''​. Otherwise, we would get an invalid syntax error. For a similar outcome however, we have the second example. Here, the use of ''​if it % 2 == 1''​ at the end is specific to this type of array initialization and will most likely generate an error in any other contexts.+Let's take a closer look at the final two examples. In the first, we used the //Python// equivalent of the //C// ternary operator: ''​it ​%%**%% 3 if it % 2 == 0 else None''​. This would roughly translate to ''​(it % 2 == 0) ? pow(it, 3) : None''​. Notice that in this example, we either have to have ''​it ** 3''​ or ''​None''​. In other words, we can't drop the ''​else''​. Otherwise, we would get an invalid syntax error. For a similar outcome however, we have the second example. Here, the use of ''​if it % 2 == 1''​ at the end is specific to this type of array initialization and will most likely generate an error in any other context.
  
 Since we know how to initialize an array, and access elements of an array, all that's left is manipulating an array. Since we know how to initialize an array, and access elements of an array, all that's left is manipulating an array.
  
 <code python> <code python>
->>>​ # first, create a simple ​array+>>>​ # first, create a simple ​list
 >>>​ v = list(range(0,​ 20, 2)) >>>​ v = list(range(0,​ 20, 2))
 >>>​ v >>>​ v
Line 265: Line 267:
  
 >>>​ # delete the element with the index 4 >>>​ # delete the element with the index 4
->>>​ # del is a Python built-in keyword and can delete more than just array elements+>>>​ # del is a Python built-in keyword and can delete more than just list elements
 >>>​ del(v[4]) >>>​ del(v[4])
 >>>​ v >>>​ v
Line 290: Line 292:
 [-99, 0, 2, 6, 18, 99] [-99, 0, 2, 6, 18, 99]
  
->>>​ # extend the array with a few more numbers from a range()+>>>​ # extend the list with a few more numbers from a range()
 >>>​ v.extend(range(-5,​ 5, 4)) >>>​ v.extend(range(-5,​ 5, 4))
 >>>​ v >>>​ v
Line 304: Line 306:
 >>>​ v >>>​ v
 [-99, -10, -5, -1, 0, 0, 2, 3, 6, 10, 18, 99] [-99, -10, -5, -1, 0, 0, 2, 3, 6, 10, 18, 99]
 +</​code>​
 +
 +== Tuples ==
 +
 +While lists are variable-sized and any element can be changed, tuples are immutable. Meaning that they can't be changed in any way once they are created. Similarly to arrays, though, slicing still works. Because slicing creates a new tuple (or array) from an existing object, you are not really //​changing//​ anything. We already used a tuple when doing string formatting earlier. They are defined exactly like a list, but using parentheses in stead of brackets. So why should we use tuples if we already have lists? For once, tuples are faster to iterate over than lists. Moreover, sometimes you might want your data to be read-only. For example, when you use the same tuple object as a dictionary key and expect it never to change.
 +
 +<code python>
 +>>>​ # this is how you declare a tuple
 +>>>​ t = ( '​pi',​ 3.1415, True )
 +>>>​ t
 +('​pi',​ 3.1415, True)
 +
 +>>>​ # splicing still works, and we get another tuple
 +>>>​ t[:2]
 +('​pi',​ 3.1415)
 +
 +>>>​ # a list can be generated from the content of a tuple
 +>>>​ list(t)
 +['​pi',​ 3.1415, True]
 +>>>​ list(t) + [ '​e',​ 2.7182, True ]
 +['​pi',​ 3.1415, True, '​e',​ 2.7182, True]
 +
 +>>>​ # similarly, a tuple can be generated from a list
 +>>>​ tuple(list(t) + [ '​e',​ 2.7182, True ])
 +('​pi',​ 3.1415, True, '​e',​ 2.7182, True)
 +
 +>>>​ # tuples can be used as a shortcut to assign multiple values at once
 +>>>​ # many functions in Python return multiple values (how would you do this in C?)
 +>>>​ # by convention, you use _ to signify that you want to ignore a certain value
 +>>>​ t = ('​c',​ 4, False)
 +>>>​ (x, y, _) = t
 +>>>​ x
 +'​c'​
 +>>>​ y
 +4
 </​code>​ </​code>​
  
 == Dictionaries == == Dictionaries ==
 +
 +These are __unordered__ sets of key-value pairs. Each key must have a corresponding value. Also, each key is unique. Dictionaries work pretty much like an array, only that you don't //have// to use numeric indexes, but objects of your choice:
 +
 +<code python>
 +>>>​ # this is how you declare a dictionary (can also be empty)
 +>>>​ ip_addrs = { '​ocw.cs.pub.ro'​ : '​141.85.227.65',​
 +...              '​google.com' ​   : '​142.250.180.206',​
 +...              '​filelist.io' ​  : '​104.21.16.66'​ }
 +
 +>>>​ # blindly accessing elements is usually a bad idea
 +>>>​ ip_addrs['​ocw.cs.pub.ro'​]
 +'​141.85.227.65'​
 +>>>​ ip_addrs['​curs.upb.ro'​]
 +Traceback (most recent call last):
 +  File "<​stdin>",​ line 1, in <​module>​
 +KeyError: '​curs.upb.ro'​
 +
 +>>>​ # better to first check if the key exists in the dictionary
 +>>>​ '​curs.upb.ro'​ in ip_addrs
 +False
 +>>>​ ip_addrs['​curs.upb.ro'​] = '​141.85.241.61'​
 +>>>​ ip_addrs['​curs.upb.ro'​]
 +'​141.85.241.61'​
 +
 +>>>​ # dictionaries also have specific methods, viewable with help()
 +>>>​ # these are a few self-explanatory examples
 +>>>​ ip_addrs.keys()
 +['​google.com',​ '​filelist.io',​ '​curs.upb.ro',​ '​ocw.cs.pub.ro'​]
 +>>>​ ip_addrs.values()
 +['​142.250.180.206',​ '​104.21.16.66',​ '​141.85.241.61',​ '​141.85.227.65'​]
 +>>>​ ip_addrs.items()
 +[('​google.com',​ '​142.250.180.206'​),​ ('​filelist.io',​ '​104.21.16.66'​),​ ('​curs.upb.ro',​ '​141.85.241.61'​),​ ('​ocw.cs.pub.ro',​ '​141.85.227.65'​)]
 +</​code>​
ii/labs/02/tasks/01.1636283154.txt.gz · Last modified: 2021/11/07 13:05 by radu.mantu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0