4/20/2020

python

** python


Python 3.8.2

https://docs.python.org/3/

-------------------------------------------------------------------------------------

>>> print("Hello world")
Hello world

>>> quit()


>>> # Types of number: int, float, complex
>>> a = 2 # This is a perfect number
>>> type(a)
class 'int'
>>> a
2
>>> print(a)
2


>>> e = 2.718281828 # Floats
>>> type(e)
class 'float'


>>> z = 2-6.1j # Complex Numbers
>>> type(z)
class 'complex'
>>> z.real
2.0
>>> z.imag
-6.1

-------------------------------------------------------------------------------------

` Strings


>>> message = "Meet me tonight."
>>> print(message)
Meet me tonight.


>>> message2 = 'The clock strikes at midnight.'
>>> print(message2)
The clock strikes at midnight.


>>> message3 = "I'm looking for someone to share in an adventure."
>>> print(message3)
I'm looking for someone to share in an adventure.


>>> message4 = 'The phrase "Beam me up, Scotty" was never said on Star Trek.'
>>> print(message4)
The phrase "Beam me up, Scotty" was never said on Star Trek.



>>> movie_quote = """One of my favorite lines from The Godfather is:
"I'm going to make him an offer he can't refuse."
Do you know who said this?"""
>>> print(movie_quote)
One of my favorite lines from The Godfather is:
"I'm going to make him an offer he can't refuse."
Do you know who said this?

-------------------------------------------------------------------------------------


` Arithmetic Operations


>>> # Numbers: int, float, complex
>>> # Operations: + - * /
>>>
>>> x = 28 # int
>>> y = 11.0 # float
>>> float(28)
28.0
>>> 3.14 # float
3.14
>>> int(3.14)
3
>>> # ints are narrower than floats
>>> # floats are wider than ints


>>> x = 1.132 # float
>>> 1.132 + 0J
(1.132+0j)
>>> complex(1.132)
(1.132+0j)
>>> float(1.132 + 0j)
Traceback (most recent call last):
  File "", line 1, in
    float(1.132 + 0j)
TypeError: can't convert complex to float
>>> # floats are narrower than complex numbers
>>> # complex numbers are wider than floats


# Arithmetic Operations


>>> # floats are narrower than complex numbers
>>> # complex numbers are wider than floats
>>>
>>> a = 1 # int
>>> b = 2.0 #float
>>> c = 3 + 0j # complex number
>>>
>>> # Rule: Widen numbers so they're the same type
>>>
>>> # Addition
>>> a + b # int + float
3.0
>>> # Subtraction
>>> b - a # float - int
1.0
>>> # Multiplication
>>> a * 7 # int * int
7
>>> # Division
>>> c / b # complex / float
(1.5+0j)
>>> 16/5
3.2
>>> 20/5
4.0
>>> 16 % 5
1
>>> 16//5
3
>>> 2/0
Traceback (most recent call last):
  File "", line 1, in
    2/0
ZeroDivisionError: division by zero

-------------------------------------------------------------------------------------

` Interactive Help


>>> dir() # Short for "directory"
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']

>>> dir(__builtins__)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '_', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']

>>> help(pow)
Help on built-in function pow in module builtins:

pow(base, exp, mod=None)
    Equivalent to base**exp with 2 arguments or base**exp % mod with 3 arguments
 
    Some types, such as ints, are able to use a more efficient algorithm when
    invoked using the three argument form.

>>> pow(2,10)
1024

>>> 2**10
1024

>>> help(hex)
Help on built-in function hex in module builtins:

hex(number, /)
    Return the hexadecimal representation of an integer.
 
    >>> hex(12648430)
    '0xc0ffee'

>>> hex(10)
'0xa'


# List of modules

>>> help('modules')

Please wait a moment while I gather a list of all available modules...

__future__          binhex              fnmatch             random
__main__            bisect              format              re
_abc                brain_argparse      formatter           redirector
_ast                brain_attrs         fractions           replace
_asyncio            brain_builtin_inference ftplib              reprlib
_bisect             brain_collections   functools           rlcompleter
_blake2             brain_crypt         gc                  rpc
_bootlocale         brain_curses        genericpath         run
_bz2                brain_dataclasses   getopt              runpy
_codecs             brain_dateutil      getpass             runscript
_codecs_cn          brain_fstrings      gettext             sched
_codecs_hk          brain_functools     glob                scrolledlist
_codecs_iso2022     brain_gi            grep                search
_codecs_jp          brain_hashlib       gzip                searchbase
_codecs_kr          brain_http          hashlib             searchengine
_codecs_tw          brain_io            heapq               secrets
_collections        brain_mechanize     help                select
_collections_abc    brain_multiprocessing help_about          selectors
_compat_pickle      brain_namedtuple_enum history             setuptools
_compression        brain_nose          hmac                shelve
_contextvars        brain_numpy_core_fromnumeric html                shlex
_csv                brain_numpy_core_function_base http                shutil
_ctypes             brain_numpy_core_multiarray hyperparser         sidebar
_ctypes_test        brain_numpy_core_numeric idle                signal
_datetime           brain_numpy_core_numerictypes idle_test           site
_decimal            brain_numpy_core_umath idlelib             six
_dummy_thread       brain_numpy_ndarray imaplib             smtpd
_elementtree        brain_numpy_random_mtrand imghdr              smtplib
_functools          brain_numpy_utils   imp                 sndhdr
_hashlib            brain_pkg_resources importlib           socket
_heapq              brain_pytest        inspect             socketserver
_imp                brain_qt            io                  sqlite3
_io                 brain_random        iomenu              squeezer
_json               brain_re            ipaddress           sre_compile
_locale             brain_six           isort               sre_constants
_lsprof             brain_ssl           itertools           sre_parse
_lzma               brain_subprocess    json                ssl
_markupbase         brain_threading     keyword             stackviewer
_md5                brain_typing        lazy_object_proxy   stat
_msi                brain_uuid          lib2to3             statistics
_multibytecodec     browser             linecache           statusbar
_multiprocessing    builtins            locale              string
_opcode             bz2                 logging             stringprep
_operator           cProfile            lzma                struct
_osx_support        calendar            macosx              subprocess
_overlapped         calltip             mailbox             sunau
_pickle             calltip_w           mailcap             symbol
_py_abc             cgi                 mainmenu            symtable
_pydecimal          cgitb               marshal             sys
_pyio               chunk               math                sysconfig
_queue              cmath               mccabe              tabnanny
_random             cmd                 mimetypes           tarfile
_sha1               code                mmap                telnetlib
_sha256             codecontext         modulefinder        tempfile
_sha3               codecs              msilib              test
_sha512             codeop              msvcrt              textview
_signal             collections         multicall           textwrap
_sitebuiltins       colorama            multiprocessing     this
_socket             colorizer           netrc               threading
_sqlite3            colorsys            nntplib             time
_sre                compileall          nt                  timeit
_ssl                concurrent          ntpath              tkinter
_stat               config              nturl2path          token
_statistics         config_key          numbers             tokenize
_string             configdialog        opcode              tooltip
_strptime           configparser        operator            trace
_struct             contextlib          optparse            traceback
_symtable           contextvars         os                  tracemalloc
_testbuffer         copy                outwin              tree
_testcapi           copyreg             parenmatch          tty
_testconsole        crypt               parser              turtle
_testimportmultiple csv                 pathbrowser         turtledemo
_testmultiphase     ctypes              pathlib             types
_thread             curses              pdb                 typing
_threading_local    dataclasses         percolator          undo
_tkinter            datetime            pickle              unicodedata
_tracemalloc        dbm                 pickletools         unittest
_warnings           debugger            pip                 urllib
_weakref            debugger_r          pipes               uu
_weakrefset         debugobj            pkg_resources       uuid
_winapi             debugobj_r          pkgutil             venv
_xxsubinterpreters  decimal             platform            warnings
abc                 delegator           plistlib            wave
aifc                difflib             poplib              weakref
antigravity         dis                 posixpath           webbrowser
argparse            distutils           pprint              window
array               doctest             profile             winreg
ast                 dummy_threading     pstats              winsound
astroid             dynoption           pty                 wrapt
asynchat            easy_install        py_compile          wsgiref
asyncio             editor              pyclbr              xdrlib
asyncore            email               pydoc               xml
atexit              encodings           pydoc_data          xmlrpc
audioop             ensurepip           pyexpat             xxsubtype
autocomplete        enum                pylint              zipapp
autocomplete_w      errno               pyparse             zipfile
autoexpand          faulthandler        pyshell             zipimport
base64              filecmp             query               zlib
bdb                 fileinput           queue               zoomheight
binascii            filelist            quopri              zzdummy

Enter any module name to get more help.  Or, type "modules spam" to search
for modules whose name or summary contain the string "spam".


>>> import math

>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'math']

>>> dir(math)
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']

>>> help(radians)
Traceback (most recent call last):
  File "", line 1, in
    help(radians)
NameError: name 'radians' is not defined

>>> help(math.radians)
Help on built-in function radians in module math:

radians(x, /)
    Convert angle x from degrees to radians.

>>> math.radians(180)
3.141592653589793


-------------------------------------------------------------------------------------

` Booleans



>>> # Boolean valuse: True, False
>>>
>>> True
True

>>> true
Traceback (most recent call last):
  File "", line 1, in
    true
NameError: name 'true' is not defined

>>> False
False

>>> false
Traceback (most recent call last):
  File "", line 1, in
    false
NameError: name 'false' is not defined

>>> a = 5

>>> b = 10

>>> a == b
False

>>> a != b
True

>>> a > b
False

>>> a < b
True

>>> type(True)


>>> type(False)



>>> bool(12)
True

>>> bool(-2.14)
True

>>> bool(0)
False

>>> bool("Python")
True

>>> bool(" ")
True

>>> bool("")
False


` Boolean Conversions

- trivial -> False
- non-trivial -> True



>>> str(True)
'True'

>>> str(False)
'False'

>>> int(True)
1

>>> int(False)
0

>>> 10 + True
11

>>> 10 * False
0


- 1 <-> True
- 0 <-> False


-------------------------------------------------------------------------------------

` Datetimes


Help on class date in module datetime:

class date(builtins.object)
 |  date(year, month, day) --> date object
 |
 |  Methods defined here:
 |
 |  __add__(self, value, /)
 |      Return self+value.
 |
 |  __eq__(self, value, /)
 |      Return self==value.
 |
 |  __format__(...)
 |      Formats self with strftime.
 |
 |  __ge__(self, value, /)
 |      Return self>=value.
 |
 |  __getattribute__(self, name, /)
 |      Return getattr(self, name).
 |
 |  __gt__(self, value, /)
 |      Return self>value.
 |
 |  __hash__(self, /)
 |      Return hash(self).
 |
 |  __le__(self, value, /)
 |      Return self<=value.
 |
 |  __lt__(self, value, /)
 |      Return self |
 |  __ne__(self, value, /)
 |      Return self!=value.
 |
 |  __radd__(self, value, /)
 |      Return value+self.
 |
 |  __reduce__(...)
 |      __reduce__() -> (cls, state)
 |
 |  __repr__(self, /)
 |      Return repr(self).
 |
 |  __rsub__(self, value, /)
 |      Return value-self.
 |
 |  __str__(self, /)
 |      Return str(self).
 |
 |  __sub__(self, value, /)
 |      Return self-value.
 |
 |  ctime(...)
 |      Return ctime() style string.
 |
 |  isocalendar(...)
 |      Return a 3-tuple containing ISO year, week number, and weekday.
 |
 |  isoformat(...)
 |      Return string in ISO 8601 format, YYYY-MM-DD.
 |
 |  isoweekday(...)
 |      Return the day of the week represented by the date.
 |      Monday == 1 ... Sunday == 7
 |
 |  replace(...)
 |      Return date with new specified fields.
 |
 |  strftime(...)
 |      format -> strftime() style string.
 |
 |  timetuple(...)
 |      Return time tuple, compatible with time.localtime().
 |
 |  toordinal(...)
 |      Return proleptic Gregorian ordinal.  January 1 of year 1 is day 1.
 |
 |  weekday(...)
 |      Return the day of the week represented by the date.
 |      Monday == 0 ... Sunday == 6
 |
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |
 |  fromisocalendar(...) from builtins.type
 |      int, int, int -> Construct a date from the ISO year, week number and weekday.
 |   
 |      This is the inverse of the date.isocalendar() function
 |
 |  fromisoformat(...) from builtins.type
 |      str -> Construct a date from the output of date.isoformat()
 |
 |  fromordinal(...) from builtins.type
 |      int -> date corresponding to a proleptic Gregorian ordinal.
 |
 |  fromtimestamp(timestamp, /) from builtins.type
 |      Create a date from a POSIX timestamp.
 |   
 |      The timestamp is a number, e.g. created via time.time(), that is interpreted
 |      as local time.
 |
 |  today(...) from builtins.type
 |      Current date or datetime:  same as self.__class__.fromtimestamp(time.time()).
 |
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  day
 |
 |  month
 |
 |  year
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |
 |  max = datetime.date(9999, 12, 31)
 |
 |  min = datetime.date(1, 1, 1)
 |
 |  resolution = datetime.timedelta(days=1)




>>> han = datetime.date(1970, 1, 31)

>>> print(han)
1970-01-31

>>> print(han.year)
1970

>>> print(han.month)
1

>>> print(han.day)
31

>>> dir(datetime)
['MAXYEAR', 'MINYEAR', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'date', 'datetime', 'datetime_CAPI', 'sys', 'time', 'timedelta', 'timezone', 'tzinfo']

>>> mill = datetime.date(2000,1,1)

>>> dt = datetime.timedelta(100)

>>> print(mill + dt)
2000-04-10



` Default format : yyyy-mm-dd

>>> print(han)
1970-01-31



>>> # Day-name, Month-name Day-#, Year
>>>
>>> print(han.strftime("%A, %B %d, %Y"))
Saturday, January 31, 1970

>>> message = "HAN was born on {:%A, %B, %d, %Y}."

>>> print(message.format(han))
HAN was born on Saturday, January, 31, 1970.

>>> dir(datetime)
['MAXYEAR', 'MINYEAR', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'date', 'datetime', 'datetime_CAPI', 'sys', 'time', 'timedelta', 'timezone', 'tzinfo']

>>> launch_date = datetime.date(2017, 3, 30)

>>> launch_time = datetime.time(22, 27, 0)

>>> launch_datetime = datetime.datetime(2017, 3, 30, 22, 27, 0)

>>> print(launch_date)
2017-03-30

>>> print(launch_time)
22:27:00

>>> print(launch_datetime)
2017-03-30 22:27:00

>>> print(launch_time.hour)
22

>>> print(launch_time.minute)
27

>>> print(launch_time.second)
0

>>> print(launch_datetime.year)
2017

>>> print(launch_datetime.month)
3

>>> print(launch_datetime.day)
30

>>> print(launch_datetime.hour)
22

>>> print(launch_datetime.minute)
27

>>> print(launch_datetime.second)
0



` Access current datetime:

- Module : datetime
- Class : datetime
- Method : today()


>>> now = datetime.datetime.today()

>>> print(now)
2020-04-21 16:09:15.982615

>>> print(now.microsecond)
982615



` Convert Strings to datetimes

- Module : datetime
- Class : datetime
- Method : strptime()


>>> moon_landing = "7/20/1969"

>>> moon_landing_datetime = datetime.datetime.strptime(moon_landing, "%m/%d/%Y")

>>> print(moon_landing_datetime)
1969-07-20 00:00:00

>>> print(type(moon_landing_datetime))


-------------------------------------------------------------------------------------


` If, then, else


# Collect string / test length

input_real = input("Please enter a test string: ")

if len(input_real) < 5:
    print("Your string is too short.")
    print("Please enter a string with at least 5 characters.")

>>>
=========== RESTART: C:/Users/purunet/Documents/py/test_of_length.py ===========
Please enter a test string: dir
Your string is too short.
Please enter a string with at least 5 characters.

>>>
=========== RESTART: C:/Users/purunet/Documents/py/test_of_length.py ===========
Please enter a test string: python


# Prompt user to enter number / test if even or odd

input_real = input("Please enter an integer: ")
number = int(input_real)

if number % 2 == 0:
    print("Your number is even.")
else:
    print("Your number is odd.")

