<jupyter_start><jupyter_text>Programming in Python  Session 1  Aim of the SessionLearn/review the basics- what is ...- how to ...  'Hello World!'<jupyter_code># the culturally-expected introductory statement
print("hello world")
# an example of what you can achieve with Python in just a few lines<jupyter_output><empty_output><jupyter_text>Literals Values of a _type_, presented literally<jupyter_code># example        name       type designation
42             # integer    int
2.016          # float      float*
"Homo sapiens" # string     str
"42"
print(42)
print("hello")<jupyter_output>42
hello<jupyter_text>- int: whole numbers e.g. 1, 1000, 6000000000- float: 'floating point' non-whole numbers e.g. 1.9, 30.01, 10e3, 1e-3- string: ordered sequence of characters, enclosed in quotation marks (single, double, _triple_)<jupyter_code># type conversions

print(type(42))
print(type("42"))<jupyter_output><class 'int'>
<class 'str'><jupyter_text>Aside - CommentsComments are preceded by a ****, and are completely ignored by the python interpreter. Comments can be on their own line or after a line of code.Comments are an incredibly useful way to keep track of what you are doing inyour code. Use comments to document what you do as much as possible, it willpay off in the long run.  Exercises 1<jupyter_code># print some strings
print("print something")
# print some numbers (ints or floats)
print(42, 45.99, 789.999999)
# print multiple values of different types all at once
#   (hints: use comma to separate values with a space, or + to join strings)
print(3545637, "words", "and this", 9866.9877)
# print a string containing quote marks
print('this is my name:"malvika"')<jupyter_output>this is my name:"malvika"<jupyter_text>Variables Store values (information) in memory, and (re-)use them. We give variables names (identifiers) so that we have a means of referring to the information on demand.<jupyter_code># variable assignment is done with '='

myname = "denbi"
print(myname)
myname1 = "this class"
# print(myname1, myname)
myint = 6779
myfloat = 7668.98

print(myint, myfloat)
print("myint value is:", myint, "and myfloat value is:", myfloat)

print("myint value is: %s and myfloat is: %s" % (myfloat, myint))

print("myint value is: {} and myfloat is: {}".format(myfloat, myint))<jupyter_output>myint value is: 6779 and myfloat value is: 7668.98
myint value is: 7668.98 and myfloat is: 6779
myint value is: 7668.98 and myfloat is: 6779<jupyter_text>Variable namingRules:- identifier lookup is case-sensitive  - `myname` & `MyName` are different- must be unique in your working environment  - existing variable will be __over-written without warning__- cannot start with a number, or any special symbol (e.g. $, %, @, -, etc...) except for "_" (underscore), which is OK.- cannot have any spaces or special characters (except for "-" (hyphen) and "_" (underscore))Conventions/good practice:- identifiers (usually) begin with a lowercase letter- followed by letters, numbers, underscores- use a strategy to make reading easier  - `myName`  - `exciting_variable`- long, descriptive > short, vague  String FormattingCreate formatted strings, with variable values substituted in.<jupyter_code># two ways to do it in Python
name = 'Florence'
age = 73
print('%s is %s years old' % (name, age)) # common amongst many programming languages

print('{} is {} years old'.format(name, age)) # perhaps more consistent with stardard Python syntax<jupyter_output>Florence is 73 years old
Florence is 73 years old<jupyter_text>Operators & Operands Using Python as a calculator: `+`, `-`, `/`, `*` etc are _operators_, the values/variables that they work on are _operands_.<jupyter_code># standard mathematical operations can be performed in Python
56+89
67*89.87

print(myint*myfloat)
print(myint/3)

# and some less common ones
print("a"*3)
print("a"+"b")<jupyter_output>51988015.419999994
2259.6666666666665
aaa
ab<jupyter_text>_Note: check out numpy, scipy, stats modules if you want to do a lot of maths_  Data Structures Programming generally requires building/working with much larger and more complex sets of data than the single values/words/sentences that we have looked at so far. In fact, finding ways to operate effectively (and efficiently) on complex structures in order to extract/produce information, _is_ (data) programming.Python has two most commonly-used structures for storing multiple pieces of data - _lists_ and _dictionaries_. Let's look at these, and a few more, now.  Lists<jupyter_code># sequence of entries, in order and of any type
numbers    = [32, 72, 42]
mixed_list = [1, 'b', 3.0, 'd']

