Helpful Basics#

To run tutorials in your browser, go to this Binder page.

You can also watch a video demo on YouTube (subscriptions & likes appreciated!).

1. Python and Jupyter Notebook#

  • Launching Python through Jupyter Notebook

    • Tutorial from Software Carpentry

    • For people who are using PyCharm, follow this post to install and run Jupyter Notebook (either in PyCharm or in your browser)

  • Make new notebooks

  • Code vs. Markdown cells

    • Edit/escape, copy/cut, insert, delete

    • Simple Markdown syntax

    • For more cheatsheets on Markdown (and markup languages), check out the Supplementary Material module of QSDedu

  • Close notebook and quit Jupyter Notebook


Note#

It’s OK if you don’t have Jupyter Notebook, you can launch Python through IDEs like PyCharm or Spyder (or just terminal/command prompt if you prefer) and follow the tutorials.


Back to top

2. import qsdsan#

[1]:
# When I do `import qsdsan`, how does Python know where to look for qsdsan?
# This is the same as `import qsdsan`, then `qs1 = qsdsan`
import qsdsan as qs1
print(f'Path for the first qsdsan package is {qs1.__path__}.')
Path for the first qsdsan package is ['/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/site-packages/qsdsan'].

Tip#

The ‘f’ prefix stands for “fancy print”, it allows the plain print function to look nicer. It’s a feature of newer Python, before this, you either have to do:

[2]:
info = 'Path for the first qsdsan package is ' + str(qs1.__path__) + '.'
print(info)
# `print('Path for the first qsdsan package is', qs1.__path__, '.')` works as well
Path for the first qsdsan package is ['/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/site-packages/qsdsan'].

Or use something like this:

[3]:
print('Path for the first qsdsan package is {}.'.format(qs1.__path__))
Path for the first qsdsan package is ['/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/site-packages/qsdsan'].

Or this:

[4]:
print('Path for the first qsdsan package is %s.' % qs1.__path__)
Path for the first qsdsan package is ['/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/site-packages/qsdsan'].

[5]:
# When doing importing, Python will look into the directories (i.e., folders) in the order of the `sys.path` list
import os, sys
print(sys.path)
['/Users/yalinli_cabbi/Code/QSDsan/docs/source/tutorials', '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python38.zip', '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8', '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/lib-dynload', '', '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/site-packages', '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/site-packages/IPython/extensions', '/Users/yalinli_cabbi/.ipython']
[6]:
# That's way too ugly, let's do it in a nicer way
for i in sys.path:
    print(i)
/Users/yalinli_cabbi/Code/QSDsan/docs/source/tutorials
/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python38.zip
/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8
/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/lib-dynload

/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/site-packages
/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/site-packages/IPython/extensions
/Users/yalinli_cabbi/.ipython
[7]:
# If Python cannot find the package from any of those directories, it will complain something like
# uncomment the following to try
# import happy_wednesday

If you’re a developer of qsdsan, you probably have cloned the qsdsan repository on Github to a local folder (let’s say, cloned_path). So if you want to import the cloned/local version of qsdsan (i.e., the one you’re developing rather than the stable version released on pypi), you need to ensure that:

  1. cloned_path is in sys.path

  2. cloned_path is of higher priority (e.g., in front of) the pip-installed path, which is usually the one that has “site-packages”)

[8]:
# Currently cloned_path is not in `sys.path`, so we will use the `insert` function to insert it
# but what if I don't know how to use that function?
# then try this
sys.path.insert?
[9]:
# Or this (which is more verbose)
help(sys.path.insert)
Help on built-in function insert:

insert(index, object, /) method of builtins.list instance
    Insert object before index.


Tip#

If you look closer, you’ll find that the help info says “insert(index, object, /) method of builtins.list instance”, not “insert(index, object, /) method of sys.path”.

This is because sys.path is an instance of the list class, and so it automatically “inherits” all the methods (i.e., functions) that are associated with a list object, and that is (imo) one of the biggest feature/advantage of object orientated programming (OOP).