>>>
============= RESTART: C:/Users/purunet/Documents/py/even_or_odd.py ============
Please enter an integer: 5
Your number is odd.
>>>
============= RESTART: C:/Users/purunet/Documents/py/even_or_odd.py ============
Please enter an integer: 2
Your number is even.
>>>


` elif = "else if"


# Scalene triangle: All sides have different lengths.
# Isosceles triangle: Two sides have the same length.
# Equilateral triangle: All sides are equal.

a = int(input("The length of side a = "))
b = int(input("The length of side b = "))
c = int(input("The length of side c = "))

if a != b and b !=c and a != c:
    print("This is a scalene triangle.")
elif a == b and b == c:
    print("This is an equilateral triangle.")
else:
    print("This is an isosceles triangle.")


>>>
================= RESTART: C:/Users/purunet/Documents/py/SIE.py ================
The length of side a = 3
The length of side b = 4
The length of side c = 5
This is a scalene triangle.
>>>
================= RESTART: C:/Users/purunet/Documents/py/SIE.py ================
The length of side a = 3
The length of side b = 3
The length of side c = 5
This is an isosceles triangle.
>>>
================= RESTART: C:/Users/purunet/Documents/py/SIE.py ================
The length of side a = 3
The length of side b = 3
The length of side c = 3

This is an equilateral triangle.

-------------------------------------------------------------------------------------

` Functions

>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']

>>> def f():
pass

>>> f()
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'f']

>>> f


>>> def ping():
return "Ping!!"

>>> ping()
'Ping!!'

>>> x = ping()

>>> print(x)
Ping!!

>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'f', 'ping', 'x']

>>>

>>> import math

>>> dir(math)
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']

>>> math.pi
3.141592653589793

>>> def volume(r):
"""Returns the volume of a sphere with radius r."""
v = (4.0/3.0) * math.pi * r**3
return v

>>> volume(3)
113.09733552923254

>>> volume()
Traceback (most recent call last):
  File "", line 1, in
    volume()
TypeError: volume() missing 1 required positional argument: 'r'

>>> help(volume)
Help on function volume in module __main__:

volume(r)
    Returns the volume of a sphere with radius r.

>>> def triangle_area(b, h):
"""Returns the area of a triangle with base b and height h."""
return 0.5 * b * h

>>> triangle_area(5, 10)
25.0


- 1 inch = 2.54 cm
- 1 foot = 12 inches

>>> def cm(feet = 0, inches = 0):
"""Converts a length from feet and inches to centimeters."""
inches_to_cm = inches * 2.54
feet_to_cm = feet * 12 * 2.54
return inches_to_cm + feet_to_cm

>>> cm(feet = 5)
152.4

>>> cm(inches = 10)
25.4

>>> cm(feet = 5, inches = 10)
177.8

>>> cm(feet = 10, inches = 5)
317.5


` Types of Arguments:
Keyword
Required

>>> def g(x = 0, y):
return x+y
SyntaxError: non-default argument follows default argument

>>> def g(y, x = 0):
return x+y

>>> g(10)
10

>>> g(10, x=5)
15

-------------------------------------------------------------------------------------

`Sets

>>> ex = set()

>>> dir(ex)
['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__init_subclass__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']

>>> help(ex.add)
Help on built-in function add:

add(...) method of builtins.set instance
    Add an element to a set.
 
    This has no effect if the element is already present.

>>> ex.add(10)

>>> ex.add(False)

>>> ex.add(3.14159)

>>> ex.add("Thorium")

>>>

>>> ex
{False, 10, 3.14159, 'Thorium'}

>>> ex.add(10)

>>> ex
{False, 10, 3.14159, 'Thorium'}

>>> len(ex)
4

>>> help(ex.remove)
Help on built-in function remove:

remove(...) method of builtins.set instance
    Remove an element from a set; it must be a member.
 
    If the element is not a member, raise a KeyError.

>>> ex.remove(10)

>>> len(ex)
3

>>> ex
{False, 3.14159, 'Thorium'}

>>> ex.remove(20)
Traceback (most recent call last):
  File "", line 1, in
    ex.remove(20)
KeyError: 20

>>> help(ex.discard)
Help on built-in function discard:

discard(...) method of builtins.set instance
    Remove an element from a set if it is a member.
 
    If the element is not a member, do nothing.

>>> ex.discard(20)

>>>

>>> ex2 = set([30, True, 2.71828, "Helium"])

>>> len(ex2)
4

>>> ex2.clear()

>>> len(ex2)
0


- Union = A∪B
- Intersection = A∩B

>>> # Integers 1 ~ 10

>>> odds = set([1, 3, 5, 7, 9])

>>> evens = set([2, 4, 6, 8, 10])

>>> primes = set([2, 3, 5, 7])

>>> composites = set([4, 6, 8, 9, 10])

>>> odds.union(evens)
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

>>> evens.union(odds)
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

>>> odds
{1, 3, 5, 7, 9}

>>> evens
{2, 4, 6, 8, 10}

>>> odds.intersection(primes)
{3, 5, 7}

>>> primes.intersection(evens)
{2}

>>> evens.intersection(odds)
set()

>>> primes.union(composites)
{2, 3, 4, 5, 6, 7, 8, 9, 10}

>>> 2 in primes
True

>>> 4 in odds
False

>>> 9 not in evens
True

>>> dir(primes)
['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__init_subclass__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']


-------------------------------------------------------------------------------------

` Lists

>>> ex = list()

>>> ex = []

>>> primes = [2, 3, 5, 7, 11, 13]

>>> primes.append(17)

>>> primes.append(19)

>>> primes
[2, 3, 5, 7, 11, 13, 17, 19]

>>> primes[0]
2

>>> primes[1]
3

>>> primes[2]
5

>>> primes[-1]
19

>>> primes[-2]
17

>>> primes[-9]
Traceback (most recent call last):
  File "", line 1, in
    primes[-9]
IndexError: list index out of range

>>> primes[-8]
2


#Slicing

>>> primes
[2, 3, 5, 7, 11, 13, 17, 19]

>>> primes[2:5]
[5, 7, 11]

>>> primes[0:6]
[2, 3, 5, 7, 11, 13]


>>> ex = [256, True, "Alpha", 1.732, [64, False]]

>>> rolls = [4, 7, 2, 7, 12, 4, 7]

>>> rolls
[4, 7, 2, 7, 12, 4, 7]


>>> numbers = [1, 2, 3]

>>> letters = ['a', 'b', 'c']

>>> numbers + letters
[1, 2, 3, 'a', 'b', 'c']

>>> letters + numbers
['a', 'b', 'c', 1, 2, 3]

>>>
>>> # Concatenation
>>>

>>> numbers
[1, 2, 3]

>>> letters
['a', 'b', 'c']

>>>
>>> dir(numbers)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>> help(numbers.reverse)
Help on built-in function reverse:

reverse() method of builtins.list instance
    Reverse *IN PLACE*.

-------------------------------------------------------------------------------------

` Dictionaries


>>> # FriendFace post
>>> # user_id = 210
>>> # message = "D4 E5 C3 C3 G7"
>>> # language = "English"
>>> # datetime = "20230215T124231Z"
>>> # location = (44.120233, -103.213332)

>>> post = {"user_id":210, "message":"D4 E5 C3 C3 G7", "language":"English", "datetime":"20230215T124231Z", "location":(44.120233, -103.213332)}

>>> type(post)
class 'dict'

>>> post2 = dict(message="SS Cotopaxi", language="English")

>>> print(post2)
{'message': 'SS Cotopaxi', 'language': 'English'}

>>> post2["user_id"] = 210

>>> post2["datetime"] = "19771116T093001Z"

>>> print(post2)
{'message': 'SS Cotopaxi', 'language': 'English', 'user_id': 210, 'datetime': '19771116T093001Z'}



` Accessing Data in Dictionaries

>>> print(post['message'])
D4 E5 C3 C3 G7

>>> print(post2['location'])
Traceback (most recent call last):
  File "", line 1, in
    print(post2['location'])
KeyError: 'location'

>>>

>>> if 'location' in post2:
print(post2['location'])
else:
print("The post does not contain a location value.")


The post does not contain a location value.

>>>
>>> try:
print(post2['location'])
except KeyError:
print("The post does not have a location.")


The post does not have a location.

>>> dir(post2)
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

>>> help(post2.get)
Help on built-in function get:

get(key, default=None, /) method of builtins.dict instance
    Return the value for key if key is in the dictionary, else default.

>>> loc = post2.get('location', None)

>>> print(loc)
None


>>> print(post)
{'user_id': 210, 'message': 'D4 E5 C3 C3 G7', 'language': 'English', 'datetime': '20230215T124231Z', 'location': (44.120233, -103.213332)}


>>> for key in post.keys():
value = post[key]
print(key, "=", value)


user_id = 210
message = D4 E5 C3 C3 G7
language = English
datetime = 20230215T124231Z
location = (44.120233, -103.213332)


>>> for key, value in post.items():
print(key, "=", value)


user_id = 210
message = D4 E5 C3 C3 G7
language = English
datetime = 20230215T124231Z
location = (44.120233, -103.213332)

>>> dir(post)
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']


-------------------------------------------------------------------------------------

` Tuples

--------------------------------------------------------------------------------

# List example
prime_numbers = [2, 3, 5, 7, 11, 13, 17]

# Tuple example
perfect_squares = (1, 4, 9, 16, 25, 36)

# Display lengths
print("# Primes = ", len(prime_numbers))
print("# Squares = ", len(perfect_squares))

print(80*"-")

# Iterate over both sequences
for p in prime_numbers:
    print("Prime: ", p)

print(80*"-")

for n in perfect_squares:
    print("Square: ", n)

print(80*"-")

print("List methods")
print(dir(prime_numbers))
print(80*"-")
print("Tuple methods")
print(dir(perfect_squares))

print(80*"-")

import sys

print(dir(sys))
print(80*"-")
print(help(sys.getsizeof))
print(80*"-")

list_eg = [1, 2, 3, "a", "b", "c", True, 3.14159]
tuple_eg = (1, 2, 3, "a", "b", "c", True, 3.14159)

print("List size = ", sys.getsizeof(list_eg))
print("Tuple size = ", sys.getsizeof(tuple_eg))

--------------------------------------------------------------------------------

