Giter Club home page Giter Club logo

learning_python's Introduction

Python Like You Mean It

View this content as hosted on Python Like You Mean It

This repository contains the source material for the website Python Like You Mean It. The site is written primarily in Jupytext-markdown (which are eventually transformed into html using nbsphinx). A huge perk of this of this is that you simply need to be familiar with Jupyter notebooks and some markdown syntax in order to contribute to this project!

Asking Questions

Please feel free to post questions (or point out mistakes) about the reading by opening a GitHub issue. Someone from the PLYMI team will respond ASAP! Refer to this reference to see how to include python-codeblocks in your post. This will make it much easier for us to discuss code with each other.

How To Contribute

Contributions to this project are very welcome! I will be sure to credit any/all contributions (unless your want to remain anonymous). Some great ways to help out are to:

  • proofread
  • add reading comprehension exercises to existing sections
  • provide general feedback about the organization of the website, the consistency of the material, etc.
  • create lengthier standalone problems to serve as holistic examples of how to apply the concepts presented in the reading
  • recommend new sections to be added to PLYMI

You can either open an issue to provide feedback or point out errors, or you can create a pull request if you want to submit new/modified materials. The other maintainers of PLYMI and I are happy to help you refine your issues and PRs, so please do not be discouraged if you are new to Git/GitHub.

I have posted a number of "To-Do" tasks in this project's issues page, and I will be adding to these as this project progresses. Included are requests for proofreading and exercises. Please post within an issue if you are working on a to-do item, so multiple people don't end up working on the same task. General feedback on content is also hugely valuable, so feel free to open a new issue to provide your feedback on any of the material.

Here is a nice Markdown "cheat sheet" for looking up how to make tables, code-blocks, etc., in Markdown.

Making a Pull Request

If you want to submit a change to some of the content (e.g. correcting typos), do the following:

  1. Fork this repository
  2. Create a new branch, appropriately named for whatever task you are performing: git checkout -b your_branch_name
  3. In your new branch, make the relevant changes and commit them.
  4. Push your branch to your fork: git push origin your_branch_name
  5. Create a Pull Request from your fork branch into the master branch of this repo.

Building the Site

Important Note: it is strongly preferred that pull requests do not contain changes to the HTML of this site. Rather, it is better if PRs simply contain changes to text files (.rst or .md). A site administrator (@rsokl, @davidmascharka) will be responsible for publishing the actual site-HTML. Thus the following instructions are useful for you to view your changes as they will appear in the site, but you likely need not go through the process of committing the changes to the HTML.

Creating a Conda Environment From Scratch

First, create a miniconda environment. We'll call it plymi and will use Python 3.8

conda create -n plymi python=3.8

It is important that we activate the environment before proceeding

Next, we'll use the conda-forge package channel to install our dependencies

conda install -c conda-forge sphinx==4.4.0 jupytext==1.13.6 nbsphinx==0.8.8 pandoc==2.1.3 sphinx_rtd_theme==1.0.0 ipykernel==6.7.0 numpy matplotlib

pip install mygrad

Finally, we will install the plymi code base from this repo. Clone the present repository and run:

pip install .

Using this environment, you should now be able to run sphinx to build the html for this site from the source-code. To do this, run the following commands in your Python terminal:

import plymi
plymi.convert_src_to_html("./Python") # point to the dir containing `conf.py`

This will convert all of the "restructured text" (.rst) files to html via sphinx. jupytext is responsible for converting the markdown (.md) files to jupyter notebooks (.ipynb) and then nbsphinx converts these notebooks to html. These html files will be located in Python/_build. You can open the index.html page in your browser to view how the locally-built site looks on your computer.

Note that, if you are introducing a new page to the site or are doing anything that would affect the site's navigation-bar, it is a good idea to delete the _build directory before building the html. This will make sure that sphinx fully generates the pages from scratch.

Publishing HTML for this site

Once you have built the html and have verified that it looks good to you, navigate to the top level of the repository and run:

import plymi
plymi.build_to_doc(".") # point to the top-level dir (contains both `docs/` and `docs_backup`)

This will back-up your current docs directory, and will move the html from _builds to docs. It will also ensure some essential "meta" files, .nojekyll and CNAME are present. The former is required for githubpages to build the site correctly, the latter ensures that the canonical name for the site is pythonlikeyoumeanit.com.

The only directories in this repository that contain html should be docs and docs_backup. Do not commit the _build directory

learning_python's People

Contributors

artichokesap avatar aylew avatar carlosperezm avatar darshankrishnaswamy avatar davidmascharka avatar dmoore04 avatar donkirkby avatar irizwaririz avatar jclu2688 avatar ravichandraveeramachaneni avatar rsokl avatar samaocarpenter avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