You may note that I sometimes refer list as a “class” but sometimes as an “object”. Both are correct, because in OOP languages everything is an object.

But “instance” and “class” cannot be used interchangably, “instance” is, as the name suggests, a practical example of the “class”.

E.g., you can think of me as a postdoc, since I have the common attributes of a postdoc (have a Ph.D. degree thus permanent head damage, etc.), but you cannot equate me to the entire postdoc “class”.

There is much more to “class”, e.g., one subclass (and instances of that subclass) can inherit attributes from all of its super classes (sub/super sometimes referred to as child/parent). Just like I can also belong to another class called “cat-owner”, the “instances” (i.e., member) of which all have cat(s) and suffer from grumpy litter-generator creatures like this:

[10]:
from IPython.display import Image
Image(url='https://upload.wikimedia.org/wikipedia/commons/d/dc/Grumpy_Cat_%2814556024763%29_%28cropped%29.jpg', width=200)
[10]:
[11]:
# So how do I know `sys.path` is a list?
type(sys.path)
[11]:
list
[12]:
# And another built-in function we often use in `if` statement is
isinstance(sys.path, list)
[12]:
True
[13]:
# E.g.
if isinstance(sys.path, list):
    print('sys.path is a list.')
else:
    print('sys path is NOT a list')
sys.path is a list.
[14]:
# To make it fancier, (and show off some advanced Python tips), we can change it to a one-liner,
# this is exactly the same as the `if... else...` statement above
info = 'sys.path is a list.' if isinstance(sys.path, list) else 'sys.path is NOT a list.'
print(info)
sys.path is a list.
[15]:
# Since we have gone into the rabbit hole, why not use fancy print?
print(f'The statement that "sys.path is a list" is {isinstance(sys.path, list)}.')
The statement that "sys.path is a list" is True.

Then there are another whole set of issues related to method resolution order (mro, i.e., which of the super classes’ attributes take priority over others), etc., but that’s for advanced Python, and we’ll skip this topic now.


Note:

We need to restart the kernel at this moment, or the already imported, pip-installed qsdsan will always be there.

[1]:
# Now I'll attempt to import another qsdsan (cloned the GitHub version) on my computer,
# firstly you need to figure out where that is (i.e., where you cloned it to)
# demo on how to find it
cloned_path = '/Users/yalinli_cabbi/coding/qs'
[2]:
# Then let's insert the cloned path into our system path
import sys
sys.path.insert(0, cloned_path)
sys.path
[2]:
['/Users/yalinli_cabbi/coding/qs',
 '/Users/yalinli_cabbi/Code/QSDsan/docs/source/tutorials',
 '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python38.zip',
 '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8',
 '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/lib-dynload',
 '',
 '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/site-packages',
 '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/site-packages/IPython/extensions',
 '/Users/yalinli_cabbi/.ipython']

You can see that the first path is the cloned path

[3]:
# So now let's try this importing again
import qsdsan as qs2
print(f'Path for the second qsdsan package is {qs2.__path__}.')
Path for the second qsdsan package is ['/Users/yalinli_cabbi/coding/qs/qsdsan'].

So we successfully import qsdsan from another place

Note:

The changes to sys.path is temporary, so if we restart the kernel and recheck the path:

[1]:
# Our previous added cloned_path is gone
import sys
sys.path
[1]:
['/Users/yalinli_cabbi/Code/QSDsan/docs/source/tutorials',
 '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python38.zip',
 '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8',
 '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/lib-dynload',
 '',
 '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/site-packages',
 '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/site-packages/IPython/extensions',
 '/Users/yalinli_cabbi/.ipython']
[2]:
# If we try to import again
import qsdsan as qs3
qs3
[2]:
<module 'qsdsan' from '/Users/yalinli_cabbi/opt/anaconda3/envs/demo/lib/python3.8/site-packages/qsdsan/__init__.py'>

We are now back to the pip-installed qsdsan :)

[3]:
# Finally, if you want to see which version of the qsdsan you are running
qs3.__version__
[3]:
'1.2.0'

Back to top