=============== RESTART: C:/Users/purunet/Documents/py/tuple1.py ===============
# Primes =  7
# Squares =  6
--------------------------------------------------------------------------------
Prime:  2
Prime:  3
Prime:  5
Prime:  7
Prime:  11
Prime:  13
Prime:  17
--------------------------------------------------------------------------------
Square:  1
Square:  4
Square:  9
Square:  16
Square:  25
Square:  36
--------------------------------------------------------------------------------
List methods
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
--------------------------------------------------------------------------------
Tuple methods
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
--------------------------------------------------------------------------------
['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '__unraisablehook__', '_base_executable', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_enablelegacywindowsfsencoding', '_framework', '_getframe', '_git', '_home', '_xoptions', 'addaudithook', 'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix', 'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth', 'getallocatedblocks', 'getcheckinterval', 'getdefaultencoding', 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'getwindowsversion', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'is_finalizing', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'pycache_prefix', 'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setcheckinterval', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info', 'unraisablehook', 'version', 'version_info', 'warnoptions', 'winver']
--------------------------------------------------------------------------------
Help on built-in function getsizeof in module sys:

getsizeof(...)
    getsizeof(object [, default]) -> int
 
    Return the size of object in bytes.

None
--------------------------------------------------------------------------------
List size =  60
Tuple size =  52
>>>


` Lists
- Add data
- Remove data
- Change data


` Tuples
- Cannot be changed
- "Immutable"
- Made quickly


--------------------------------------------------------------------------------

import timeit


list_test = timeit.timeit(stmt="[1,2,3,4,5]", number=1000000)
tuple_test = timeit.timeit(stmt="(1,2,3,4,5)", number=1000000)


print("List time: ", list_test)
print("Tuple time: ", tuple_test)

print(80*"-")

empty_tuple = ()
test1 = ("a")
test2 = ("a",)
test3 = ("a", "b")
test4 = ("a", "b", "c")

print(empty_tuple)
print(test1)
print(test2)
print(test3)
print(test4)

--------------------------------------------------------------------------------
=============== RESTART: C:/Users/purunet/Documents/py/tuple1.py ===============
List time:  0.11906162499999995
Tuple time:  0.016417991999999937
--------------------------------------------------------------------------------
()
a
('a',)
('a', 'b')
('a', 'b', 'c')

--------------------------------------------------------------------------------

` Alternative Construction of Tuples

test1 = 1,
test2 = 1, 2
test3 = 1, 2, 3

print(test1)
print(test2)
print(test3)

print(type(test1))
print(type(test2))
print(type(test3))

--------------------------------------------
(1,)
(1, 2)
(1, 2, 3)
class 'tuple'
class 'tuple'
class 'tuple'


--------------------------------------------


` Tuples with 1 Element


` Tuple Assignment

--------------------------------------------
# (age, country, knows_python)

survey = (27, "Vietnam", True)

age = survey[0]
country = survey[1]
knows_python = survey[2]

print("Age = ", age)
print("Country = ", country)
print("Knows Python?", knows_python)

print(80*"-")

survey2 = (21, "SwitzerLand", False)
age, country, knows_python = survey2


print("Age = ", age)
print("Country = ", country)
print("Knows Python?", knows_python)

country = ("Australia")
print(country)


country = ("Australia",)
print(country)

--------------------------------------------

=============== RESTART: C:/Users/purunet/Documents/py/tuple1.py ===============
Age =  27
Country =  Vietnam
Knows Python? True
--------------------------------------------------------------------------------
Age =  21
Country =  SwitzerLand
Knows Python? False
Australia
('Australia',)

--------------------------------------------

>>> a, b, c = (1, 2, 3, 4)
Traceback (most recent call last):
  File "", line 1, in
    a, b, c = (1, 2, 3, 4)
ValueError: too many values to unpack (expected 3)

>>> x , y, z = (1, 2)
Traceback (most recent call last):
  File "", line 1, in
    x , y, z = (1, 2)
ValueError: not enough values to unpack (expected 3, got 2)

-------------------------------------------------------------------------------------

` Logging


- Purpose : Record progress and problems ...

- Levels : Debug, Info, Warning, Error, Critical 


>>> import logging

>>> dir(logging)

['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR', 'FATAL', 'FileHandler', 'Filter', 'Filterer', 'Formatter', 'Handler', 'INFO', 'LogRecord', 'Logger', 'LoggerAdapter', 'Manager', 'NOTSET', 'NullHandler', 'PercentStyle', 'PlaceHolder', 'RootLogger', 'StrFormatStyle', 'StreamHandler', 'StringTemplateStyle', 'Template', 'WARN', 'WARNING', '_STYLES', '_StderrHandler', '__all__', '__author__', '__builtins__', '__cached__', '__date__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__status__', '__version__', '_acquireLock', '_addHandlerRef', '_checkLevel', '_defaultFormatter', '_defaultLastResort', '_handlerList', '_handlers', '_levelToName', '_lock', '_logRecordFactory', '_loggerClass', '_nameToLevel', '_register_at_fork_reinit_lock', '_releaseLock', '_removeHandlerRef', '_showwarning', '_srcfile', '_startTime', '_str_formatter', '_warnings_showwarning', 'addLevelName', 'atexit', 'basicConfig', 'captureWarnings', 'collections', 'critical', 'currentframe', 'debug', 'disable', 'error', 'exception', 'fatal', 'getLevelName', 'getLogRecordFactory', 'getLogger', 'getLoggerClass', 'info', 'io', 'lastResort', 'log', 'logMultiprocessing', 'logProcesses', 'logThreads', 'makeLogRecord', 'os', 'raiseExceptions', 're', 'root', 'setLogRecordFactory', 'setLoggerClass', 'shutdown', 'sys', 'threading', 'time', 'traceback', 'warn', 'warning', 'warnings', 'weakref']

>>>


- Level : Numeric Value

- NOTSET : 0

- DEBUG : 10

- INFO : 20

- WARNING : 30

- ERROR : 40

- CRITICAL : 50


==========================================

import logging

# Creat and Configure logger
logging.basicConfig(filename = "H:\\python\\LinuxerHAN.log")
logger = logging.getLogger()

# Test the logger
logger.info("My First message.")

print(logger.level)

==========================================
=============== RESTART: C:/Users/purunet/Documents/py/message.py ==============
30

==========================================

import logging

# Creat and Configure logger
logging.basicConfig(filename = "H:\\python\\LinuxerHAN.log", level = logging.DEBUG)
logger = logging.getLogger()

# Test the logger
logger.info("My First message.")

print(logger.level)

==========================================

=============== RESTART: C:/Users/purunet/Documents/py/message.py ==============
10


LinuxerHAN.log : INFO:root:My First message.


==========================================

import logging

# Creat and Configure logger
LOG_FORMAT = "%(levelname)s %(asctime)s - %(message)s"
logging.basicConfig(filename = "H:\\python\\LinuxerHAN.log",
                    level = logging.DEBUG,
                    format = LOG_FORMAT)
logger = logging.getLogger()

# Test the logger
logger.info("My First message.")

print(logger.level)

==========================================

=============== RESTART: C:/Users/purunet/Documents/py/message.py ==============
10

LinuxerHAN.log : INFO 2020-04-25 13:09:05,946 - My First message.


==========================================

import logging

# Creat and Configure logger
LOG_FORMAT = "%(levelname)s %(asctime)s - %(message)s"
logging.basicConfig(filename = "H:\\python\\LinuxerHAN.log",
                    level = logging.DEBUG,
                    format = LOG_FORMAT,
                    filemode = 'w')
logger = logging.getLogger()

# Test the logger
logger.info("My Second message.")

==========================================

LinuxerHAN.log : INFO 2020-04-25 13:11:28,364 - My Second message.


==========================================

import logging

# Creat and Configure logger
LOG_FORMAT = "%(levelname)s %(asctime)s - %(message)s"
logging.basicConfig(filename = "H:\\python\\LinuxerHAN.log",
                    level = logging.DEBUG,
                    format = LOG_FORMAT,
                    filemode = 'w')
logger = logging.getLogger()

# Test message
logger.debug("This is a harmless debug message.")
logger.info("Just some useful info.")
logger.warning("I'm sorry, but I can't do that, Dave.")
logger.error("Did you just try to divide by zero?")
logger.critical("The entire internet is down!!")

==========================================

LinuxerHAN.log :

DEBUG 2020-04-25 13:14:40,053 - This is a harmless debug message.
INFO 2020-04-25 13:14:40,054 - Just some useful info.
WARNING 2020-04-25 13:14:40,054 - I'm sorry, but I can't do that, Dave.
ERROR 2020-04-25 13:14:40,054 - Did you just try to divide by zero?
CRITICAL 2020-04-25 13:14:40,054 - The entire internet is down!!


==========================================

import logging

# Creat and Configure logger
LOG_FORMAT = "%(levelname)s %(asctime)s - %(message)s"
logging.basicConfig(filename = "H:\\python\\LinuxerHAN.log",
                    level = logging.ERROR,
                    format = LOG_FORMAT,
                    filemode = 'w')
logger = logging.getLogger()

# Test message
logger.debug("This is a harmless debug message.")
logger.info("Just some useful info.")
logger.warning("I'm sorry, but I can't do that, Dave.")
logger.error("Did you just try to divide by zero?")
logger.critical("The entire internet is down!!")

==========================================

LinuxerHAN.log :

ERROR 2020-04-25 13:16:17,550 - Did you just try to divide by zero?
CRITICAL 2020-04-25 13:16:17,550 - The entire internet is down!!


==========================================

import logging
import math

# Creat and Configure logger
LOG_FORMAT = "%(levelname)s %(asctime)s - %(message)s"
logging.basicConfig(filename = "H:\\python\\LinuxerHAN.log",
                    level = logging.DEBUG,
                    format = LOG_FORMAT,
                    filemode = 'w')
logger = logging.getLogger()

def quadratic_formula(a, b, c):
    """Return the solutions to the equation ax^2 + bx + c = 0."""
    logger.info("quadratic_formula({0}, {1}, {2})".format(a, b, c))

    # Compute the discriminant
    logger.debug("# Compute the discriminant")
    disc = b**2 - 4*a*c

    # Compute the two roots
    logger.debug("# Compute the two roots")
    root1 = (-b + math.sqrt(disc)) / (2*a)
    root2 = (-b - math.sqrt(disc)) / (2*a)

    # Return the roots
    logger.debug("# Return the roots")
    return (root1, root2)

roots = quadratic_formula(1, 0, -4)
print(roots)

==========================================

=============== RESTART: C:/Users/purunet/Documents/py/message.py ==============
(2.0, -2.0)


LinuxerHAN.log :

INFO 2020-04-25 13:23:45,842 - quadratic_formula(1, 0, -4)
DEBUG 2020-04-25 13:23:45,842 - # Compute the discriminant
DEBUG 2020-04-25 13:23:45,842 - # Compute the two roots
DEBUG 2020-04-25 13:23:45,842 - # Return the roots


==========================================

import logging
import math

# Creat and Configure logger
LOG_FORMAT = "%(levelname)s %(asctime)s - %(message)s"
logging.basicConfig(filename = "H:\\python\\LinuxerHAN.log",
                    level = logging.DEBUG,
                    format = LOG_FORMAT,
                    filemode = 'w')
logger = logging.getLogger()

def quadratic_formula(a, b, c):
    """Return the solutions to the equation ax^2 + bx + c = 0."""
    logger.info("quadratic_formula({0}, {1}, {2})".format(a, b, c))

    # Compute the discriminant
    logger.debug("# Compute the discriminant")
    disc = b**2 - 4*a*c

    # Compute the two roots
    logger.debug("# Compute the two roots")
    root1 = (-b + math.sqrt(disc)) / (2*a)
    root2 = (-b - math.sqrt(disc)) / (2*a)

    # Return the roots
    logger.debug("# Return the roots")
    return (root1, root2)

roots = quadratic_formula(1, 0, 1)
print(roots)

==========================================

=============== RESTART: C:/Users/purunet/Documents/py/message.py ==============
Traceback (most recent call last):
  File "C:/Users/purunet/Documents/py/message.py", line 29, in
    roots = quadratic_formula(1, 0, 1)
  File "C:/Users/purunet/Documents/py/message.py", line 22, in quadratic_formula
    root1 = (-b + math.sqrt(disc)) / (2*a)
ValueError: math domain error

LinuxerHAN.log :

INFO 2020-04-25 13:25:27,895 - quadratic_formula(1, 0, 1)
DEBUG 2020-04-25 13:25:27,896 - # Compute the discriminant
DEBUG 2020-04-25 13:25:27,896 - # Compute the two roots


--------------------------------------------------------------------------------

` Fibonacci Sequence, Recursion and Memoization



` Fibonacci Sequence

- 1, 1, 2, 3, 5, 8, 13, 21, . . .

- Goal : Write function to return n**th term of Fibonacci Sequence.

- Fast, Clearly written, Rock solid



==========================================

def fibonacci(n):
    if n == 1:
        return 1
    elif n == 2:
        return 1
    elif n > 2:
        return fibonacci(n-1) + fibonacci(n-2)


for n in range(1, 11):
    print(n, ":", fibonacci(n))

==========================================

============== RESTART: C:/Users/purunet/Documents/py/fibonacci.py =============
1 : 1
2 : 1
3 : 2
4 : 3
5 : 5
6 : 8
7 : 13
8 : 21
9 : 34
10 : 55


==========================================

def fibonacci(n):
    if n == 1:
        return 1
    elif n == 2:
        return 1
    elif n > 2:
        return fibonacci(n-1) + fibonacci(n-2)


for n in range(1, 30):
    print(n, ":", fibonacci(n))

==========================================

1 : 1
2 : 1
3 : 2
4 : 3
5 : 5
6 : 8
7 : 13
8 : 21
9 : 34
10 : 55
11 : 89
12 : 144
13 : 233
14 : 377
15 : 610
16 : 987
17 : 1597
18 : 2584
19 : 4181
20 : 6765
21 : 10946
22 : 17711
23 : 28657
24 : 46368
25 : 75025
26 : 121393
27 : 196418
28 : 317811
29 : 514229

- fibonacci(5) = fibonacci(4) + fibonacci(3)

= fibonacci(3) + fibonacci(2) + fibonacci(2) + fibonacci(1)

= fibonacci(2) + fibonacci(1) + fibonacci(2) + fibonacci(2) + fibonacci(1)

= 1 + 1 + 1 + 1 + 1 = 5



` Memoization

- Idea : Cache values

1. Implement explicitly

2. Use builtin Python tool


==========================================

fibonacci_cache = {}

def fibonacci(n):
    # If we have cached the value, then return it
    if n in fibonacci_cache:
        return fibonacci_cache[n]

    # Compute the Nth term
    if n == 1:
        value = 1
    elif n == 2:
        value = 1
    elif n > 2:
        value = fibonacci(n-1) + fibonacci(n-2)

    # Cache the value and return it
    fibonacci_cache[n] = value
    return value



for n in range(1, 50):
    print(n, ":", fibonacci(n))

==========================================

============= RESTART: C:/Users/purunet/Documents/py/fibonacci2.py =============
1 : 1
2 : 1
3 : 2
4 : 3
5 : 5
6 : 8
7 : 13
8 : 21
9 : 34
10 : 55
11 : 89
12 : 144
13 : 233
14 : 377
15 : 610
16 : 987
17 : 1597
18 : 2584
19 : 4181
20 : 6765
21 : 10946
22 : 17711
23 : 28657
24 : 46368
25 : 75025
26 : 121393
27 : 196418
28 : 317811
29 : 514229
30 : 832040
31 : 1346269
32 : 2178309
33 : 3524578
34 : 5702887
35 : 9227465
36 : 14930352
37 : 24157817
38 : 39088169
39 : 63245986
40 : 102334155
41 : 165580141
42 : 267914296
43 : 433494437
44 : 701408733
45 : 1134903170
46 : 1836311903
47 : 2971215073
48 : 4807526976
49 : 7778742049



` LRU Cache = Least Recently Used Cache


==========================================

from functools import lru_cache

@lru_cache(maxsize = 1000)
def fibonacci(n):
    if n == 1:
        return 1
    elif n == 2:
        return 1
    elif n > 2:
        return fibonacci(n-1) + fibonacci(n-2)


for n in range(1, 500):
    print(n, ":", fibonacci(n))
 
==========================================

============ RESTART: C:/Users/purunet/Documents/py/fibonacci_lru.py ===========
1 : 1
2 : 1
3 : 2
4 : 3
5 : 5
6 : 8

...


499 : 86168291600238450732788312165664788095941068326060883324529903470149056115823592713458328176574447204501



==========================================


from functools import lru_cache

@lru_cache(maxsize = 1000)
def fibonacci(n):
    # Check that the input is a positive integer
    if type(n) != int:
        raise TypeError("n must be a positive int")
    if n < 1:
        raise ValueError("n must be a positive int")

    # Compute the Nth term
    if n == 1:
        return 1
    elif n == 2:
        return 1
    elif n > 2:
        return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci("ONE"))


==========================================

============ RESTART: C:/Users/purunet/Documents/py/fibonacci_lru.py ===========
Traceback (most recent call last):
  File "C:/Users/purunet/Documents/py/fibonacci_lru.py", line 20, in
    print(fibonacci("ONE"))
  File "C:/Users/purunet/Documents/py/fibonacci_lru.py", line 8, in fibonacci
    raise TypeError("n must be a positive int")
TypeError: n must be a positive int


==========================================

from functools import lru_cache

@lru_cache(maxsize = 1000)
def fibonacci(n):
    # Check that the input is a positive integer
    if type(n) != int:
        raise TypeError("n must be a positive int")
    if n < 1:
        raise ValueError("n must be a positive int")

    # Compute the Nth term
    if n == 1:
        return 1
    elif n == 2:
        return 1
    elif n > 2:
        return fibonacci(n-1) + fibonacci(n-2)
 
for n in range(1, 51):
    print(fibonacci(n))

==========================================

============ RESTART: C:/Users/purunet/Documents/py/fibonacci_lru.py ===========
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
1346269
2178309
3524578
5702887
9227465
14930352
24157817
39088169
63245986
102334155
165580141
267914296
433494437
701408733
1134903170
1836311903
2971215073
4807526976
7778742049
12586269025

==========================================

from functools import lru_cache

@lru_cache(maxsize = 1000)
def fibonacci(n):
    # Check that the input is a positive integer
    if type(n) != int:
        raise TypeError("n must be a positive int")
    if n < 1:
        raise ValueError("n must be a positive int")

    # Compute the Nth term
    if n == 1:
        return 1
    elif n == 2:
        return 1
    elif n > 2:
        return fibonacci(n-1) + fibonacci(n-2)
 
for n in range(1, 51):
    print(fibonacci(n+1) / fibonacci(n))

==========================================

============ RESTART: C:/Users/purunet/Documents/py/fibonacci_lru.py ===========
1.0
2.0
1.5
1.6666666666666667
1.6
1.625
1.6153846153846154
1.619047619047619
1.6176470588235294
1.6181818181818182
1.6179775280898876
1.6180555555555556
1.6180257510729614
1.6180371352785146
1.618032786885246
1.618034447821682
1.6180338134001253
1.618034055727554
1.6180339631667064
1.6180339985218033
1.618033985017358
1.6180339901755971
1.618033988205325
1.618033988957902
1.6180339886704431
1.6180339887802426
1.618033988738303
1.6180339887543225
1.6180339887482036
1.6180339887505408
1.6180339887496482
1.618033988749989
1.618033988749859
1.6180339887499087
1.6180339887498896
1.618033988749897
1.618033988749894
1.6180339887498951
1.6180339887498947
1.618033988749895
1.618033988749895
1.618033988749895
1.618033988749895
1.618033988749895
1.618033988749895
1.618033988749895
1.618033988749895
1.618033988749895
1.618033988749895
1.618033988749895


--------------------------------------------------------------------------------