learning_python's Issues

Module 5 Packages typo fix

Fixed Typo

Note that the module is still being executed in full, however instead of producing the module-instance my_module, this import statement instead only returns the specified objects that were defined in the module.

C++/C vs Python

@davidmascharka do you have a better example that can demonstrate the simplicity of Python code, compared to C or C++? The hello world example is kinda BS, because it is just a matter of boilerplate code. Do you think a better example is warranted?

If you can think of anything, feel free to just post code snippets here

Module 3 General Feedback

This is pretty much the same thing I did for the first two modules. My apologies if I mention something that has already been fixed as I have been reading everything over the course of a few days. And again, if you need help with anything else I'd be happy to help!

Module 3

Accessing Data along Multiple Dimensions Exercises (in the exercises folder)

In def solution_1(x) the comment says to delete pass but it currently has return None in the function definition and not pass.
Good catch on making sure that the original array is manipulated so that the answer can't just be hard-coded. But, perhaps provide guidance for why the solution x[0:1] which returns an array of the shape (1,3,3) is incorrect when the answer is looking for an array of shape (3,3)

Accessing Data along Multiple Dimensions (actual content)

Under two-dimensional arrays section, there is a line that says "where the desire to.. is manifestly desirable". I don't think manifestly works here since it is an adverb and desirable is not a verb.

Under the Introduction to reshape section, perhaps clarify that x.reshape() doesn't actually change the numpy array x. The comments for the code in that section makes it seem as if it is exactly the same as x= x.reshape(), which actually changes the shape of x.

Array Traversal

It might be nice to explain the usefulness of row vs. column traversal and how it might affect whether you end up with a row or a copy. This can be seen in the example below.

This produces a view

>>> a = np.arange(12).reshape(3, 4)
>>> a[0:3:2, :][:, [0, 2]] = 100
>>> a
array([[100,   1, 100,   3],
       [  4,   5,   6,   7],
       [100,   9, 100,  11]])

This produces a copy

>>> a[:, [0, 2]][0:3:2, :] = 0
>>> a
array([[100,   1, 100,   3],
       [  4,   5,   6,   7],
       [100,   9, 100,  11]])

Since there is no way to traverse the array column-wise with a single start, size, and stride, it cannot be constructed into a view like it was when traversed row-wise.

Basic Array Attributes

Since there isn't a module on OOP (yet, at least), maybe explain more in depth of why these attributes don't need parenthesis to be accessed. I know this is a mistake I made a lot when first starting out.

'x.shape' and not 'x.shape()'

Broadcasting

I know the linear algebra section is very brief, but perhaps mention that broadcasting is just a convenient tool provided in numpy and not actually done in linear algebra.
For ex, numpy will multiply a (2,3) and (2,1) matrix, which can't be done normally.

Also, in reading comprehension: broadcast compatibility,
asking whether or not a 7 x 2 with a 7 will work seems ambiguous because a 7 x 2 with a 7, will not work but a 7 x 2 with a 7 x 1 will work.

In reading comprehension: basic broadcasting, a small comment is that np.random.rand will give numbers between 0 and 1, but the example results in the comment give numbers like 2 and 3. This might cause potential confusion and make the user doubt the numbers they're getting (although this can easily be checked through the solutions that's why this is just a side note)

Finally, I found a notebook pretty similar to this one that might be a nice add-on/ might provide ideas for more content; http://scipy-cookbook.readthedocs.io/index.html

More things to do

For those who are interesting in contributing more to PLYMI:

I would like to improve the consistency of PLYMI. One of the most inconsistent aspects of the site are the solutions to the reading comprehension questions at the end of each section. These vary wildly in format and length of discussion. It would be great to have improved uniformity here.

More broadly, any feedback on the overall organization of the site/modules and recommendations towards this end would be great.

More reading comprehension and end-of-module questions/solutions are always welcome :)

Lastly, and this is probably too broad to be actionable, module 4 (OOP) is pretty lame. I think it needs better motivation and context for the readers.

Need requirements.txt for building PLYMI

Current versions that successfully build plymi

  • Python 3.7
  • nbsphinx 0.4.2
  • sphinx 1.8.4
  • pandoc 2.1.3
  • nbconvert 5.3.1 (5.4.1 was needed on my surface...)
  • jupytext 1.1.1
  • numpy
  • matplotlib
  • sphinx_rtd_theme 0.4.3

Adding links to Chinese version

The Chinese translation of the site is currently hosted on https://alexding123.github.io/Learning_Python/. It'd be great if you could add a permanent redirect (without path redirect) on your domain's synthetic record slot from subdomain cn to this link so that the site can be viewed on https://cn.pythonlikeyoumeanit.com. #102 provides a preliminary pull request to add the cross-link to the Chinese site's URL, though it requires you to generate the HTML on your site on the branch push the results before merging (my computer generate slightly different HTML and .doctree files that would screw up the commit history).