print(number)

empty_list = []
another_empty_list = list()

letters = list('abcdefghi')

# accessing list entries

# adding/removing entries

# changing the order of entries

# sequence of entries, in order and of any type
numbers    = [32, 72, 42]
mixed_list = [1, 'b', 3.0, 'd']

#print(numbers)

empty_list = []
another_empty_list = list()

print(empty_list)
empty_list.append("this value")

print(empty_list)
empty_list.append("this value 2")

print(empty_list)
empty_list.append("this value 3")

print(empty_list)
empty_list.append(76890.789)

print(empty_list)

letters = list('abcdefghi')

numbers = [32, 72, 42]

# accessing list entries
print(numbers[1])
print(numbers[0])
print(numbers[-1])

# adding/removing entries
numbers.append(788)

print(numbers)
numbers.remove(42)

print(numbers)
numbers.remove(numbers[1])
print(numbers)

numbers.append(899)
print(numbers)

number_copy = numbers.copy()

number_clone = numbers
print(number_copy)
print(number_clone)
# changing the order of entries
number_copy = numbers.copy()
print(number_copy)

# numbers.clear() #remove everything

print(number_clone)

# changing the order of entries
numbers.reverse()
print(numbers)<jupyter_output>[899, 788, 32]
[899, 788, 32]
[32, 788, 899]<jupyter_text>Objects, Methods, and How To Get Help In Python, everything is an _object_ - some value(s), packaged up with a set of things that can be done with/to it (___methods___), and pieces of information about it (___attributes___). This makes it very easy to perform the most commonly-needed operations for that/those type of value(s). The language has a standard syntax for accessing methods:<jupyter_code>string_object = 'I remember, standing by the wall'
name = 'denbi'
# methods - object.something()
print(string_object.upper())
print(string_object.lower())

print(name.capitalize())
# more...
# dir() and help()
mydir = {}

mydir = {"key1" : "val1", "key4656" : 678.999, 
         "name" : "denbi"}
print(mydir)

print(mydir["name"])
print(mydir["key1"])
# sets<jupyter_output><empty_output><jupyter_text>Exercises 2<jupyter_code># add 'Sally' to the list of students' names
student_names = ['Sandy', 'Pete', 'Richard', 'Rebecca']
student_names.append("Sally")
print(student_names)
# access the fourth entry of the list
print(student_names[3])

# join the list with a new list from another class

other_student_names = ['Sam', 'Fiona', 'Sarah', 
                       'Richard', 'Sarah', 'Matthew']

mixed_student_names = student_names + other_student_names

print("Merged into a new list: %s" % mixed_student_names)

student_names.extend(other_student_names)
print("student_names extended %s" % student_names)
print(set(student_names))
print(list(set(student_names)))<jupyter_output>{'Richard', 'Rebecca', 'Sam', 'Sarah', 'Sally', 'Sandy', 'Fiona', 'Matthew', 'Pete'}
['Richard', 'Rebecca', 'Sam', 'Sarah', 'Sally', 'Sandy', 'Fiona', 'Matthew', 'Pete']<jupyter_text>Dictionaries<jupyter_code># collection of paired information - keys and values
student_marks = {'Alessio': 67, 'Nic': 48, 'Georg': 68}

empty_dict         = {}
another_empty_dict = dict()

student_marks["newkey"] = "newval"
student_marks

student_marks["newkey"] = 99

student_marks.pop("newkey")
print(student_marks)

# accessing dict entries
student_marks['Alessio']

# adding/changing/deleting entries
#print(student_marks.keys())
#print(student_marks.values())
#print(student_marks.items())<jupyter_output>{'Alessio': 67, 'Nic': 48, 'Georg': 68}<jupyter_text>Mutable? Object types can be divided into two categories - mutable & immutable. _Mutable_ objects can be changed 'in-place' - their value can be updated, added to, re-ordered etc without the need to create a whole new object every time. _Immutable_ types cannot be changed in place - once they have a value, this value cannot be altered. though, of course, it can __always__ be overwritten.<jupyter_code># lists are mutable
cities = ['Nairobi', 'Vancouver', 'Wellington', 'Beijing']
cities[2] = 'Heidelberg'