` Random Module


- WARNING : The pseudo-random generators of this module should not be used for security purposes. Use os.urandom() or SystemRandom if you require a cryptographically secure pseudo-random number generator.



>>> import random

>>> print(dir(random))
['BPF', 'LOG4', 'NV_MAGICCONST', 'RECIP_BPF', 'Random', 'SG_MAGICCONST', 'SystemRandom', 'TWOPI', '_Sequence', '_Set', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_accumulate', '_acos', '_bisect', '_ceil', '_cos', '_e', '_exp', '_inst', '_log', '_os', '_pi', '_random', '_repeat', '_sha512', '_sin', '_sqrt', '_test', '_test_generator', '_urandom', '_warn', 'betavariate', 'choice', 'choices', 'expovariate', 'gammavariate', 'gauss', 'getrandbits', 'getstate', 'lognormvariate', 'normalvariate', 'paretovariate', 'randint', 'random', 'randrange', 'sample', 'seed', 'setstate', 'shuffle', 'triangular', 'uniform', 'vonmisesvariate', 'weibullvariate']

>>> print(help(random.random))
Help on built-in function random:

random() method of random.Random instance
    random() -> x in the interval [0, 1).

None

==========================================

# Display 10 random numbers from interval [0, 1)

import random

for i in range(10):
    print(random.random())

==========================================
>>>
=============== RESTART: C:\Users\purunet\Documents\py\random.py ===============
0.8842398219404946
0.7210446357770858
0.23567797036671323
0.612747031386252
0.962537973088246
0.43899164585336514
0.6647050324514451
0.6272597035506544
0.8680715919393864
0.8823947034528059


- Call random(): # in [0, 1)

- Scale number (multiply by 4): # in [0, 4)

- Shift number (add 3): # in [3, 7)


==========================================

# Generate random numbers from interval [3, 7)

import random

def my_random():
    # Random, scale, shift, return ...

    return 4*random.random() + 3

for i in range(10):
    print(my_random())

==========================================
>>>
============== RESTART: C:/Users/purunet/Documents/py/my_random.py =============
6.555925541631019
5.8514688619756985
6.280315461207344
4.525353950278374
3.331743678054259
4.606227878164031
5.953287986990951
6.73314853927789
5.78299610178107
6.769740446996599



>>> import random

>>> dir(random)
['BPF', 'LOG4', 'NV_MAGICCONST', 'RECIP_BPF', 'Random', 'SG_MAGICCONST', 'SystemRandom', 'TWOPI', '_Sequence', '_Set', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_accumulate', '_acos', '_bisect', '_ceil', '_cos', '_e', '_exp', '_inst', '_log', '_os', '_pi', '_random', '_repeat', '_sha512', '_sin', '_sqrt', '_test', '_test_generator', '_urandom', '_warn', 'betavariate', 'choice', 'choices', 'expovariate', 'gammavariate', 'gauss', 'getrandbits', 'getstate', 'lognormvariate', 'normalvariate', 'paretovariate', 'randint', 'random', 'randrange', 'sample', 'seed', 'setstate', 'shuffle', 'triangular', 'uniform', 'vonmisesvariate', 'weibullvariate']

>>> help(random.uniform)
Help on method uniform in module random:

uniform(a, b) method of random.Random instance
    Get a random number in the range [a, b) or [a, b] depending on rounding.


- The random() function can be used to build customized random number generators.


==========================================

import random

for i in range(10):
    print(random.uniform(3, 7))

==========================================

>>>
=========== RESTART: C:/Users/purunet/Documents/py/random_uniform.py ===========
4.640836683284151
5.38086964107031
6.760087369311232
6.3824147128857405
6.951546157044718
6.246547183066015
6.783621687027413
5.853924696076453
6.377544582079553
3.4597714284434624


- random() and uniform() are both uniform distributions.

- Normal Distribution (aka " Bell Curve")


==========================================

import random

for i in range(20):
    print(random.normalvariate(0, 1))

==========================================
>>>
======== RESTART: C:/Users/purunet/Documents/py/random_normalvariate.py ========
0.061574910894126866
0.08564769924080946
0.8155491113773194
-0.5527889531971246
-1.19508743701972
-2.2647957154285656
-0.8579184678703422
0.5898754570683628
-1.2783444691710266
0.7112006966298586
-1.0974902051132067
1.2897583104513202
1.191931637572934
0.8465134653282321
-0.5751153685653602
1.0037090030177087
-1.3138370567524176
0.5686222246100371
-0.7394626246416109
0.6587960077412071


==========================================

import random

for i in range(20):
    print(random.normalvariate(0, 9))

==========================================

>>>
======== RESTART: C:/Users/purunet/Documents/py/random_normalvariate.py ========
-2.9987649600953397
-2.784261638766268
-0.5179251099533887
14.623051300496249
3.738891931480059
-4.3795930461975106
1.5798022507439053
0.9558637207361133
-8.668391253684735
0.7034760832955402
-8.798775807366434
-2.3951056092152436
9.11413896622082
8.171486669202736
-2.8139044902527064
4.382254553139539
-2.4615546974576636
-6.837180543996578
5.8986423864359985
-7.164558685016086


==========================================

import random

for i in range(20):
    print(random.normalvariate(0, 0.3))

==========================================
>>>
======== RESTART: C:/Users/purunet/Documents/py/random_normalvariate.py ========
-0.008851214960729334
-0.007331761535370901
-0.2808364071916394
-0.32449165512482114
0.17338242090553044
-0.13266427908136036
0.4604197967976666
-0.34833101538542416
0.3455538802223964
-0.5189246452165621
-0.06788248215161154
-0.32784539172192084
0.2742092590592461
-0.12995933528122194
0.16319688712433314
0.15466534241633986
-0.07055632510955571
0.33778132021981644
-0.05194610201823036
-0.1803335543297564


==========================================

import random

for i in range(20):
    print(random.normalvariate(5, 0.3))

==========================================
>>>
======== RESTART: C:/Users/purunet/Documents/py/random_normalvariate.py ========
4.842001693810185
4.817058121807893
4.856485710389507
5.107689206671948
5.344501992690381
4.654236119789514
5.136874037017121
5.053963347896129
4.8160977178612105
4.875657415628781
4.90654808461572
5.165924247944272
4.715393365866115
5.106606973798311
4.530639505490783
4.745284691470494
5.010738130713205
4.972487262414717
5.47105402164317
4.85008741042468


` Discrete Probability Distributions

` randint(min, max) "Random Integer"


==========================================

import random

for i in range(20):
    print(random.randint(1, 6))


==========================================
>>>
=========== RESTART: C:/Users/purunet/Documents/py/random_randint.py ===========
4
6
1
4
6
2
5
4
4
1
2
1
4
6
1
4
4
5
4
1


` Random element from a list


==========================================

import random

outcomes = ['red', 'black', 'white', 'blue']

for i in range(20):
    print(random.choice(outcomes))

==========================================

>>>
============ RESTART: C:/Users/purunet/Documents/py/random_choice.py ===========
blue
white
black
black
red
white
white
white
blue
white
red
white
blue
white
blue
black
white
white
blue
red


--------------------------------------------------------------------------------

` CSV Module

- CSV(Comma Separated Values)


>>> path = "H:\python\google_stock_data.csv"

>>> file = open(path)

>>> for line in file:
print(line)



Date,Open,High,Low,Close,Volume,Adj Close

8/19/2014,585.002622,587.342658,584.002627,586.862643,978600,586.862643

8/18/2014,576.11258,584.512631,576.002598,582.162619,1284100,582.162619

...

8/19/2004,100.000168,104.060182,95.960165,100.340176,44871300,50.119968



>>> path = "H:\python\google_stock_data.csv"

>>> lines = [line for line in open(path)]

>>>

>>> lines[0]
'Date,Open,High,Low,Close,Volume,Adj Close\n'

>>>

>>> lines[1]
'8/19/2014,585.002622,587.342658,584.002627,586.862643,978600,586.862643\n'

>>>

>>> lines[0].strip()
'Date,Open,High,Low,Close,Volume,Adj Close'

>>>

>>> lines[0].strip().split(',')
['Date', 'Open', 'High', 'Low', 'Close', 'Volume', 'Adj Close']

>>>

>>> dataset = [line.strip().split(',') for line in open(path)]

>>>

>>> dataset[0]
['Date', 'Open', 'High', 'Low', 'Close', 'Volume', 'Adj Close']

>>> dataset[1]
['8/19/2014', '585.002622', '587.342658', '584.002627', '586.862643', '978600', '586.862643']


>>> import csv

>>> print(dir(csv))
['Dialect', 'DictReader', 'DictWriter', 'Error', 'QUOTE_ALL', 'QUOTE_MINIMAL', 'QUOTE_NONE', 'QUOTE_NONNUMERIC', 'Sniffer', 'StringIO', '_Dialect', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', 'excel', 'excel_tab', 'field_size_limit', 'get_dialect', 'list_dialects', 're', 'reader', 'register_dialect', 'unix_dialect', 'unregister_dialect', 'writer']


==========================================

import csv

path = "H:\python\google_stock_data.csv"
file = open(path, newline='')
reader = csv.reader(file)

header = next(reader) # The first line is the header
data = [row for row in reader] # Read the remaining data

print(header)
print(data[0])

==========================================
>>>
============= RESTART: C:/Users/purunet/Documents/py/random_csv.py =============
['Date', 'Open', 'High', 'Low', 'Close', 'Volume', 'Adj Close']
['8/19/2014', '585.002622', '587.342658', '584.002627', '586.862643', '978600', '586.862643']



==========================================

import csv
from datetime import datetime

path = "H:\python\google_stock_data.csv"
file = open(path, newline='')
reader = csv.reader(file)

header = next(reader) # The first line is the header

data = []
for row in reader:
    # row = [Date, Open, High, Low, Close, Volume, Adj. Close]
    date = datetime.strptime(row[0], '%m/%d/%Y')
    open_price = float(row[1]) # 'open' is a builtin function
    high = float(row[2])
    low = float(row[3])
    close = float(row[4])
    volume = int(row[5])
    adj_close = float(row[6])

    data.append([date, open_price, high, low, close, volume, adj_close])
 
# Compute and store daily stock returns
returns_path = "H:\python\google_returns.csv"
file = open(returns_path, 'w')
writer = csv.writer(file)
writer.writerow(["Date", "Return"])

 
for i in range(len(data) - 1):
    todays_row = data[i]
    todays_date = todays_row[0]
    todays_price = todays_row[-1]
    yesterdays_row = data[i+1]
    yesterdays_price = yesterdays_row[-1]

    daily_return = (todays_price - yesterdays_price) / yesterdays_price
    formatted_date = todays_date.strftime('%m/%d/%Y')
    writer.writerow([todays_date, daily_return])

==========================================

=== google_returns.csv ===

Date,Return

2014-08-19 00:00:00,0.00807338679366512
...

2004-11-12 00:00:00,-0.005573157040086529


--------------------------------------------------------------------------------

` Random Walk


- What is the longest random walk you can take so that on average you wil end up 4 blocks or fewer from home?


` The Plan

- Write random walk function

- V1) Simple

- V2) Short


==========================================

import random

def random_walk(n):
    """Return coordinates after 'n' block random walk."""

    x = 0
    y = 0
    for i in range(n):
        step = random.choice(['N', 'S', 'E', 'W'])
        if step == 'N':
            y = y+1
        elif step == 'S':
            y = y-1
        elif step == 'E':
            x = x+1
        else:
            x = x-1
    return (x, y)


for i in range(25):
    walk = random_walk(10)
    print(walk, "Distance from home = ",
          abs(walk[0]) + abs(walk[1]))


==========================================
>>>
============= RESTART: C:/Users/purunet/Documents/py/random_walk.py ============
(5, 1) Distance from home =  6
(1, 1) Distance from home =  2
(-2, 0) Distance from home =  2
(-1, 1) Distance from home =  2
(-2, -2) Distance from home =  4
(2, 2) Distance from home =  4
(0, -2) Distance from home =  2
(0, 0) Distance from home =  0
(-6, 0) Distance from home =  6
(0, 2) Distance from home =  2
(-2, 0) Distance from home =  2
(2, 0) Distance from home =  2
(1, 1) Distance from home =  2
(-2, -2) Distance from home =  4
(-1, 1) Distance from home =  2
(-7, -3) Distance from home =  10
(0, -2) Distance from home =  2
(-2, 2) Distance from home =  4
(1, -1) Distance from home =  2
(1, -1) Distance from home =  2
(-3, 3) Distance from home =  6
(1, 1) Distance from home =  2
(0, -4) Distance from home =  4
(3, 1) Distance from home =  4
(1, 3) Distance from home =  4



==========================================

- dx = "difference in x"
- dy = "difference in y"

- x += dx <-> x = x + dx
- y += dy <-> y = y + dy


==========================================

import random

def random_walk2(n):
    """Return coordinates after 'n' block random walk."""
    x, y = 0, 0
    for i in range(n):
       (dx, dy) = random.choice([(0, 1), (0, -1), (1, 0), (-1,0)])
       x += dx
       y += dy
    return (x, y)


for i in range(25):
    walk = random_walk2(10)
    print(walk, "Distance from home = ",
          abs(walk[0]) + abs(walk[1]))

==========================================

>>>
============ RESTART: C:/Users/purunet/Documents/py/random_walk2.py ============
(0, 0) Distance from home =  0
(-5, 3) Distance from home =  8
(3, 3) Distance from home =  6
(1, 1) Distance from home =  2
(-1, 1) Distance from home =  2
(0, -4) Distance from home =  4
(1, 3) Distance from home =  4
(3, -1) Distance from home =  4
(1, 1) Distance from home =  2
(-4, 0) Distance from home =  4
(-2, 0) Distance from home =  2
(1, -1) Distance from home =  2
(0, 2) Distance from home =  2
(0, 0) Distance from home =  0
(0, 0) Distance from home =  0
(3, 1) Distance from home =  4
(1, -1) Distance from home =  2
(2, -4) Distance from home =  6
(0, 0) Distance from home =  0
(0, 0) Distance from home =  0
(-1, -1) Distance from home =  2
(-2, 2) Distance from home =  4
(-3, 1) Distance from home =  4
(-3, -1) Distance from home =  4
(1, 1) Distance from home =  2


- Monte Carlo

==========================================

import random

def random_walk_3(n):
    """Return coordinates after 'n' block random walk."""
    x, y = 0, 0
    for i in range(n):
       (dx, dy) = random.choice([(0, 1), (0, -1), (1, 0), (-1,0)])
       x += dx
       y += dy
    return (x, y)


number_of_walks = 10000

for walk_length in range(1, 31):
    no_transport = 0 # Number of walks 4 or fewer blocks from home
    for i in range(number_of_walks):
        (x, y) = random_walk_3(walk_length)
        distance = abs(x) + abs(y)
        if distance <= 4:
            no_transport += 1
    no_transport_percentage = float(no_transport) / number_of_walks
    print("Walk size = ", walk_length,
          " / % of no transport = ", 100*no_transport_percentage)


==========================================

>>>
============ RESTART: C:/Users/purunet/Documents/py/random_walk3.py ============
Walk size =  1  / % of no transport =  100.0
Walk size =  2  / % of no transport =  100.0
Walk size =  3  / % of no transport =  100.0
Walk size =  4  / % of no transport =  100.0
Walk size =  5  / % of no transport =  87.42999999999999
Walk size =  6  / % of no transport =  93.61
Walk size =  7  / % of no transport =  76.53999999999999
Walk size =  8  / % of no transport =  86.25
Walk size =  9  / % of no transport =  66.75
Walk size =  10  / % of no transport =  79.17
Walk size =  11  / % of no transport =  59.940000000000005
Walk size =  12  / % of no transport =  73.59
Walk size =  13  / % of no transport =  54.120000000000005
Walk size =  14  / % of no transport =  66.89
Walk size =  15  / % of no transport =  49.519999999999996
Walk size =  16  / % of no transport =  62.19
Walk size =  17  / % of no transport =  45.660000000000004
Walk size =  18  / % of no transport =  57.54
Walk size =  19  / % of no transport =  41.03
Walk size =  20  / % of no transport =  53.87
Walk size =  21  / % of no transport =  38.06
Walk size =  22  / % of no transport =  49.74
Walk size =  23  / % of no transport =  34.54
Walk size =  24  / % of no transport =  47.980000000000004
Walk size =  25  / % of no transport =  33.54
Walk size =  26  / % of no transport =  45.49
Walk size =  27  / % of no transport =  31.319999999999997
Walk size =  28  / % of no transport =  42.27
Walk size =  29  / % of no transport =  28.76
Walk size =  30  / % of no transport =  40.75

==========================================

import random

def random_walk_3(n):
    """Return coordinates after 'n' block random walk."""
    x, y = 0, 0
    for i in range(n):
       (dx, dy) = random.choice([(0, 1), (0, -1), (1, 0), (-1,0)])
       x += dx
       y += dy
    return (x, y)


number_of_walks = 20000

for walk_length in range(1, 31):
    no_transport = 0 # Number of walks 4 or fewer blocks from home
    for i in range(number_of_walks):
        (x, y) = random_walk_3(walk_length)
        distance = abs(x) + abs(y)
        if distance <= 4:
            no_transport += 1
    no_transport_percentage = float(no_transport) / number_of_walks
    print("Walk size = ", walk_length,
          " / % of no transport = ", 100*no_transport_percentage)

==========================================

>>>
============ RESTART: C:/Users/purunet/Documents/py/random_walk3.py ============
Walk size =  1  / % of no transport =  100.0
Walk size =  2  / % of no transport =  100.0
Walk size =  3  / % of no transport =  100.0
Walk size =  4  / % of no transport =  100.0
Walk size =  5  / % of no transport =  87.685
Walk size =  6  / % of no transport =  94.08
Walk size =  7  / % of no transport =  76.075
Walk size =  8  / % of no transport =  86.44500000000001
Walk size =  9  / % of no transport =  67.205
Walk size =  10  / % of no transport =  79.225
Walk size =  11  / % of no transport =  59.760000000000005
Walk size =  12  / % of no transport =  73.21
Walk size =  13  / % of no transport =  53.43
Walk size =  14  / % of no transport =  66.945
Walk size =  15  / % of no transport =  49.035000000000004
Walk size =  16  / % of no transport =  62.565000000000005
Walk size =  17  / % of no transport =  44.595
Walk size =  18  / % of no transport =  58.309999999999995
Walk size =  19  / % of no transport =  41.099999999999994
Walk size =  20  / % of no transport =  53.580000000000005
Walk size =  21  / % of no transport =  38.115
Walk size =  22  / % of no transport =  50.8
Walk size =  23  / % of no transport =  35.045
Walk size =  24  / % of no transport =  48.120000000000005
Walk size =  25  / % of no transport =  32.58
Walk size =  26  / % of no transport =  44.73
Walk size =  27  / % of no transport =  30.8
Walk size =  28  / % of no transport =  42.51
Walk size =  29  / % of no transport =  30.075000000000003
Walk size =  30  / % of no transport =  41.36

--------------------------------------------------------------------------------

` List Comprehensions


- List : [1, 2, "a", 3.14]