New Section Idea: Exceptions

One important aspect of Python that isn't discussed in PLYMI is Python's exceptions, what causes them, and how to create your own. I feel like an additional section in the Odds And Ends Module would be appropriate, discussing

  • The different types of exceptions and what they mean
  • Assert statements and how to use them
  • Raise statements and how to use them
  • Creating a new exception with Python's Exception object

I'd love to write up this section for the site. Is this something that you guys find appropriate? @rsokl @davidmascharka

sliding window

def sliding_window_view(arr, window_shape, step, dilation=None):
    """ Create a sliding window view over the trailing dimesnions of an array. 
        No copy is made.
        
        The window is applied only to valid regions of `arr`, but is applied geedily. 
        
        See Notes section for details.
        
        Parameters
        ----------
        arr : numpy.ndarray, shape=(..., [x, (...), z])
            C-ordered array over which sliding view-window is applied along the trailing
            dimensions [x, ..., z], as determined by the length of `window_shape`.
            
        window_shape : Sequence[int]
            Specifies the shape of the view-window: [Wx, (...), Wz].
            The length of `window_shape` determines the length of [x, (...) , z]
            
        step : Union[int, Sequence[int]]
            The step sized used along the [x, (...), z] dimensions: [Sx, (...), Sz].
            If a single integer is specified, a uniform step size is used.
            
        dilation : Optional[Sequence[int]]
            The dilation factor used along the [x, (...), z] directions: [Dx, (...), Dz].
            If no value is specified, a dilation factor of 1 is used along each direction.
            Dilation specifies the step size used when filling the window's elements
            
        Returns
        -------
        A contiguous view of `arr`, of shape ([X, (...), Z], ..., [Wx, (...), Wz]), where
        [X, ..., Z] is the shape of the grid on which the window was applied. See Notes
        sections for more details.
        
        Notes
        -----
        Window placement:
            Given a dimension of size x, with a window of size W along this dimension, applied
            with stride S and dilation D, the window will be applied
                                      X = (x - (W - 1) * D + 1) // S + 1
            number of times along that dimension.
            
        Interpreting output:
            In general, given an array `arr` of shape (..., x, (...), z), and
                `out = sliding_window_view(arr, window_shape=[Wx, (...), Wz], step=[Sx, (...), Sz])`
            the indexing `out` with [ix, (...), iz] produces the following view of x:
            
                `out[ix, (...), iz] ==
                    x[..., ix*Sx:(ix*Sx + Wx*Dx):Dx, (...), iz*Sz:(iz*Sz + Wz*Dz):Dz]`
                    
            For example, suppose `arr` is an array of shape (10, 12, 6). Specifying sliding
            window of shape (3, 3) with step size (2, 2), dilation (2, 1) will create the view:
            
                            [[arr[:,  0:6:2, 0:3], arr[:,   0:6:3, 3:6]]
                             [arr[:, 6:12:2, 0:3], arr[:, 6:12:12, 3:6]]]
                             
            producing a view of shape (2, 2, 10, 3, 3) in total.
            
        Examples
        --------
        >>> import numpy as np
        >>> x = np.arange(36).reshape(6, 6)
        >>> x
        array([[ 0,  1,  2,  3,  4,  5],
               [ 6,  7,  8,  9, 10, 11],
               [12, 13, 14, 15, 16, 17],
               [18, 19, 20, 21, 22, 23],
               [24, 25, 26, 27, 28, 29],
               [30, 31, 32, 33, 34, 35]])
         
        Apply an 3x2 window with step-sizes of (2, 2). This results in
        the window being placed twice along axis-0 and three times along axis-1.
        >>> y = sliding_window_view(x, step=(2, 2), window_shape=(3, 2))
        >>> y.shape
        (2, 3, 3, 2)
        
        # window applied at (0, 0)
        >>> y[0, 0]
        array([[ 0,  1],
               [ 6,  7],
               [12, 13]])
        
        # window applied at (2, 0)
        >>> y[1, 0]
        array([[12, 13],
               [18, 19],
               [24, 25]])
        
        # window applied at (0, 2)
        >>> y[0, 1]
        array([[ 2,  3],
               [ 8,  9],
               [14, 15]])
               
        >>> i, j = np.random.randint(0, 2, size=2)
        >>> wx, wy = (2, 2)
        >>> sx, sy = (2, 2)
        >>> np.all(y[i, j] == x[..., i*sx:(i*sx + wx), j*sy:(j*sy + wy)])
        True
        """

    from numbers import Integral
    from numpy.lib.stride_tricks import as_strided
    import numpy as np

    step = tuple(int(step) for i in range(len(window_shape))) if isinstance(step, Integral) else tuple(step)
    assert all(isinstance(i, Integral) and i > 0 for i in step), "`step` be a sequence of positive integers"

    window_shape = tuple(window_shape)
    if not all(isinstance(i, Integral) and i > 0 for i in window_shape):
        msg = "`window_shape` be a sequence of positive integers"
        raise AssertionError(msg)

    if len(window_shape) > arr.ndim:
        msg = """ `window_shape` cannot specify more values than `arr.ndim`."""
        raise AssertionError(msg)

    if any(i > j for i,j in zip(window_shape[::-1], arr.shape[::-1])):
        msg = """ The window must fit within the trailing dimensions of `arr`."""
        raise AssertionError(msg)

    if dilation is None:
        dilation = np.ones((len(window_shape),), dtype=int)
    else:
        if isinstance(dilation, Integral):
            dilation = tuple(int(dilation) for i in range(len(window_shape)))
        else:
            np.asarray(dilation)
            assert all(isinstance(i, Integral) for i in dilation)
            if any(w*d > s for w,d,s in zip(window_shape[::-1], dilation[::-1], arr.shape[::-1])):
                msg = """ The dilated window must fit within the trailing dimensions of `arr`."""
                raise AssertionError(msg)

    step = np.array(step)  # (Sx, ..., Sz)
    window_shape = np.array(window_shape)  # (Wx, ..., Wz)
    in_shape = np.array(arr.shape[-len(step):])  # (x, ... , z)
    nbyte = arr.strides[-1]  # size, in bytes, of element in `arr`

    # per-byte strides required to fill a window
    win_stride = tuple(np.cumprod(arr.shape[:0:-1])[::-1]) + (1,)

    # per-byte strides required to advance the window
    step_stride = tuple(win_stride[-len(step):] * step)

    # update win_stride to accommodate dilation
    win_stride = np.array(win_stride)
    win_stride[-len(step):] *= dilation
    win_stride = tuple(win_stride)

    # tuple of bytes to step to traverse corresponding dimensions of view
    # see: 'internal memory layout of an ndarray'
    stride = tuple(int(nbyte * i) for i in step_stride + win_stride)

    # number of window placements along x-dim: X = (x - (Wx - 1)*Dx + 1) // Sx + 1
    out_shape = tuple((in_shape - ((window_shape - 1) * dilation + 1)) // step + 1)

    # ([X, (...), Z], ..., [Wx, (...), Wz])
    out_shape = out_shape + arr.shape[:-len(step)] + tuple(window_shape)
    out_shape = tuple(int(i) for i in out_shape)

    return as_strided(arr, shape=out_shape, strides=stride, writeable=False)


def unit_test(num_trials):
    import numpy as np
    for i in range(num_trials):
        ndim = np.random.randint(1, 5)
        shape = np.random.choice(range(1,10), size=ndim)
        win_dim = np.random.randint(1, ndim+1)
        win_shape = tuple(int(np.random.randint(1, i+1)) for i in shape[-win_dim:])
        step = tuple(int(np.random.randint(1, i+1)) for i in shape[-win_dim:])
        dilation = tuple(int(np.random.randint(1, i+1)) for i in shape[-win_dim:]//win_shape)

        x = np.random.randint(0, 10, size=np.prod(shape)).reshape(shape)
        y = sliding_window_view(x, window_shape=win_shape, step=step, dilation=dilation)

        for ind in np.ndindex(*y.shape[:win_dim]):
            slices = tuple(slice(i*s, i*s + w*d, d) for i,w,s,d in zip(ind, win_shape, step, dilation))
            if not np.allclose(y[tuple([*ind])], x[(..., *slices)]):
                m = f"""
                        index:{ind}
                        dilation:{dilation}
                        x-shape:{x.shape}, y-shape:{y.shape}, 
                        win-shape:{win_shape}, step:{step}
                        y[ind]:{y[tuple([*ind])].shape}, x[ind]:{x[(..., *slices)].shape}"""
                print(m)
                return {"x": x,
                        "y": y,
                        "ind":ind,
                        "slices":slices,
                        "win_shape":win_shape,
                        "step":step,
                        "dilation":dilation}
return None

Proofreading fixes

Feel free to add to this with minor text changes that can get pushed later.

  • "E.g., in Linux you can add the following alias to you ~/.bashrc file" should be your bashrc here

  • "To start the IPython console, open your terminal (Mac/Linux) or cmd.exe (Windows), type ipython into it, and hit . You should see the following display on your screen:" at the beginning of this section reads a little awkardly. Rephrasing this would be good.

Adding a glob subsection

@davidmascharka do you have any interest in adding a brief subsection to Working with Files about glob? Maybe entitled: "finding files with glob".

I have single Path-method example using glob, but it is so essential that it probably deserves its own brief subsection that shows off the patterns a bit more. We can probably forego discussing the glob module and keep it in the context of a Path method.

I figured that you can do more justice to Unix-style pattern matching than I ;)

If you want, you can just post the markdown here, and I can incorporate it into the notebook. Whatever you want to do (if you want to write this at all)

Implement link checker

Ensure that links are not broken and that internal links use https and not http. Using the example provided by hypothesis

from hypothesis.stateful import GenericStateMachine
import hypothesis.strategies as st
from requests_html import HTMLSession


class LinkChecker(GenericStateMachine):
    def __init__(self):
        super(LinkChecker, self).__init__()
        self.session = HTMLSession()
        self.result = None

    def steps(self):
        if self.result is None:
            # Always start on the home page
            return st.just("https://hypothesis.works/")
        else:
            return st.sampled_from([
                l
                for l in self.result.html.absolute_links
                # Don't try to crawl to other people's sites
                if l.startswith("https://hypothesis.works") and
                # Avoid Cloudflare's bot protection. We are a bot but we don't
                # care about the info it's hiding.
                '/cdn-cgi/' not in l
            ])

    def execute_step(self, step):
        self.result = self.session.get(step)

        assert self.result.status_code == 200

        for l in self.result.html.absolute_links:
            # All links should be HTTPS
            assert "http://hypothesis.works" not in l


TestLinks = LinkChecker.TestCase

Landing page GitHub link

PLYMI is on GitHub

If you have questions about the reading, think that you have spotted some mistakes, or would like to contribute to PLYMI, please visit our GitHub page. You will need to create a GitHub account in order to post an issue; this process is free and easy. We would love for you to join us to discuss the website!

The GitHub page text is a link to this repo. Since this repo is private, only people with access will be able to access it. Everybody else will be directed to GitHub's 404 page; is this really what we want?

Code block formatting issue

There seems to be a problem with mix-and-match style code blocks that incorporate multiline comments mixed with console-style inputs

# 1
>>> "yo"
yo

versus

# 1
# 2
>>> "yo"
  File "<ipython-input-29-41bcffd77fef>", line 3
    >>> "yo"
     ^
SyntaxError: invalid syntax

Can others verify this behavior? Does this seem like a major issue? @AFederici when you were working through the content, did you naturally just copy the input-lines, denoted by >>>, or did were you wanting to copy the entire code blocks?

I'm concerned that readers getting this syntax error will not realize that they can just delete the multi-line comment, as this is very obscure.

General Feedback over the introduction, Module 1, and Module 2

Overall, I worked my way through every file up through the end of the second module; I essentially read everything and tried out all of the examples and reading comprehension questions on my own. I thought the formatting was very elegant, resulting in a "walk-through" that flowed really well. I am going to include general feedback on things I thought could possibly be added in certain sections, suggestions of wording/proofreading, and my opinions on things I found to be very useful inclusions. Finally, if you would be interested in me also reading through and giving feedback on other modules or need help with anything else like content creating or writing reading comprehension questions I would be happy to!

P.S - The titles for sections will be the Jupyter notebook file names. Also, excuse my poor grammar at times, a lot of these were just notes written to myself as I went along

Intro

What this isn't

In the first line, I believe it should be "This is not even close to being an exhaustive treatment of the python language. Currently, there is no "an" there.

Overall, this was a good introduction and was very convincing on why this site will have certain benefits over, say, buying a book

Module 1

Site Formatting

In line 9, above the code that states "x = 1", the text says "the following code assigns the variable x to the integer 1". I believe that this should be "the following code assigns integer 1 to the variable x

My overall impression was that, yes, this is important to have in the beginning; however, this might overwhelm a beginner that doesn't even have python installed yet. Perhaps a disclaimer at the top would be nice saying something along the lines of, do not worry if you don't know what any of this means yet, this is just to provide you with an idea of the layout from here on out.

Getting Started With Python

The links in the section were a nice touch. Also, it was smart to have the readers hold back from jumping the gun and downloading python on their own as there is a nice tutorial for it in soon after

Getting Started With IDEs

While IDEs are nice, maybe give the reader the pros and cons of text editors over vim since I know there are people on both sides of the spectrum in regards to which is better for growing as a programmer

Module 2

Basic Objects

Maybe introduce the shorthand operations of +=, -=, etc.
These are very nice to use, and even come up in examples later on without any real formal introduction

Maybe introduce bitwise operators here? I could see these as being maybe extraneous for the purpose of this guide, but it might prevent any confusion from arising later on between logical and, and bitwise and for example.

I thought that the exercises in this module were very good because they provoke the reader to actually go and look at some of the documentation.

Finally, towards the end where the string exercise solutions are presented, the question was "Convert the integer 12 to the string 12". But, the solution was "str(11)", which I believe should be "str(12)"

Conditional Statements

Maybe make it clearer that you can have multiple if-statements in a row that will all execute as long as they are true, but with an if and elif statements, only one of them will execute. This sort of was hinted at by reading the comments in the coding examples but I don't recall it being that straightforward.

For example, the code below would produce "1st2nd"
x = 10
if (x > 2): print("1st")
if (x > 5): print("2nd)

While the next lines of code would just produce "1st"
x = 10
if (x > 2): print("1st")
elif (x > 5): print("2nd)

Data Structures

Deques and sets both sort of get mentioned without a ton of explanation. They both get talked about more in depth in later sections within module 2 so it might be nice to give a link to where they are discussed further just so no one gets confused.

Sequence Types

Towards the end in "Reading Comprehension, General Understanding", I believe there is a mistake in the solution. The question says to interpret the second half of a list as (n+1)/2 if odd and n/2 if even, BUT, the solution interprets half of a list as (n-1)/2 instead of (n+1)/2.
To fix this, I think the solution should be (len(x)+1) // 2 instead of len(x)//2

Data Structures II

Under the section "What can a dictionary store", it might be good to let the readers know that it isn't usually a good idea to use a float as a key like you did in one of the examples since the computer doesn't always store their exact values. This is kind of the same problem when testing to see if a float is equal to a certain number.

Frozen Sets were briefly mentioned here, but not talked about until a later section I think (the order in the notebook is alphabetical so I'm not actually sure of the true order). But, if this section comes before the one where frozen sets are talked about more extensively, again, maybe include a reference link to that spot.

Finally, I think it was a nice touch to mention ordered dics and why they should still be used for safety despite the new python updates.

Data Structures III

Names Tuples were very interesting. I personally did not know about these, and the example showcasing their utility was very practical as well. Overall, I really liked this module and felt like it is one of the more useful ones to someone already decently familiar with python.

Functions

Perhaps mention **kwargs since you already mentioned *args already.

Generators and Comprehensions

The memory consumption pic didn't show up in the notebook, but I'm not sure if this was something on my end and maybe not a problem on the website version.

Introduction (Control Flow)

There was a note of there being a more efficient way of finding all numbers divisible by three, it might be nice to provide this somewhere?

Scope

Maybe say that variables within a file scope are basically view only within a function. But, you can define the variable as global towards the beginning of the function to enable it to change.

Ex-
x = 10
def numberChange(numb):
global x
x += numb
return x
In [ ]: numberChange(5)
Out[ ]: 15

This would generate "local variable 'x' referenced before assignment" without the statement "global x"

Creating a admonition note in rst

.. raw:: html

   <div class="admonition note">
   <p class="admonition-title fa fa-exclamation-circle"><strong>The inline if-else statement</strong>:</p>
   <p>My understanding is that you had to roll your support for this. So I am wondering - can this be reproduced via sphinx from a .rst file?</p>
   </div>

Proofreading: The Essentials of Python

The following need proofreading:

  • Basic Object Types
  • Sequence Types
  • Variables & Assignment
  • Introducing Control Flow
  • Conditional Statements
  • For-Loops and While-Loops
  • Iterables
  • Generators & Comprehension Expressions
  • Python’s “Itertools”
  • Basics of Functions
  • Scope
  • Data Structures (Part I): Introduction
  • Data Structures (Part II): Dictionaries
  • Data Structures (Part III): Sets & the Collections Module

New Module: Essentials of Python

Python Module 2: Essentials of Python

  • Introduction
  • "if", "else", and "elif"
  • "for-loops"
  • "break", "continue", and "pass"
  • Functions

Code block comment formatting

Most of the code blocks in the text are formatted as so:

# demonstrating broadcasting
>>> x = np.array([1, 2, 3])
...

The idea here is that I would like each code block to provide enough content that someone could solely peruse the code blocks and still understand the major points of a section. This is the same way I like to treat figure captions in a paper.

The problem is that the leading comment technically needs to come after a >>>, as it is impossible to type into an empty line in ipython, which is what this input/output scheme mimics. Thus copying and pasting that code into a notebook cell will produce a syntax error upon execution:

  File "<ipython-input-23-3ae05d90a710>", line 3
    >>> x = np.array([1, 2, 3])
     ^
SyntaxError: invalid syntax

One solution to this is to faithfully use >>> on each line, but this is really cluttered:

# Computing the first two terms of the 
# refactored Euclidean distance equation

# creates a shape-(5,) array
>>> x_sqrd_summed = np.sum(x**2, axis=1)

# creates a shape-(6,) array
>>> y_sqrd_summed = np.sum(y**2, axis=1)

becomes

>>> # Computing the first two terms of the 
>>> # refactored Euclidean distance equation

>>> # creates a shape-(5,) array
>>> x_sqrd_summed = np.sum(x**2, axis=1)

>>> # creates a shape-(6,) array
>>> y_sqrd_summed = np.sum(y**2, axis=1)

This really breaks the flow of the text, in my mind.

One solution to this is to move the "Guide to Formatting" to be in a much more obvious location, and to call out these leading comments here. We could explicitly show them how to copy an example and paste it into a notebook cell.

@davidmascharka thoughts? Any other ideas?

Adding worked problems to the end of modules

It is critically important that PLYMI provides a solid bank of worked problems for the readers. In addition to the reading comprehension questions that are included withing the modules, I would like to add a section at the end of each module that is dedicated to working through "real world" problems, by leveraging the materials from that module.

I think that a good approach to generating these examples is to reflect on projects that you have worked on and identify small pieces of code that can be extracted and problemified. For example, when implementing einsum in MyGrad, I needed to implement merge_max_mappings, which is to merge together a sequence of dictionaries, retaining the mappings with the largest values. This would be a great problem to include at the end of The Essentials of Python.

Proofreading: Essentials of Numpy

The following need proofreading:

  • Introducing the ND-array
  • Accessing Data Along Multiple Dimensions in an Array
  • Basic Array Attributes
  • Functions for Creating NumPy Arrays
  • Reshaping Arrays & Array-Traversal Order
  • “Vectorized” Operations: Optimized Computations on NumPy Arrays
  • Array Broadcasting

Line breaks for sanely viewing diffs

JSON apparently doesn't allow for linebreaks in its text, so all the markdown you write on a single line gets formatted as a massively-long line. For example, the first line of content in GettingStartedWithPython.ipynb is 438 characters long. This makes reading diffs awful.

Since there's no JSON workaround, the options appear to be to either consciously break lines while writing markdown (a single line break won't create a paragraph break) or post-process files before committing. Both of these are painful.

What are your thoughts on the tradeoffs between diff readability and pain of markdown formatting in Jupyter?

Aggregate links at bottom of each page

Although I try to include links to the official Python/NumPy docs throughout the text, it would be nice if we aggregated those links at the bottom of each page. For example, at the bottom of the page on Sequence Types would be the subsection.

Links to Official Documentation


I would like to promote the reader learning to consult the documentation, so including readily-accessible links would be good. We should take care to link the Python 3 content (Python 2 usually is the top hit on Google, so it is easy to navigate to that version).

Module 2

  • Basic Object Types
  • Sequence Types
  • Variables & Assignment
  • Introducing Control Flow
  • Conditional Statements
  • For-Loops and While-Loops
  • Iterables
  • Generators & Comprehension Expressions
  • Python’s “Itertools”
  • Basics of Functions
  • Scope
  • Data Structures (Part I): Introduction
  • Data Structures (Part II): Dictionaries
  • Data Structures (Part III): Sets & the Collections Module

Module 3

  • Introducing the ND-array
  • Accessing Data Along Multiple Dimensions in an Array
  • Basic Array Attributes
  • Functions for Creating NumPy Arrays
  • Reshaping Arrays & Array-Traversal Order
  • “Vectorized” Operations: Optimized Computations on NumPy Arrays
  • Array Broadcasting
  • Basic Indexing & Views

New Module: OOP

Module 6: Object Oriented Programming

  • Introduction to object oriented programming
  • Defining a class
  • Referencing an object
  • Creating an object instance
  • Methods
  • Special methods
  • Class inheritance

Proofreading: Getting Started with Python

The following need proofreading:

  • 1_GettingStartedWithPython.ipynb
  • 2_Installing_Python.ipynb
  • 3_Getting_Started_With_IDEs_and_Notebooks.ipynb
  • 4_Informal_Intro_Python.ipynb
  • 5_Numerical_Work_In_Python.ipynb

Needs Reading Comprehension Questions

Module 2

  • Python’s “Itertools”
  • Data Structures (Part I): Introduction
  • Data Structures (Part II): Dictionaries
  • Data Structures (Part III): Sets & the Collections Module

Module 3

  • Accessing Data Along Multiple Dimensions in an Array

New Module: Odds & Ends

Precise content to be included here is up for debate

Matplotlib

  • Object-oriented interface only (explicit use of fig/ax objects)
  • Plotting in notebook mode (this should be the main mode of plotting)
  • Basic plotting, color, line-style, axis labels, titles
  • Error-bars and fill-between error regions
  • Multiple plots
  • Plotting images
  • Saving figures

File I/O

  • Introduce the open context manager
  • Basics usage of the yielded file object: read, readline, iterations, write, etc.
  • NumPy I/O functionality
  • working with paths: pathlib.Path

String Formatting (??)

  • f-strings, etc.

Basic of modules (??)

  • __init__.py and creating your own Python package
  • dirt-simple setup.py template and demonstration of python setup.py install/develop

Naming Conventions for Jupyter

This isn't super important, but how do we want to refer to everything? Technically, from their website, Project Jupyter develops the Jupyter Notebook. The Jupyter Notebook is just a convenient wrapper around IPython notebooks. So The Notebook writes notebooks, which is weird. Do we want to be really precise with how we're saying everything, or can we reasonably just refer to Jupyter notebooks?

Edit: Ah, so the IPython notebook is the previous evolution of the Jupyter Notebook. So what in the world is the proper convention for naming? Python developers are ridiculous.

Exercises: Introducing NumPy

The following sections of the "Introducing NumPy" module need exercises (in the Exercises directory)

  • 2_AccessingDataAlongMultipleDimensions.ipynb
  • 4_FunctionsForCreatingNumpyArrays.ipynb
  • 5_ReshapingArrays.ipynb
  • 6_VectorizedOperations.ipynb

Proposition: text-based source files via Jupytext

Source control for notebooks is awful. Editing notebooks is awful (@davidmascharka can maybe attest to these more than anyone on the planet). Meta data in notebooks is awful.

I am proposing a workflow that consists of writing / version-controlling .md or .py files as the source documents of PLYMI. And then using jupytext and nbsphinx to convert these to notebooks and then html.

Background

Why do we use notebooks in PLYMI? The answer was that it was by far the easiest solution for me when I first started working on this project. nbsphinx provides an incredibly easy means for jumping from a familiar notebook format to nice html. That being said, only a couple of PLYMI's sections actually use nbsphinx as intended: example 1, example 2. The rest of these sections could be written in pure .rst... almost.

The reason why we need nbsphinx for all of this is because of these guys:
image

image

These custom "admonition boxes", with nice headers and code-blocks, cannot be produced in reSt files. The author of nbsphinx rolled his own special support for these boxes.

I experimented with PLYMI without these boxes, and it turns out that they are super important to the experience that we give the reader. Delimiting takeaways, reading comprehension questions, etc. is critical. So until common markdown provides support for these, we need nbsphinx and the whole stack that it builds off of.

Proposed Solution

I would like to use jupytext to mediate conversions between notebooks and text files. From their readme:

Have you always wished Jupyter notebooks were plain text documents?

Yes.

Wished you could edit them in your favorite IDE?

Yes...!

And get clear and meaningfull diffs when doing version control?

YES!!!

Then... Jupytext may well be the tool you're looking for!

OKAY!!

jupytext supports a workflow in which a notebook, say notebook.ipynb, can be "paired" with a python script, notebook.py (or other type of file, like markdown). You can now edit the script and run jupytext --sync notebook.py to propagate changes to the notebook. You can also edit the notebook, and changes will propagate to the text file automatically. Ultimately we would only share the text files, and generate the notebook locally as needed.

Thus a full work cycle of editing PLYMI source and building the site anew would look like:

  1. Pull PLYMI
  2. Edit text files
  3. Version control the text files
  4. Use jupytext to build the notebooks from text
  5. Use sphinx/nbsphinx to build html from notebooks
  6. Version control the html

For @davidmascharka an edit workflow would simply be steps 1-3.

I am going to experiment with this and verify that we can indeed generate all of PLYMI as-is from text files as the true source files.

From there, I will mess with the smaller details / config setting for jupytext to see if I can prescribe a simple, portable workflow that can be stood up from scratch easily. And one that gets us from text to html quickly. Ultimately it is important that this methodology does not require specialized knowledge of these tools.

I would love feedback thoughts on this. Let me know if anything about jupytext and its capabilities jump out as being particularly useful for PLYMI or if you have any concerns.

Edit: it looks like nbsphinx can leverage jupytext directly if we modify the sphinx conf.py file. This means that sphinx itself would do the text -> notebook conversion.

Cross Links b/w Reading Comprehension Questions and Solutions

It's pretty inconvenient to have to scroll back and forth between reading comprehension questions and solutions to match them up when checking solutions. It'd be great if there's a button that takes you from the question to the solution and vice versa. Or, maybe we could restructure the webpage such each question has a "click to reveal answer" button? This is probably difficult given your setup, but the former I think is possible.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.