cities.insert(2, 'Wellington')
print(cities)
# strings are immutable
beatles = list("I'd like to be under the sea")
print(beatles[6])<jupyter_output>k<jupyter_text>Looping Time for some real programming. The biggest motivation for researches to learn a programming language is the opportunity to automate repetitive tasks and analyses.For loops define a set of steps that will be carried out for all items in a sequence. The items in the sequence will be taken one-at-a-time, and the loop performed, until there are no more items to process.<jupyter_code>#for season in ['Spring', 'Summer', 'Autumn', 'Winter']
# print season entries one by one

seasons = ['Spring', 'Summer', 'Autumn', 'Winter']

for season in seasons:
    print(season)
print("outside loop: %s" % season)
word = 'python'

for letter in word:
    print(letter.upper())
    
for item in [656, 789, 789, 56]:
    print(item)
# iterating through two lists simultaneously
student_names = ['Sandy', 'Pete', 'Richard', 'Rebecca']
other_student_names = ['Sam', 'Fiona', 'Sarah', 
                       'Richard', 'Sarah', 'Matthew']

rollnumber = [1, 2, 3, 4, 6, 7, 8]

#print(range(len(student_names)))

student_number_dict = {}
for i in range(len(student_names)):
    #print(student_names[i], rollnumber[i])
    student_number_dict[student_names[i]] = rollnumber[i]
    
print(student_number_dict)
# range
print(list(range(0, 4)))

print(list(range(4)))

i = 50
j = 60
print(list(range(i, j+1)))

print(list(range(i, j+1, 3)))
# zip

# enumerate
# list comprehensions<jupyter_output><empty_output><jupyter_text>Conditionals - if, elif, else Looping allows you to perform a common set of operations on multiple pieces of data very quickly. But what if you want to treat the pieces differently, depending on some property or other of the objects?This is the other central part of programming: testing for certain circumstances and changing the treatment of pieces of data accordingly. It is known as _flow control_, as you are controlling the flow of data through your script of operations.  if - elif - else<jupyter_code># use if statements to test for a condition

temperature = 25

if temperature > 30:
    print(True)
    
if temperature > 30:
    print("temperature is > 30")
    print(temperature*120)
    print(True)
else:
    print("temperature is not > 30")
    print(False)

# use else to dictate what happens when the condition isn't met

# use elif to add more conditionals

print('------')
if temperature > 30:
    print('yes')
elif temperature < 30:
    print('temperature is < 30')
else:
    print('temperature is 30')
# list comprehensions with conditionals
namelist1 = ['sara', 'matt', 'ben', 'toby']
namelist2 = ['frank', 'jules', 'james', 'toby']

for name in namelist1:
    for name2 in namelist2:
        if name == name2:
            print(name.capitalize())
       # else:
        #    print(False)
combined_list = namelist1 + namelist2
print(combined_list)
combined_list2 = []

for name in namelist1:
    if name not in combined_list2:
        combined_list2.append(name)
print(combined_list2)

for name2 in namelist2:
    if name2 not in combined_list2:
        combined_list2.append(name2)
    else:
        print("name exists: %s" % name2)
    print(combined_list2)<jupyter_output>['sara', 'matt', 'ben', 'toby']
name exists: toby
['sara', 'matt', 'ben', 'toby', 'frank', 'jules', 'james']
{'fraction_non_alphanumeric': 0.11415220293724966, 'fraction_numerical': 0.028371161548731642, 'mean_word_length': 4.97457627118644, 'pattern_counts': {'":': 0, '<': 50, '<?xml version=': 0, '>': 54, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '285409', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 4116, 'n_tokens_neox': 3756, 'n_words': 1350, 'path': 'Python_course_materials/.ipynb_checkpoints/SwC_python_session-1-checkpoint.ipynb', 'repo_name': 'wyn9191/Python_learning', 'size': '11984'}