- List Comprehensions:

[expr for val in collection]

[expr for val in collection if ]

[expr for val in collection if and ]

[expr for val1 in collection and val2 in collections2]



>>> squares = []

>>> for i in range(1, 101):
squares.append(i**2)


>>> print(squares)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801, 10000]

>>>


>>> squares2 = [i**2 for i in range(1,101)]

>>> print(squares2)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801, 10000]

>>>

>>> remainders5 = [x**2 % 5 for x in range(1, 101)]

>>> print(remainders5)
[1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0, 1, 4, 4, 1, 0]

>>>

>>> remainders11 = [x**2 % 11 for x in range(1, 101)]

>>> print(remainders11)
[1, 4, 9, 5, 3, 3, 5, 9, 4, 1, 0, 1, 4, 9, 5, 3, 3, 5, 9, 4, 1, 0, 1, 4, 9, 5, 3, 3, 5, 9, 4, 1, 0, 1, 4, 9, 5, 3, 3, 5, 9, 4, 1, 0, 1, 4, 9, 5, 3, 3, 5, 9, 4, 1, 0, 1, 4, 9, 5, 3, 3, 5, 9, 4, 1, 0, 1, 4, 9, 5, 3, 3, 5, 9, 4, 1, 0, 1, 4, 9, 5, 3, 3, 5, 9, 4, 1, 0, 1, 4, 9, 5, 3, 3, 5, 9, 4, 1, 0, 1]



` Quadratic Reciprocity by Gauss

- p_remainders = [x ** 2 % p for x in range(0, p)]

- len(p_remainders) = p + 1 / 2


==========================================

movies = ["Star Wars", "Gandhi", "Casablanca", "Shawshank Redemption",
          "Toy Story", "Gone with the Wind", "Citizen Kane",
          "It's a Wonderful Life", "The Wizard of Oz", "Gattaca",
          "Rear Window", "Ghostbusters", "To kill A Mockingbird",
          "Good Will Hunting", "2001: A Space Odyssey",
          "Raiders of the Lost Ark", "Groundhog Day",
          "Close Encounters of the Third Kind"]

gmovies = []
for title in movies:
    if title.startswith("G"):
        gmovies.append(title)


print(gmovies)


gmovies = [title for title in movies if title.startswith("G")]
print(gmovies)

==========================================

>>>
=============== RESTART: C:/Users/purunet/Documents/py/movies.py ===============
['Gandhi', 'Gone with the Wind', 'Gattaca', 'Ghostbusters', 'Good Will Hunting', 'Groundhog Day']
['Gandhi', 'Gone with the Wind', 'Gattaca', 'Ghostbusters', 'Good Will Hunting', 'Groundhog Day']


- Task : Find movies released before 2000

==========================================

movies = [("Citizen Kane", 1941), ("Spirited Away", 2001),
          ("It's a Wonderful Life", 1946), ("Gattaca", 1997),
          ("No Country for Old Men", 2007), ("Rear Window", 1954),
          ("The Lord of the Rings: The Fellowship of the Ring", 2001),
          ("Groundhog Day", 1993), ("Close Encounters of the Third Kind", 1977),
          ("The Royal Tenenbaums", 2001), ("The Aviator", 2004),
          ("Raiders of the Lost Ark", 1981)]


       
pre2k = [title for (title, year) in movies if year < 2000]

print(pre2k)

==========================================

>>>
=============== RESTART: C:/Users/purunet/Documents/py/movies2.py ==============
['Citizen Kane', "It's a Wonderful Life", 'Gattaca', 'Rear Window', 'Groundhog Day', 'Close Encounters of the Third Kind', 'Raiders of the Lost Ark']

>>>

- Scalar Myltiplication


>>> v = [2, -3, 1]

>>> 4*v
[2, -3, 1, 2, -3, 1, 2, -3, 1, 2, -3, 1]


- 4 * v = v + v + v + v
- Adding Lists = Concatenation


>>> [2, 4, 6] + [1, 3, 5]
[2, 4, 6, 1, 3, 5]


>>> w = [4*x for x in v]

>>> print(w)
[8, -12, 4]


- Cartesian Product by Rene Descartes

- If A and B are sets, then the Cartesian product is the set of pairs (a, b) where 'a' is in A and 'b' is in B.

- A x B = { (a, b) | a ∈ A, b ∈ B }


- ex) A = {1, 3}, B = {x, y} then A x B = {(1,x), (1,y), (3,x), (3,y)}


>>> A = [1, 3, 5, 7]

>>> B = [2, 4, 6, 8]

>>>

>>> cartesian_product = [(a,b) for a in A for b in B]

>>>

>>> print(cartesian_product)
[(1, 2), (1, 4), (1, 6), (1, 8), (3, 2), (3, 4), (3, 6), (3, 8), (5, 2), (5, 4), (5, 6), (5, 8), (7, 2), (7, 4), (7, 6), (7, 8)]


--------------------------------------------------------------------------------

` Classes



- user1 is an "instance" of User

- user1 is an "object"


 - Field : Data attached to an object


>>> class User:
pass

>>> user1 = User()

>>> user1.first_name = "Dave"

>>> user1.last_name = "Bowman"

>>>

>>> print(user1.first_name)
Dave

>>> print(user1.last_name)
Bowman


- Style Guide for Python (PEP 8) : "...lowercase with words separated by underscores as necessary to improve readability."


>>>

>>> first_name = "Arthur"

>>> last_name = "Clarke"

>>> print(first_name, last_name)
Arthur Clarke

>>>

>>> print(user1.first_name, user1.last_name)
Dave Bowman



>>> user2 = User()

>>> user2.first_name = "Frank"

>>> user2.last_name = "Poole"

>>>

>>> print(first_name, last_name)
Arthur Clarke

>>>

>>> print(user1.first_name, user1.last_name)
Dave Bowman

>>>

>>> print(user2.first_name, user2.last_name)
Frank Poole


>>> user1.age = 40

>>> user2.favorite_book = "2001: A Space Odyssey"

>>>

>>> print(user1.age)
40

>>> print(user2.age)
Traceback (most recent call last):
  File "", line 1, in
    print(user2.age)
AttributeError: 'User' object has no attribute 'age'


` Class Features

- Methods
- Initialization
- Help text


` init method

- init = initialization

- a.k.a " Constructor"

==========================================

class User:
    def __init__(self, full_name, birthday):
        self.name = full_name
        self.birthday = birthday # yyyymmdd

        # Extract first and last names
        name_pieces = full_name.split(" ")
        self.first_name = name_pieces[0]
        self.last_name = name_pieces[-1]
     


user = User("Dave Bowman", "19710315")
print(user.name)
print(user.first_name)
print(user.last_name)
print(user.birthday)

==========================================

>>>
=============== RESTART: C:/Users/purunet/Documents/py/class1.py ===============
Dave Bowman
Dave
Bowman
19710315

==========================================

class User:
    """A member of FriendFace. For now we are
       Only storing their name and birthday.
       But soon we will store an uncomfortable
       amount of user information. """
 
    def __init__(self, full_name, birthday):
        self.name = full_name
        self.birthday = birthday # yyyymmdd

        # Extract first and last names
        name_pieces = full_name.split(" ")
        self.first_name = name_pieces[0]
        self.last_name = name_pieces[-1]
     


help(User)

==========================================

>>>
=============== RESTART: C:/Users/purunet/Documents/py/class1.py ===============
Help on class User in module __main__:

class User(builtins.object)
 |  User(full_name, birthday)
 |
 |  A member of FriendFace. For now we are
 |  Only storing their name and birthday.
 |  But soon we will store an uncomfortable
 |  amount of user information.
 |
 |  Methods defined here:
 |
 |  __init__(self, full_name, birthday)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)

>>>


==========================================

import datetime

class User:
    """A member of FriendFace. For now we are
       Only storing their name and birthday.
       But soon we will store an uncomfortable
       amount of user information. """
 
    def __init__(self, full_name, birthday):
        self.name = full_name
        self.birthday = birthday # yyyymmdd

        # Extract first and last names
        name_pieces = full_name.split(" ")
        self.first_name = name_pieces[0]
        self.last_name = name_pieces[-1]
     
    def age(self):
        """Return the age of the user in years."""
        today = datetime.date(2001, 5, 12)
        yyyy = int(self.birthday[0:4])
        mm = int(self.birthday[4:6])
        dd = int(self.birthday[6:8])
        dob = datetime.date(yyyy, mm, dd) # Date of birth
        age_in_days = (today - dob).days
        age_in_years = age_in_days / 365
        return int(age_in_years)


user = User("Dave Bowman", "19710315")
print(user.age())

help(user.age())

==========================================

>>>
=============== RESTART: C:/Users/purunet/Documents/py/class1.py ===============
30


Help on class User in module __main__:

class User(builtins.object)
 |  User(full_name, birthday)
 |
 |  A member of FriendFace. For now we are
 |  Only storing their name and birthday.
 |  But soon we will store an uncomfortable
 |  amount of user information.
 |
 |  Methods defined here:
 |
 |  __init__(self, full_name, birthday)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |
 |  age(self)
 |      Return the age of the user in years.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)


` Classes :

- Fields
- Methods
- Instances

--------------------------------------------------------------------------------

` Prime Numbers

- Only divisible by itself and 1

- (2, 3, 5, 7, 11, 13, 17, 19, ...)



` Composite Number 

- Can be factored into smaller integers

- (4 = 2 x 2, 6 = 2 x 3, 8 = 2 x 2 x 2, 9 = 3 x 3, ...)


` Unit: 1


# V1) Test all divisors from 2 through n-1 (skip 1 and n)


==========================================

def is_prime_v1(n):
    """Return 'True' if 'n' is a prime number, False otherwise."""
    if n == 1:
        return False # 1 is not prime

    for d in range(2, n):
        if n % d == 0:
            return False
    return True


# ===== Test Function =====
for n in range(1, 21):
    print(n, is_prime_v1(n))

==========================================

>>>
= RESTART: C:/Users/purunet/AppData/Local/Programs/Python/Python38-32/prime1.py
1 False
2 True
3 True
4 False
5 True
6 False
7 True
8 False
9 False
10 False
11 True
12 False
13 True
14 False
15 False
16 False
17 True
18 False
19 True
20 False
>>>


==========================================

import time

def is_prime_v1(n):
    """Return 'True' if 'n' is a prime number, False otherwise."""
    if n == 1:
        return False # 1 is not prime

    for d in range(2, n):
        if n % d == 0:
            return False
    return True


# ===== Time Function =====
t0 = time.time()
for n in range(1, 20000):
    is_prime_v1(n)
t1 = time.time()
print("Time required: ", t1 - t0)

==========================================

>>>
= RESTART: C:/Users/purunet/AppData/Local/Programs/Python/Python38-32/prime_time.py
Time required:  3.688201427459717
>>>



` Next step: Reduce number of divisors we check

36 = 1 x 36
36 = 2 x 18
36 = 3 x 12
36 = 4 x 9
36 = 6 x 6
36 = 9 x 4
36 = 12 x 3
36 = 18 x 2
36 = 36 x 1


# v2) Test all divisors from 2 through sqrt(N)


==========================================

import math
import time


def is_prime_v1(n):
    """Return 'True' if 'n' is a prime number, False otherwise."""
    if n == 1:
        return False # 1 is not prime

    for d in range(2, n):
        if n % d == 0:
            return False
    return True



def is_prime_v2(n):
    """Return 'True' if 'n' is a prime number, False otherwise."""
    if n == 1:
        return False # 1 is not prime

    max_divisor = math.floor(math.sqrt(n))
    for d in range(2, 1 + max_divisor):
        if n % d == 0:
            return False
    return True



# ===== Time Function =====
for n in range(1, 21):
    print(n, is_prime_v2(n))


==========================================
>>>
= RESTART: C:/Users/purunet/AppData/Local/Programs/Python/Python38-32/prime_time.py
1 False
2 True
3 True
4 False
5 True
6 False
7 True
8 False
9 False
10 False
11 True
12 False
13 True
14 False
15 False
16 False
17 True
18 False
19 True
20 False
>>>


==========================================

import math
import time


def is_prime_v1(n):
    """Return 'True' if 'n' is a prime number, False otherwise."""
    if n == 1:
        return False # 1 is not prime

    for d in range(2, n):
        if n % d == 0:
            return False
    return True



def is_prime_v2(n):
    """Return 'True' if 'n' is a prime number, False otherwise."""
    if n == 1:
        return False # 1 is not prime

    max_divisor = math.floor(math.sqrt(n))
    for d in range(2, 1 + max_divisor):
        if n % d == 0:
            return False
    return True



# ===== Time Function =====
t0 = time.time()
for n in range(1, 20000):
    is_prime_v1(n)
t1 = time.time()
print("Time required: ", t1 - t0)

==========================================
>>>
= RESTART: C:/Users/purunet/AppData/Local/Programs/Python/Python38-32/prime_time.py
Time required:  3.6052064895629883



- Step 1) Test if n is even

- Step 2) Test only odd divisors


==========================================

import math
import time


def is_prime_v1(n):
    """Return 'True' if 'n' is a prime number, False otherwise."""
    if n == 1:
        return False # 1 is not prime

    for d in range(2, n):
        if n % d == 0:
            return False
    return True



def is_prime_v2(n):
    """Return 'True' if 'n' is a prime number, False otherwise."""
    if n == 1:
        return False # 1 is not prime

    max_divisor = math.floor(math.sqrt(n))
    for d in range(2, 1 + max_divisor):
        if n % d == 0:
            return False
    return True


def is_prime_v3(n):
    """Return 'True' if 'n' is a prime number, False otherwise."""
    if n == 1:
        return False # 1 is not prime

    # If it's even and not 2, then it's not prime
    if n == 2:
        return True
    if n > 2 and n % 2 == 0:
        return False

    max_divisor = math.floor(math.sqrt(n))
    for d in range(3, 1 + max_divisor, 2):
        if n % d == 0:
            return False
    return True

# ===== Test Function =====
for n in range(1, 21):
    print(n, is_prime_v3(n))

==========================================

>>>
= RESTART: C:/Users/purunet/AppData/Local/Programs/Python/Python38-32/prime_time3.py
1 False
2 True
3 True
4 False
5 True
6 False
7 True
8 False
9 False
10 False
11 True
12 False
13 True
14 False
15 False
16 False
17 True
18 False
19 True
20 False


==========================================

import math
import time


def is_prime_v1(n):
    """Return 'True' if 'n' is a prime number, False otherwise."""
    if n == 1:
        return False # 1 is not prime

    for d in range(2, n):
        if n % d == 0:
            return False
    return True



def is_prime_v2(n):
    """Return 'True' if 'n' is a prime number, False otherwise."""
    if n == 1:
        return False # 1 is not prime

    max_divisor = math.floor(math.sqrt(n))
    for d in range(2, 1 + max_divisor):
        if n % d == 0:
            return False
    return True


def is_prime_v3(n):
    """Return 'True' if 'n' is a prime number, False otherwise."""
    if n == 1:
        return False # 1 is not prime

    # If it's even and not 2, then it's not prime
    if n == 2:
        return True
    if n > 2 and n % 2 == 0:
        return False

    max_divisor = math.floor(math.sqrt(n))
    for d in range(3, 1 + max_divisor, 2):
        if n % d == 0:
            return False
    return True


# ===== Time Function =====
t0 = time.time()
for n in range(1, 20000):
    is_prime_v1(n)
t1 = time.time()
print("Time required: ", t1 - t0)

==========================================

>>>
= RESTART: C:/Users/purunet/AppData/Local/Programs/Python/Python38-32/prime_time3.py
Time required:  3.683206081390381


--------------------------------------------------------------------------------


` PyDoc


==========================================


C:\Users\purunet>python -m pydoc
pydoc - the Python documentation tool

pydoc ...
    Show text documentation on something.  may be the name of a
    Python keyword, topic, function, module, or package, or a dotted
    reference to a class or function within a module or module in a
    package.  If contains a '\', it is used as the path to a
    Python source file to document. If name is 'keywords', 'topics',
    or 'modules', a listing of these things is displayed.

pydoc -k
    Search for a keyword in the synopsis lines of all available modules.

pydoc -n
    Start an HTTP server with the given hostname (default: localhost).

pydoc -p
    Start an HTTP server on the given port on the local machine.  Port
    number 0 can be used to get an arbitrary unused port.

pydoc -b
    Start an HTTP server on an arbitrary unused port and open a Web browser
    to interactively browse documentation.  This option can be used in
    combination with -n and/or -p.

pydoc -w ...
    Write out the HTML documentation for a module to a file in the current
    directory.  If contains a '\', it is treated as a filename; if
    it names a directory, documentation is written for all the contents.


==========================================


C:\Users\purunet>python -m pydoc math
Help on built-in module math:

NAME
    math

DESCRIPTION
    This module provides access to the mathematical functions
    defined by the C standard.

FUNCTIONS
    acos(x, /)
        Return the arc cosine (measured in radians) of x.

    acosh(x, /)
        Return the inverse hyperbolic cosine of x.

    asin(x, /)
        Return the arc sine (measured in radians) of x.

    asinh(x, /)
        Return the inverse hyperbolic sine of x.

    atan(x, /)
        Return the arc tangent (measured in radians) of x.

    atan2(y, x, /)
        Return the arc tangent (measured in radians) of y/x.

        Unlike atan(y/x), the signs of both x and y are considered.

    atanh(x, /)
        Return the inverse hyperbolic tangent of x.

    ceil(x, /)
        Return the ceiling of x as an Integral.

        This is the smallest integer >= x.

    comb(n, k, /)
        Number of ways to choose k items from n items without repetition and wit
hout order.

        Evaluates to n! / (k! * (n - k)!) when k <= n and evaluates
        to zero when k > n.

        Also called the binomial coefficient because it is equivalent
        to the coefficient of k-th term in polynomial expansion of the
        expression (1 + x)**n.

        Raises TypeError if either of the arguments are not integers.
        Raises ValueError if either of the arguments are negative.

    copysign(x, y, /)
        Return a float with the magnitude (absolute value) of x but the sign of
y.

        On platforms that support signed zeros, copysign(1.0, -0.0)
        returns -1.0.

    cos(x, /)
        Return the cosine of x (measured in radians).

    cosh(x, /)
        Return the hyperbolic cosine of x.

    degrees(x, /)
        Convert angle x from radians to degrees.

    dist(p, q, /)
        Return the Euclidean distance between two points p and q.

        The points should be specified as sequences (or iterables) of
        coordinates.  Both inputs must have the same dimension.

        Roughly equivalent to:
            sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q)))

    erf(x, /)
        Error function at x.

    erfc(x, /)
        Complementary error function at x.

    exp(x, /)
        Return e raised to the power of x.

    expm1(x, /)
        Return exp(x)-1.

        This function avoids the loss of precision involved in the direct evalua
tion of exp(x)-1 for small x.

    fabs(x, /)
        Return the absolute value of the float x.

    factorial(x, /)
        Find x!.

        Raise a ValueError if x is negative or non-integral.

    floor(x, /)
        Return the floor of x as an Integral.

        This is the largest integer <= x.

    fmod(x, y, /)
        Return fmod(x, y), according to platform C.

        x % y may differ.

    frexp(x, /)
        Return the mantissa and exponent of x, as pair (m, e).

        m is a float and e is an int, such that x = m * 2.**e.
        If x is 0, m and e are both 0.  Else 0.5 <= abs(m) < 1.0.

    fsum(seq, /)
        Return an accurate floating point sum of values in the iterable seq.

        Assumes IEEE-754 floating point arithmetic.

    gamma(x, /)
        Gamma function at x.

    gcd(x, y, /)
        greatest common divisor of x and y

    hypot(...)
        hypot(*coordinates) -> value

        Multidimensional Euclidean distance from the origin to a point.

        Roughly equivalent to:
            sqrt(sum(x**2 for x in coordinates))

        For a two dimensional point (x, y), gives the hypotenuse
        using the Pythagorean theorem:  sqrt(x*x + y*y).

        For example, the hypotenuse of a 3/4/5 right triangle is:

            >>> hypot(3.0, 4.0)
            5.0

    isclose(a, b, *, rel_tol=1e-09, abs_tol=0.0)
        Determine whether two floating point numbers are close in value.

          rel_tol
            maximum difference for being considered "close", relative to the
            magnitude of the input values
          abs_tol
            maximum difference for being considered "close", regardless of the
            magnitude of the input values

        Return True if a is close in value to b, and False otherwise.

        For the values to be considered close, the difference between them
        must be smaller than at least one of the tolerances.

        -inf, inf and NaN behave similarly to the IEEE 754 Standard.  That
        is, NaN is not close to anything, even itself.  inf and -inf are
        only close to themselves.

    isfinite(x, /)
        Return True if x is neither an infinity nor a NaN, and False otherwise.

    isinf(x, /)
        Return True if x is a positive or negative infinity, and False otherwise
.

    isnan(x, /)
        Return True if x is a NaN (not a number), and False otherwise.

    isqrt(n, /)
        Return the integer part of the square root of the input.

    ldexp(x, i, /)
        Return x * (2**i).

        This is essentially the inverse of frexp().

    lgamma(x, /)
        Natural logarithm of absolute value of Gamma function at x.

    log(...)
        log(x, [base=math.e])
        Return the logarithm of x to the given base.

        If the base not specified, returns the natural logarithm (base e) of x.

    log10(x, /)
        Return the base 10 logarithm of x.

    log1p(x, /)
        Return the natural logarithm of 1+x (base e).

        The result is computed in a way which is accurate for x near zero.

    log2(x, /)
        Return the base 2 logarithm of x.

    modf(x, /)
        Return the fractional and integer parts of x.

        Both results carry the sign of x and are floats.

    perm(n, k=None, /)
        Number of ways to choose k items from n items without repetition and wit
h order.

        Evaluates to n! / (n - k)! when k <= n and evaluates
        to zero when k > n.

        If k is not specified or is None, then k defaults to n
        and the function returns n!.

        Raises TypeError if either of the arguments are not integers.
        Raises ValueError if either of the arguments are negative.

    pow(x, y, /)
        Return x**y (x to the power of y).

    prod(iterable, /, *, start=1)
        Calculate the product of all the elements in the input iterable.

        The default start value for the product is 1.

        When the iterable is empty, return the start value.  This function is
        intended specifically for use with numeric values and may reject
        non-numeric types.

    radians(x, /)
        Convert angle x from degrees to radians.

    remainder(x, y, /)
        Difference between x and the closest integer multiple of y.

        Return x - n*y where n*y is the closest integer multiple of y.
        In the case where x is exactly halfway between two multiples of
        y, the nearest even value of n is used. The result is always exact.

    sin(x, /)
        Return the sine of x (measured in radians).

    sinh(x, /)
        Return the hyperbolic sine of x.

    sqrt(x, /)
        Return the square root of x.

    tan(x, /)
        Return the tangent of x (measured in radians).

    tanh(x, /)
        Return the hyperbolic tangent of x.

    trunc(x, /)
        Truncates the Real x to the nearest Integral toward 0.

        Uses the __trunc__ magic method.

DATA
    e = 2.718281828459045
    inf = inf
    nan = nan
    pi = 3.141592653589793
    tau = 6.283185307179586

FILE
    (built-in)


==========================================


C:\Users\purunet>python -m pydoc tuple
Help on class tuple in module builtins:

class tuple(object)
 |  tuple(iterable=(), /)
 |
 |  Built-in immutable sequence.
 |
 |  If no argument is given, the constructor returns an empty tuple.
 |  If iterable is specified the tuple is initialized from iterable's items.
 |
 |  If the argument is a tuple, the return value is the same object.
 |
 |  Built-in subclasses:
 |      asyncgen_hooks
 |      UnraisableHookArgs
 |
 |  Methods defined here:
 |
 |  __add__(self, value, /)
 |      Return self+value.
 |
 |  __contains__(self, key, /)
 |      Return key in self.
 |
 |  __eq__(self, value, /)
 |      Return self==value.
 |
 |  __ge__(self, value, /)
 |      Return self>=value.
 |
 |  __getattribute__(self, name, /)
 |      Return getattr(self, name).
 |
 |  __getitem__(self, key, /)
 |      Return self[key].
 |
 |  __getnewargs__(self, /)
 |
 |  __gt__(self, value, /)
 |      Return self>value.
 |
 |  __hash__(self, /)
 |      Return hash(self).
 |
 |  __iter__(self, /)
 |      Implement iter(self).
 |
 |  __le__(self, value, /)
 |      Return self<=value.
 |
 |  __len__(self, /)
 |      Return len(self).
 |
 |  __lt__(self, value, /)
 |      Return self |
 |  __mul__(self, value, /)
 |      Return self*value.
 |
 |  __ne__(self, value, /)
 |      Return self!=value.
 |
 |  __repr__(self, /)
 |      Return repr(self).
 |
 |  __rmul__(self, value, /)
 |      Return value*self.
 |
 |  count(self, value, /)
 |      Return number of occurrences of value.
 |
 |  index(self, value, start=0, stop=2147483647, /)
 |      Return first index of value.
 |
 |      Raises ValueError if the value is not present.
 |
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.



==========================================


C:\Users\purunet>python -m pydoc pow
Help on built-in function pow in module builtins:

pow(base, exp, mod=None)
    Equivalent to base**exp with 2 arguments or base**exp % mod with 3 arguments

    Some types, such as ints, are able to use a more efficient algorithm when
    invoked using the three argument form.

==========================================

C:\Users\purunet>python -m pydoc -k ftp
ftplib - An FTP client class and some helper functions.
test.test_ftplib - Test script for ftplib module.

==========================================

C:\Users\purunet>python -m pydoc ftplib
Help on module ftplib:

NAME
    ftplib - An FTP client class and some helper functions.

MODULE REFERENCE
    https://docs.python.org/3.8/library/ftplib

    The following documentation is automatically generated from the Python
    source files.  It may be incomplete, incorrect or include features that
    are considered implementation detail and may vary between Python
    implementations.  When in doubt, consult the module reference at the
    location listed above.

DESCRIPTION
    Based on RFC 959: File Transfer Protocol (FTP), by J. Postel and J. Reynolds

    Example:

    >>> from ftplib import FTP
    >>> ftp = FTP('ftp.python.org') # connect to host, default port
    >>> ftp.login() # default, i.e.: user anonymous, passwd anonymous@
    '230 Guest login ok, access restrictions apply.'
    >>> ftp.retrlines('LIST') # list directory contents

    ...


==========================================

C:\Users\purunet>python -m pydoc -k sql
_sqlite3
sqlite3
sqlite3.dbapi2
sqlite3.dump
sqlite3.test
sqlite3.test.backup
sqlite3.test.dbapi
sqlite3.test.dump
sqlite3.test.factory
sqlite3.test.hooks
sqlite3.test.regression
sqlite3.test.transactions
sqlite3.test.types
sqlite3.test.userfunctions
test.test_sqlite
pip._vendor.lockfile.sqlitelockfile

==========================================


C:\Users\purunet>python -m pydoc sqlite3

Help on package sqlite3:

NAME
    sqlite3

MODULE REFERENCE
    https://docs.python.org/3.8/library/sqlite3
 
    The following documentation is automatically generated from the Python
    source files.  It may be incomplete, incorrect or include features that
    are considered implementation detail and may vary between Python
    implementations.  When in doubt, consult the module reference at the
    location listed above.

DESCRIPTION
    # pysqlite2/__init__.py: the pysqlite2 package.
    #
    # Copyright (C) 2005 Gerhard H\xe4ring
    #
    # This file is part of pysqlite.
    #
    # This software is provided 'as-is', without any express or implied
    # warranty.  In no event will the authors be held liable for any damages
    # arising from the use of this software.
    #
    # Permission is granted to anyone to use this software for any purpose,
    # including commercial applications, and to alter it and redistribute it
    # freely, subject to the following restrictions:
    #
    # 1. The origin of this software must not be misrepresented; you must not
    #    claim that you wrote the original software. If you use this software
    #    in a product, an acknowledgment in the product documentation would be
    #    appreciated but is not required.
    # 2. Altered source versions must be plainly marked as such, and must not be
    #    misrepresented as being the original software.
    # 3. This notice may not be removed or altered from any source distribution.

     ...


==========================================

C:\Users\purunet>python -m pydoc -p 314
Server ready at http://localhost:314/
Server commands: [b]rowser, [q]uit
server> b

==========================================




==========================================

server> q
Server stopped

==========================================

C:\Users\purunet>python -m pydoc -b
Server ready at http://localhost:3447/
Server commands: [b]rowser, [q]uit
server> q
Server stopped
==========================================
==========================================

C:\>mkdir pydoc_demo

C:\>cd pydoc_demo

C:\pydoc_demo>python -m pydoc -w json
wrote json.html

C:\pydoc_demo>dir
 C 드라이브의 볼륨에는 이름이 없습니다.
 볼륨 일련 번호: 840E-6930

 C:\pydoc_demo 디렉터리

2020-04-26  오후 03:10   









          .
2020-04-26  오후 03:10   









          ..
2020-04-26  오후 03:10            45,282 json.html
               1개 파일              45,282 바이트
               2개 디렉터리  18,962,493,440 바이트 남음

C:\pydoc_demo>start json.html

==========================================


--------------------------------------------------------------------------------


` JSON (Java Script Object Notation)


>>> import json

>>> dir(json)
['JSONDecodeError', 'JSONDecoder', 'JSONEncoder', '__all__', '__author__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', '_default_decoder', '_default_encoder', 'codecs', 'decoder', 'detect_encoding', 'dump', 'dumps', 'encoder', 'load', 'loads', 'scanner']

>>>


` Key Methods

- json.load(f): Load JSON data from file(or file-like object)

- json.loads(s): Load JSON data from a string

- json.dump(j, f): Write JSON object to file(or file-like object)

- json.dumps(j): Output JSON object as string








>>> movie2 = {}

>>> movie2["title"] = "Minority Report"

>>> movie2["director"] = "Steven Spielberg"

>>> movie2["composer"] = "John Williams"

>>> movie2["actors"] = ["Tom Cruise", "Colin Farrell",
    "Samantha Morton", "Max von Sydow"]

>>> movie2["is_awesome"] = True

>>> movie2["budget"] = 102000000

>>> movie2["cinematographer"] = "Janusz Kami\u0144ski"

>>> file2 = open("H:\python\movie_2.txt", "w", encoding="utf-8")

>>> json.dump(movie2, file2, ensure_ascii=False)

>>> file2.close()



- movie_2.txt

{"title": "Minority Report", "director": "Steven Spielberg", "composer": "John Williams", "actors": ["Tom Cruise", "Colin Farrell", "Samantha Morton", "Max von Sydow"], "is_awesome": true, "budget": 102000000, "cinematographer": "Janusz Kamiński"}

--------------------------------------------------------------------------------


` Lambda Expressions


- Anonymous Function = Lambda Expression



>>> # Write function to compute 3x+1

>>>

>>> def f(x):
return 3*x + 1

>>> f(3)
10

>>>

>>> lambda x: 3*x + 1
at 0x02476BF8>


>>> g = lambda x: 3*x+1

>>> g(3)
10

>>>


` Lambda expression with multiple inputs


>>> # Combine first name and last name into a single "Full Name"

>>>

>>> full_name = lambda fn, ln: fn.strip().title() + " " + ln.strip().title()

>>> full_name(" leonhard", "EULER")
'Leonhard Euler'



` Lambda Expressions

lambda : "What is my purpose?"

lambda x : 3*x+1

lambda x, y : (x*y)**0.5 # Geometric Mean

lambda x, y, z : 3/(1/x + 1/y + 1/z) # Harmonic Mean

...

lambda x1, x2, ..., xn :



` A function with no name...


>>> help(scifi_authors.sort)
Help on built-in function sort:

sort(*, key=None, reverse=False) method of builtins.list instance
    Sort the list in ascending order and return None.
 
    The sort is in-place (i.e. the list itself is modified) and stable (i.e. the
    order of two equal elements is maintained).
 
    If a key function is given, apply it once to each list item and sort them,
    ascending or descending, according to their function values.
 
    The reverse flag can be set to sort in descending order.


>>> scifi_authors.sort(key=lambda name: name.split(" ")[-1].lower())

>>> scifi_authors
['Douglas Adams', 'Isaac Asimov', 'Leigh Brackett', 'Ray Bradbury', 'Orson Scott Card', 'Arthus C. Clarke', 'Robert Heinlein', 'Frank Herbert', 'H. G. Wells']

>>>


` Quadratic Functions

- f(x) = ax2 + bx + c


>>> def build_quadratic_function(a, b, c):
"""Returns the function f(x) = ax^2 + bx + c"""
return lambda x: a*x**2 + b*x + c

>>> f = build_quadratic_function(2, 3, -5)

>>> f(0)
-5

>>> f(1)
0

>>> f(2)
9

>>> build_quadratic_function(3, 0, 1)(2) # 3x^2+1 evaluated for x=2
13


--------------------------------------------------------------------------------

` Map, Filter, Reduce


>>> import math

>>>

>>> def area(r):
"""Area of a circle with radius 'r'."""
return math.pi * (r**2)

>>> radii = [2, 5, 7.1, 0.3, 10]

>>>

>>> # Method 1: Direct method

>>>

>>> areas = []

>>> for r in radii:
a = area(r)
areas.append(a)


>>> areas
[12.566370614359172, 78.53981633974483, 158.36768566746147, 0.2827433388230814, 314.1592653589793]

>>>

>>> # Method 2: Use 'map' function

>>>

>>> map(area, radii)


>>> list(map(area, radii))
[12.566370614359172, 78.53981633974483, 158.36768566746147, 0.2827433388230814, 314.1592653589793]

>>>


` 'map' function

- Data : a1, a2, ..., an

- Function: f

- map(f, data): Returns iterator over
f(a1), f(a2), ..., f(an)



>>> temps = [("Berlin", 29), ("Cairo", 36), ("Buenos Aires", 19),
("Lost Angeles", 26), ("Tokyo", 27), ("New York", 28),
("London", 22), ("Beijing", 32)]
>>>

>>> c_to_f = lambda data: (data[0], (9/5)*data[1] + 32)

>>>

>>> list(map(c_to_f, temps))
[('Berlin', 84.2), ('Cairo', 96.8), ('Buenos Aires', 66.2), ('Lost Angeles', 78.80000000000001), ('Tokyo', 80.6), ('New York', 82.4), ('London', 71.6), ('Beijing', 89.6)]

>>>


` F = 9*C/5 + 32

` filter function

- Example : Find all data above the average.


>>> import statistics

>>>

>>> data = [1.3, 2.7, 0.8, 4.1, 4.3, -0.1]

>>> avg = statistics.mean(data)

>>> avg
2.183333333333333

>>>

>>> filter(lambda x: x > avg, data)


>>>

>>> list(filter(lambda x: x > avg, data))
[2.7, 4.1, 4.3]

>>>

>>> list(filter(lambda x: x < avg, data))
[1.3, 0.8, -0.1]

>>>

>>>

>>> # Remove missing data

>>>

>>> countries = ["", "Argentina", "", "Brazil", "Chile", "", "Colombia", "",
     "Ecuador", "", "Venezuela"]

>>>

>>> list(filter(None, countries))
['Argentina', 'Brazil', 'Chile', 'Colombia', 'Ecuador', 'Venezuela']

>>>


` False values

- "", 0, 0.0, 0j, [], (), {}, False, None, instances which signal they are empty


` reduce function

- In Python 3+, reduce is not a builtin function Moved to the 'functools' module

- "Use functools.reduce() if you really need it; however, 99% of the time an explicit for loop is more readable." by Guido van Rossum Python creator


`` reduce function

- Data : [a1, a2, a3, ..., an]
- Function : f(x, y)

- reduce(f, data):
Step 1: val1 = f(a1, a2)
Step 2: val2 = f(val1, a3)
Step 3: val3 = f(val2, a4)
...
Step n-1: valn-1 = f(valn-2, an)
Return valn-1

- Alternatively:
returns f(f(f(a1, a2), a3), a4), ..., an)


>>> from functools import reduce

>>>

>>> # Multiply all numbers in a list

>>>

>>> data = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

>>> multiplier = lambda x, y: x*y

>>> reduce(multiplier, data)
6469693230

>>>

>>> product = 1

>>> for x in data:
product = product * x


>>> product
6469693230


--------------------------------------------------------------------------------

` Sorting


>>> # Alkaline earth metals

>>> earth_metals = ["Beryllium", "Magnesium", "Calcium", "Strontium", "Barium", "Radium"]

>>> earth_metals.sort()

>>> earth_metals
['Barium', 'Beryllium', 'Calcium', 'Magnesium', 'Radium', 'Strontium']

>>>

>>> earth_metals.sort(reverse=True)

>>> earth_metals
['Strontium', 'Radium', 'Magnesium', 'Calcium', 'Beryllium', 'Barium']

>>>

>>> earth_metals = ("Beryllium", "Magnesium", "Calcium", "Strontium", "Barium", "Radium")

>>> earth_metals.sort()
Traceback (most recent call last):
  File "", line 1, in
    earth_metals.sort()
AttributeError: 'tuple' object has no attribute 'sort'


>>> help(list.sort)
Help on method_descriptor:

sort(self, /, *, key=None, reverse=False)
    Sort the list in ascending order and return None.
 
    The sort is in-place (i.e. the list itself is modified) and stable (i.e. the
    order of two equal elements is maintained).
 
    If a key function is given, apply it once to each list item and sort them,
    ascending or descending, according to their function values.
 
    The reverse flag can be set to sort in descending order.



---------------------------------------
reverse = False => Sort in ascending order
reverse = True => Sort in descending order

"in-place" algorithm
Does not create a 2nd data structure
Modifies input/existing structure
---------------------------------------

---------------------------------------
format := (name, radius, density, distance from Sun)

Radius: Radius at equator in kilometers
Density: Average density in g/cm3
Distance from Sun: Avg. distance to sun in AUs

1 Astronomical unit  - Average distance of Earth to Sun
---------------------------------------

>>> planets = [
("Mercury", 2440, 5.43, 0.395),
("Venus", 6052, 5.24, 0.723),
("Earth", 6378, 5.52, 1.000),
("Mars", 3396, 3.93, 1.530),
("Jupiter", 71492, 1.33, 5.210),
("Saturn", 60268, 0.69, 9.551),
("Uranus", 2559, 1.27, 19.213),
("Neptune", 24764, 1.64, 30.070)
]


>>> size = lambda planet: planet[1]

>>> planets.sort(key=size, reverse=True)

>>> planets
[('Jupiter', 71492, 1.33, 5.21), ('Saturn', 60268, 0.69, 9.551), ('Neptune', 24764, 1.64, 30.07), ('Earth', 6378, 5.52, 1.0), ('Venus', 6052, 5.24, 0.723), ('Mars', 3396, 3.93, 1.53), ('Uranus', 2559, 1.27, 19.213), ('Mercury', 2440, 5.43, 0.395)]

>>> density = lambda planet: planet[2]

>>> planets.sort(key=density)

>>> planets
[('Saturn', 60268, 0.69, 9.551), ('Uranus', 2559, 1.27, 19.213), ('Jupiter', 71492, 1.33, 5.21), ('Neptune', 24764, 1.64, 30.07), ('Mars', 3396, 3.93, 1.53), ('Venus', 6052, 5.24, 0.723), ('Mercury', 2440, 5.43, 0.395), ('Earth', 6378, 5.52, 1.0)]


---------------------------------------
list.sort() changes the list

Q: Can you create a sorted copy?
Q: How do you sort a tuple?
A : Use sorted()
-------------------------------------

>>> help(sorted)
Help on built-in function sorted in module builtins:

sorted(iterable, /, *, key=None, reverse=False)
    Return a new list containing all items from the iterable in ascending order.
 
    A custom key function can be supplied to customize the sort order, and the
    reverse flag can be set to request the result in descending order.



>>> earth_metals = ["Beryllium", "Magnesium", "Calcium", "Strontium", "Barium", "Radium"]

>>> sorted_earth_metals = sorted(earth_metals)

>>> sorted_earth_metals
['Barium', 'Beryllium', 'Calcium', 'Magnesium', 'Radium', 'Strontium']

>>> earth_metals
['Beryllium', 'Magnesium', 'Calcium', 'Strontium', 'Barium', 'Radium']

>>>

>>> data = (7,2,5,6,1,3,9,10,4,8)

>>> sorted(data)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

>>> data
(7, 2, 5, 6, 1, 3, 9, 10, 4, 8)

>>> sorted("Alphabetical")
['A', 'a', 'a', 'b', 'c', 'e', 'h', 'i', 'l', 'l', 'p', 't']


--------------------------------------------------------------------------------


` Text Files


` Text Files

- Plain Text
- XML
- JSON
- Source Code
...


` Binary Files

- Compiled code
- App data
- Media files (images, audio, video)


Help on built-in function open in module io:

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
    Open file and return a stream.  Raise OSError upon failure.
 
    file is either a text or byte string giving the name (and the path
    if the file isn't in the current working directory) of the file to
    be opened or an integer file descriptor of the file to be
    wrapped. (If a file descriptor is given, it is closed when the
    returned I/O object is closed, unless closefd is set to False.)
 
    mode is an optional string that specifies the mode in which the file
    is opened. It defaults to 'r' which means open for reading in text
    mode.  Other common values are 'w' for writing (truncating the file if
    it already exists), 'x' for creating and writing to a new file, and
    'a' for appending (which on some Unix systems, means that all writes
    append to the end of the file regardless of the current seek position).
    In text mode, if encoding is not specified the encoding used is platform
    dependent: locale.getpreferredencoding(False) is called to get the
    current locale encoding. (For reading and writing raw bytes use binary
    mode and leave encoding unspecified.) The available modes are:
 
    ========= ===============================================================
    Character Meaning
    --------- ---------------------------------------------------------------
    'r'       open for reading (default)
    'w'       open for writing, truncating the file first
    'x'       create a new file and open it for writing
    'a'       open for writing, appending to the end of the file if it exists
    'b'       binary mode
    't'       text mode (default)
    '+'       open a disk file for updating (reading and writing)
    'U'       universal newline mode (deprecated)
    ========= ===============================================================
 
    The default mode is 'rt' (open for reading text). For binary random
    access, the mode 'w+b' opens and truncates the file to 0 bytes, while
    'r+b' opens the file without truncation. The 'x' mode implies 'w' and
    raises an `FileExistsError` if the file already exists.
 
    Python distinguishes between files opened in binary and text modes,
    even when the underlying operating system doesn't. Files opened in
    binary mode (appending 'b' to the mode argument) return contents as
    bytes objects without any decoding. In text mode (the default, or when
    't' is appended to the mode argument), the contents of the file are
    returned as strings, the bytes having been first decoded using a
    platform-dependent encoding or using the specified encoding if given.
 
    'U' mode is deprecated and will raise an exception in future versions
    of Python.  It has no effect in Python 3.  Use newline to control
    universal newlines mode.
 
    buffering is an optional integer used to set the buffering policy.
    Pass 0 to switch buffering off (only allowed in binary mode), 1 to select
    line buffering (only usable in text mode), and an integer > 1 to indicate
    the size of a fixed-size chunk buffer.  When no buffering argument is
    given, the default buffering policy works as follows:
 
    * Binary files are buffered in fixed-size chunks; the size of the buffer
      is chosen using a heuristic trying to determine the underlying device's
      "block size" and falling back on `io.DEFAULT_BUFFER_SIZE`.
      On many systems, the buffer will typically be 4096 or 8192 bytes long.
 
    * "Interactive" text files (files for which isatty() returns True)
      use line buffering.  Other text files use the policy described above
      for binary files.
 
    encoding is the name of the encoding used to decode or encode the
    file. This should only be used in text mode. The default encoding is
    platform dependent, but any encoding supported by Python can be
    passed.  See the codecs module for the list of supported encodings.
 
    errors is an optional string that specifies how encoding errors are to
    be handled---this argument should not be used in binary mode. Pass
    'strict' to raise a ValueError exception if there is an encoding error
    (the default of None has the same effect), or pass 'ignore' to ignore
    errors. (Note that ignoring encoding errors can lead to data loss.)
    See the documentation for codecs.register or run 'help(codecs.Codec)'
    for a list of the permitted encoding error strings.
 
    newline controls how universal newlines works (it only applies to text
    mode). It can be None, '', '\n', '\r', and '\r\n'.  It works as
    follows:
 
    * On input, if newline is None, universal newlines mode is
      enabled. Lines in the input can end in '\n', '\r', or '\r\n', and
      these are translated into '\n' before being returned to the
      caller. If it is '', universal newline mode is enabled, but line
      endings are returned to the caller untranslated. If it has any of
      the other legal values, input lines are only terminated by the given
      string, and the line ending is returned to the caller untranslated.
 
    * On output, if newline is None, any '\n' characters written are
      translated to the system default line separator, os.linesep. If
      newline is '' or '\n', no translation takes place. If newline is any
      of the other legal values, any '\n' characters written are translated
      to the given string.
 
    If closefd is False, the underlying file descriptor will be kept open
    when the file is closed. This does not work when a file name is given
    and must be True in that case.
 
    A custom opener can be used by passing a callable as *opener*. The
    underlying file descriptor for the file object is then obtained by
    calling *opener* with (*file*, *flags*). *opener* must return an open
    file descriptor (passing os.open as *opener* results in functionality
    similar to passing None).
 
    open() returns a file object whose type depends on the mode, and
    through which the standard file operations such as reading and writing
    are performed. When open() is used to open a file in a text mode ('w',
    'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open
    a file in a binary mode, the returned class varies: in read binary
    mode, it returns a BufferedReader; in write binary and append binary
    modes, it returns a BufferedWriter, and in read/write mode, it returns
    a BufferedRandom.
 
    It is also possible to use a string or bytearray as a file for both
    reading and writing. For strings StringIO can be used like a file
    opened in a text mode, and for bytes a BytesIO can be used like a file
    opened in a binary mode.


>>> f = open("H:\python\movie_1.txt")

>>> text = f.read()

>>> f.close()

>>>

>>> print(text)
{
    "title" : "Gattaca",
    "release_year" : 1997,
    "is_awesome" : true,
    "won_oscar" : false,
    "actors" : ["Ethan Hawke", :"Uma Thurman", "Alan Arkin", "Loren Dean"],
    "budget" : null,
    "credits" : {
        "directory" : "Andrew Niccol",
        "writer" : "Andrew Niccol",
        "composer" : "Michael Nyman",
        "cinematographer" : "Slawomir Idziak"
    }
}



>>> with open("H:\python\movie_1.txt") as fobj:
movie = fobj.read()


>>> print(movie)
{
    "title" : "Gattaca",
    "release_year" : 1997,
    "is_awesome" : true,
    "won_oscar" : false,
    "actors" : ["Ethan Hawke", :"Uma Thurman", "Alan Arkin", "Loren Dean"],
    "budget" : null,
    "credits" : {
        "directory" : "Andrew Niccol",
        "writer" : "Andrew Niccol",
        "composer" : "Michael Nyman",
        "cinematographer" : "Slawomir Idziak"
    }
}




==========================================

with open("H:\python\future_lottery_numbers.txt") as f:
    text = f.read()

print(text)

==========================================

>>>
============== RESTART: C:/Users/purunet/Documents/py/test_text.py =============
Traceback (most recent call last):
  File "C:/Users/purunet/Documents/py/test_text.py", line 3, in
    with open("H:\python\future_lottery_numbers.txt") as f:
OSError: [Errno 22] Invalid argument: 'H:\\python\x0cuture_lottery_numbers.txt'
>>>

==========================================

try:
    with open("H:\python\movie_3.txt") as f:
        text = f.read()
except FileNotFoundError:
    text = None
 
print(text)

==========================================


>>>
============= RESTART: C:/Users/purunet/Documents/py/test_text2.py =============
None


>>>


==========================================

try:
    with open("H:\python\movie_1.txt") as f:
        text = f.read()
except FileNotFoundError:
    text = None
 
print(text)

==========================================

>>>
============= RESTART: C:/Users/purunet/Documents/py/test_text2.py =============
{
    "title" : "Gattaca",
    "release_year" : 1997,
    "is_awesome" : true,
    "won_oscar" : false,
    "actors" : ["Ethan Hawke", :"Uma Thurman", "Alan Arkin", "Loren Dean"],
    "budget" : null,
    "credits" : {
        "directory" : "Andrew Niccol",
        "writer" : "Andrew Niccol",
        "composer" : "Michael Nyman",
        "cinematographer" : "Slawomir Idziak"
    }
}


==========================================

oceans = ["Pacific", "Atlantic", "Indian", "Southern", "Arctic"]

with open("H:\python\oceans.txt", "w") as f:
    for ocean in oceans:
        f.write(ocean)

==========================================

- oceans.txt

PacificAtlanticIndianSouthernArctic


==========================================

oceans = ["Pacific", "Atlantic", "Indian", "Southern", "Arctic"]

with open("H:\python\oceans.txt", "w") as f:
    for ocean in oceans:
        f.write(ocean)
        f.write('\n')


==========================================

- oceans.txt

Pacific
Atlantic
Indian
Southern
Arctic

==========================================

oceans = ["Pacific", "Atlantic", "Indian", "Southern", "Arctic"]

with open("H:\python\oceans.txt", "w") as f:
    for ocean in oceans:
        print(ocean, file=f)

==========================================

- oceans.txt

Pacific
Atlantic
Indian
Southern
Arctic


==========================================

oceans = ["Pacific", "Atlantic", "Indian", "Southern", "Arctic"]

with open("H:\python\oceans.txt", "w") as f:
    for ocean in oceans:
        print(ocean, file=f)

with open("H:\python\oceans.txt", "a") as f:
    print(23*"=", file=f)
    print("These are the 5 oceans.", file=f)

==========================================

- oceans.txt

Pacific
Atlantic
Indian
Southern
Arctic
=======================
These are the 5 oceans.


--------------------------------------------------------------------------------

` Unit Tests



==========================================

from math import pi

def circle_area(r):
    return pi*(r**2)


# Test function
radii = [2, 0, -3, 2+5j, True, "radius"]
message = "Area of circles with r = {radius} is {area}."

for r in radii:
    A = circle_area(r)
    print(message.format(radius=r, area=A))

==========================================

>>>
============== RESTART: C:/Users/purunet/Documents/py/unit_test.py =============
Area of circles with r = 2 is 12.566370614359172.
Area of circles with r = 0 is 0.0.
Area of circles with r = -3 is 28.274333882308138.
Area of circles with r = (2+5j) is (-65.97344572538566+62.83185307179586j).
Area of circles with r = True is 3.141592653589793.
Traceback (most recent call last):
  File "C:/Users/purunet/Documents/py/unit_test.py", line 15, in
    A = circle_area(r)
  File "C:/Users/purunet/Documents/py/unit_test.py", line 7, in circle_area
    return pi*(r**2)
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
>>>


` Unit Tests


- Naming Convention #1

/ circles.py
/test_circles.py


- Naming Convention #2

/circles.py
/circles_test.py


--------circles.py---------

from math import pi

def circle_area(r):
return pi*(r**2)

------------------------


================test_circles.py============

import unittest
from circles import circle_area
from math import pi

class TestCircleArea(unittest.TestCase):
    def test_area(self):
        # Test areas when radius >= 0
        self.assertAlmostEqual(circle_area(1), pi)
        self.assertAlmostEqual(circle_area(0), 0)
        self.assertAlmostEqual(circle_area(2.1), pi * 2.1**2)

==========================================

C:\unit_tests>python -m unittest test_circles
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK



C:\unit_tests>python -m unittest
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK




================test_circles.py============

import unittest
from circles import circle_area
from math import pi

class TestCircleArea(unittest.TestCase):
    def test_area(self):
        # Test areas when radius >= 0
        self.assertAlmostEqual(circle_area(1), pi)
        self.assertAlmostEqual(circle_area(0), 0)
        self.assertAlmostEqual(circle_area(2.1), pi * 2.1**2)

    def test_values(self):
        # Make suer value errors are raised when necessary
        self.assertRaises(ValueError, circle_area, -2)

==========================================

C:\unit_tests>python -m unittest
.F
======================================================================
FAIL: test_values (test_circles.TestCircleArea)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\unit_tests\test_circles.py", line 17, in test_values
    self.assertRaises(ValueError, circle_area, -2)
AssertionError: ValueError not raised by circle_area

----------------------------------------------------------------------
Ran 2 tests in 0.002s

FAILED (failures=1)



==============circles.py===================

from math import pi

def circle_area(r):
    if r < 0:
        raise ValueError("The radius cannot be negative.")
    return pi*(r**2)

==========================================


C:\unit_tests>python -m unittest
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK


>>> import unittest

>>> help(unittest.TestCase.assertSetEqual)
Help on function assertSetEqual in module unittest.case:

assertSetEqual(self, set1, set2, msg=None)
    A set-specific equality assertion.
 
    Args:
        set1: The first set to compare.
        set2: The second set to compare.
        msg: Optional message to use on failure instead of a list of
                differences.
 
    assertSetEqual uses ducktyping to support different types of sets, and
    is optimized for sets specifically (parameters must support a
    difference method).


================test_circles.py============

import unittest
from circles import circle_area
from math import pi

class TestCircleArea(unittest.TestCase):
    def test_area(self):
        # Test areas when radius >= 0
        self.assertAlmostEqual(circle_area(1), pi)
        self.assertAlmostEqual(circle_area(0), 0)
        self.assertAlmostEqual(circle_area(2.1), pi * 2.1**2)

    def test_values(self):
        # Make suer value errors are raised when necessary
        self.assertRaises(ValueError, circle_area, -2)


    def test_types(self):
        # Make sure type errors are raised when necessary
        self.assertRaises(TypeError, circle_area, 3+5j)
        self.assertRaises(TypeError, circle_area, True)
        self.assertRaises(TypeError, circle_area, "radius")

==========================================

C:\unit_tests>python -m unittest
.F.
======================================================================
FAIL: test_types (test_circles.TestCircleArea)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\unit_tests\test_circles.py", line 23, in test_types
    self.assertRaises(TypeError, circle_area, True)
AssertionError: TypeError not raised by circle_area

----------------------------------------------------------------------
Ran 3 tests in 0.002s

FAILED (failures=1)


==============circles.py===================

from math import pi

def circle_area(r):
    if type(r) not in [int, float]:
        raise TypeError("The radius must be a non-negative real number.")
 
    if r < 0:
        raise ValueError("The radius cannot be negative.")
    return pi*(r**2)

==========================================


C:\unit_tests>python -m unittest
...
----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK


--------------------------------------------------------------------------------

` Exceptions



- "If you fail to plan, you are planning to fail."

- "If you fail to plan for failure, you are planning to fail as an engineer." - Socratica


` Exception Object:

- Description

- Traceback



` Mistakes are deliberate


==========================================

for i in range(5)
    print("Hello, world!")


==========================================

SyntaxError: invalid syntax


==========================================

for i in range(5):
    print("Hello, world!")


==========================================
>>>
========= RESTART: C:/Users/purunet/Documents/py/exceptions_tutorial.py ========
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
>>>

==========================================

1/0

==========================================


>>>
========= RESTART: C:/Users/purunet/Documents/py/exceptions_tutorial.py ========
Traceback (most recent call last):
  File "C:/Users/purunet/Documents/py/exceptions_tutorial.py", line 2, in
    1/0
ZeroDivisionError: division by zero


==========================================

with open("x_files.txt") as xf:
    the_truth = xf.read()

print(the_truth)

==========================================

>>>
========= RESTART: C:/Users/purunet/Documents/py/exceptions_tutorial.py ========
Traceback (most recent call last):
  File "C:/Users/purunet/Documents/py/exceptions_tutorial.py", line 2, in
    with open("x_files.txt") as xf:
FileNotFoundError: [Errno 2] No such file or directory: 'x_files.txt'




==========================================

1 + 2 + "three"

==========================================

>>>
========= RESTART: C:/Users/purunet/Documents/py/exceptions_tutorial.py ========
Traceback (most recent call last):
  File "C:/Users/purunet/Documents/py/exceptions_tutorial.py", line 2, in
    1 + 2 + "three"
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>>


==========================================

import math

print(math.sqrt(-1))

==========================================

>>>
========= RESTART: C:/Users/purunet/Documents/py/exceptions_tutorial.py ========
Traceback (most recent call last):
  File "C:/Users/purunet/Documents/py/exceptions_tutorial.py", line 4, in
    print(math.sqrt(-1))
ValueError: math domain error
>>>


- For complex numbers, use 'cmath' module


` Objective:

- Write function that reads binary file and returns data
- Measure time required




==========================================

import logging
import time

# Create logger
logging.basicConfig(filename = "H:\python\problems.log", level = logging.DEBUG)
logger = logging.getLogger()

def read_file_timed(path):
    """Return the contents of the file at 'path' and measure time required."""
    start_time = time.time()
    try:
        f = open(path, mode='rb')
        data = f.read()
        return data
    except FileNotFoundError as err:
        logger.error(err)
        raise
    else:
        f.close()
    finally:
        stop_time = time.time()
        dt = stop_time - start_time
        logger.info("Time required for {file} = {time}".format(file=path, time=dt))

    data = read_file_timed("H:\python\aaa.mp3")

==========================================

- Do, or do not. There is no try.

--------------------------------------------------------------------------------

` Urllib


` URL(Uniform Resource Locator)


ex) https://en.wikipedia.org/wiki/URL?key=value&life=42#History

- Protocol : http, https, ftp, ...
- Host : en.wikipedia.org
- Port : http=80, https=443
- Path : wiki/URL
- Querystring : key=value&life=42
- Fragment : History



` urllib

- request : open URLs
- response : (used internally)
- error : request exceptions
- parse : useful URL functions
- robotparser : robots.txt files


>>> import urllib

>>> dir(urllib)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'parse']
>>>

>>> from urllib import request

>>> dir(request)
['AbstractBasicAuthHandler', 'AbstractDigestAuthHandler', 'AbstractHTTPHandler', 'BaseHandler', 'CacheFTPHandler', 'ContentTooShortError', 'DataHandler', 'FTPHandler', 'FancyURLopener', 'FileHandler', 'HTTPBasicAuthHandler', 'HTTPCookieProcessor', 'HTTPDefaultErrorHandler', 'HTTPDigestAuthHandler', 'HTTPError', 'HTTPErrorProcessor', 'HTTPHandler', 'HTTPPasswordMgr', 'HTTPPasswordMgrWithDefaultRealm', 'HTTPPasswordMgrWithPriorAuth', 'HTTPRedirectHandler', 'HTTPSHandler', 'MAXFTPCACHE', 'OpenerDirector', 'ProxyBasicAuthHandler', 'ProxyDigestAuthHandler', 'ProxyHandler', 'Request', 'URLError', 'URLopener', 'UnknownHandler', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', '_cut_port_re', '_ftperrors', '_have_ssl', '_localhost', '_noheaders', '_opener', '_parse_proxy', '_proxy_bypass_macosx_sysconf', '_randombytes', '_safe_gethostbyname', '_splitattr', '_splithost', '_splitpasswd', '_splitport', '_splitquery', '_splittag', '_splittype', '_splituser', '_splitvalue', '_thishost', '_to_bytes', '_url_tempfiles', 'addclosehook', 'addinfourl', 'base64', 'bisect', 'build_opener', 'contextlib', 'email', 'ftpcache', 'ftperrors', 'ftpwrapper', 'getproxies', 'getproxies_environment', 'getproxies_registry', 'hashlib', 'http', 'install_opener', 'io', 'localhost', 'noheaders', 'os', 'parse_http_list', 'parse_keqv_list', 'pathname2url', 'posixpath', 'proxy_bypass', 'proxy_bypass_environment', 'proxy_bypass_registry', 'quote', 're', 'request_host', 'socket', 'ssl', 'string', 'sys', 'tempfile', 'thishost', 'time', 'unquote', 'unquote_to_bytes', 'unwrap', 'url2pathname', 'urlcleanup', 'urljoin', 'urlopen', 'urlparse', 'urlretrieve', 'urlsplit', 'urlunparse', 'warnings']

>>>

- Files : open(file)
- URLs : urlopen(url)


>>> resp = request.urlopen("https://www.wikipedia.org")

>>> type(resp)
class 'http.client.HTTPResponse'

>>> dir(resp)
['__abstractmethods__', '__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_abc_impl', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', '_check_close', '_close_conn', '_get_chunk_left', '_method', '_peek_chunked', '_read1_chunked', '_read_and_discard_trailer', '_read_next_chunk_size', '_read_status', '_readall_chunked', '_readinto_chunked', '_safe_read', '_safe_readinto', 'begin', 'chunk_left', 'chunked', 'close', 'closed', 'code', 'debuglevel', 'detach', 'fileno', 'flush', 'fp', 'getcode', 'getheader', 'getheaders', 'geturl', 'headers', 'info', 'isatty', 'isclosed', 'length', 'msg', 'peek', 'read', 'read1', 'readable', 'readinto', 'readinto1', 'readline', 'readlines', 'reason', 'seek', 'seekable', 'status', 'tell', 'truncate', 'url', 'version', 'will_close', 'writable', 'write', 'writelines']
>>>


>>> resp.code
200


` HTTP Status Codes

- 200 : OK

- 400 : Bad Request
- 403 : Forbidden
- 404 : Not Found
...

>>> resp.length
69046

>>> resp.peek()

>>> resp.read()
b''


>>> resp = request.urlopen("https://www.google.com/search?q=socratica")
Traceback (most recent call last):
  File "", line 1, in
    resp = request.urlopen("https://www.google.com/search?q=socratica")
  File "C:\Users\purunet\AppData\Local\Programs\Python\Python38-32\lib\urllib\request.py", line 222, in urlopen
    return opener.open(url, data, timeout)
  File "C:\Users\purunet\AppData\Local\Programs\Python\Python38-32\lib\urllib\request.py", line 531, in open
    response = meth(req, response)
  File "C:\Users\purunet\AppData\Local\Programs\Python\Python38-32\lib\urllib\request.py", line 640, in http_response
    response = self.parent.error(
  File "C:\Users\purunet\AppData\Local\Programs\Python\Python38-32\lib\urllib\request.py", line 569, in error
    return self._call_chain(*args)
  File "C:\Users\purunet\AppData\Local\Programs\Python\Python38-32\lib\urllib\request.py", line 502, in _call_chain
    result = func(*args)
  File "C:\Users\purunet\AppData\Local\Programs\Python\Python38-32\lib\urllib\request.py", line 649, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 403: Forbidden
>>>

>>> # https://www.youtube.com/watch?v=EuC-yVzHhMI&t=5m56s

>>>

>>> qs = "v=" + "EuC-yVzHhMI" + "&" + "t=" + "5m56s"

>>>

>>> from urllib import parse

>>> dir(parse)
['DefragResult', 'DefragResultBytes', 'MAX_CACHE_SIZE', 'ParseResult', 'ParseResultBytes', 'Quoter', 'ResultBase', 'SplitResult', 'SplitResultBytes', '_ALWAYS_SAFE', '_ALWAYS_SAFE_BYTES', '_DefragResultBase', '_NetlocResultMixinBase', '_NetlocResultMixinBytes', '_NetlocResultMixinStr', '_ParseResultBase', '_ResultMixinBytes', '_ResultMixinStr', '_SplitResultBase', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_asciire', '_checknetloc', '_coerce_args', '_decode_args', '_encode_result', '_hexdig', '_hextobyte', '_hostprog', '_implicit_encoding', '_implicit_errors', '_noop', '_parse_cache', '_portprog', '_safe_quoters', '_splitattr', '_splithost', '_splitnetloc', '_splitnport', '_splitparams', '_splitpasswd', '_splitport', '_splitquery', '_splittag', '_splittype', '_splituser', '_splitvalue', '_to_bytes', '_typeprog', 'clear_cache', 'collections', 'namedtuple', 'non_hierarchical', 'parse_qs', 'parse_qsl', 'quote', 'quote_from_bytes', 'quote_plus', 're', 'scheme_chars', 'splitattr', 'splithost', 'splitnport', 'splitpasswd', 'splitport', 'splitquery', 'splittag', 'splittype', 'splituser', 'splitvalue', 'sys', 'to_bytes', 'unquote', 'unquote_plus', 'unquote_to_bytes', 'unwrap', 'urldefrag', 'urlencode', 'urljoin', 'urlparse', 'urlsplit', 'urlunparse', 'urlunsplit', 'uses_fragment', 'uses_netloc', 'uses_params', 'uses_query', 'uses_relative', 'warnings']

>>>

>>> params = {"v": "EuC-yVzHhMI", "t": "5m56s"}

>>> querystring = parse.urlencode(params)

>>> querystring
'v=EuC-yVzHhMI&t=5m56s'

>>> url = "https://www.youtube.com/watch" + "?" + querystring

>>> resp = request.urlopen(url)

>>> resp.isclosed()
False

>>> resp.code
200

>>> html = resp.read().decode("utf-8")

>>> html[:500]
'