Skip to content

Commit

Permalink
Concept extraction / references mega merge
Browse files Browse the repository at this point in the history
* Create common working area

* Extract Concepts from v2 exercise: reverse-string

* Create reverse-string.md

* Update reverse-string.md

* Add Concepts from v2 exercise: variable-length-quantity

* Add first concepts group

* Improved concepts as per PR review

* Adds concept from binary-search-tree

* Add initial list

First pass concepts for `allergies` to address exercism#460

* Initial list of concepts

First pass list of concepts to address exercism#459

* Add Concepts for v2 exercise: phone-number

* Add phone-number Python concepts

* Small update to index access and slice topics.

* Add notes from review.
 - more information about classes, inheritance
 - flesh out privacy, public and non-public
 - clarify wording around iterables and index/slice access

* One more note about brackets and strings.

* Add Concepts for v2 exercise: hamming

* Add concepts for hamming

* Add note about tuple unpacking.

* Add notes about polymorphism, builtins, and dunder methods.

* Some whitespace fixes.

* [WIP] `clock` exercise concepts.

* Extract Concepts from v2 exercise: markdown

* Initial commit for markdown exercise concepts.

* Concept starter for markdown

* Added detail to Markdown concepts

* Final edits before harmonization

Final Markdown edits before we merge and harmonize.

* Add Concepts for v2 exercise: matrix

* `matrix` exercise concepts (issue exercism#386)

First pass of concepts for `matrix ` exercise in python.  Pretty sure this is too detailed, but wanted to get something for review before proceeding with additional exercises.

* Edits to better match exercism#290 Formatting

Edited concepts to better match the formatting of issue exercism#290

* Typo correction

* added title

* Extract Concepts from v2 exercise: rna-transcription

* Beginning of Concepts for rna-transcription

* More detailed concepts for rna-trranscription

More detailed concepts for rna-transcription exrcise.

* Added title

* Extract Concepts from v2 exercise: robot-simulator

* Beginning of concepts for robot-simulator.

* WIP Concepts

* Additional detail for concepts

* Detail third pass

Third pass on adding concept detail.

* Additional detail for concepts.

* Edits per PR Feedback

Numerous spelling corrections.  Additional edits to address comments from last review.

* [WIP] Concept implementation instructions

* Adds instructions for exercise implementation

* Adds correction as per PR reviews

* Harmonize, part 1

* fix relative links in references/README.md

* First pass at harmonization

Shifts all documents to a common format, adds minimal link tagging to
the "concept" currently listed in each file. These will really need
multiple more passes, as they diverge from each other even when
describing the same topic. Many extraneous topics have crept in, added
in an "aspirational" fashion to the exercises; we may need to trim some
of that.

* Pulling in examples from BethanyG

* [WIP] Extracted concept unification

* Unification of extracted concepts

* Typos and duplicates remove

* Duplicates concept unification

* Concepts have now links to original file

* Update languages/reference/README.md

Co-Authored-By: Erik Schierboom <erik_schierboom@hotmail.com>

Co-authored-by: khoivan88 <33493502+khoivan88@users.noreply.github.com>
Co-authored-by: David G <davidgerva@gmail.com>
Co-authored-by: Ashley Drake <a.l.drake713@gmail.com>
Co-authored-by: Pedro Romano <pedro@paparomeo.net>
Co-authored-by: BethanyG <BethanyG@users.noreply.github.com>
Co-authored-by: Erik Schierboom <erik_schierboom@hotmail.com>
  • Loading branch information
7 people committed Jan 29, 2021
1 parent c46ab81 commit ccb7c9d
Show file tree
Hide file tree
Showing 17 changed files with 932 additions and 3 deletions.
15 changes: 15 additions & 0 deletions reference/concepts/pep_8_style_guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# PEP 8 Style

Unlike most earlier languages -- and many newer -- Python has an "official" style guide, and has had one for quite some time.

> One of [Python creator Guido von Rossum]'s key insights is that code is read much more often than it is written. The guidelines provided here are intended to improve the readability of code and make it consistent across the wide spectrum of Python code. As [PEP 20](zen_of_python.md) says, "Readability counts".
The various conventions within it might at times seem arbitrary, but they've been carefully chosen to enhance the readability of Python code, and should generally be adopted and adhered to unless explicitly overridden by a project-specific style guide, which itself should be a derivative of PEP 8.

## Tools

Various tools exist in the Python ecosystem for ensuring that your code doesn't grossly violate PEP 8 conventions. Currently the two most recommended (if opinionated) ones would be [Pylint](https://www.pylint.org/), which will analyze your code for style as well as logical errors, and [Black](https://black.readthedocs.io/en/stable/), which will autoformat your code to take the guesswork out of readability.

## Resources

- [PEP-8](https://www.python.org/dev/peps/pep-0008/)
10 changes: 10 additions & 0 deletions reference/concepts/python_enhancement_proposals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Python Enhancement Proposals (PEPs)

Python is an incredibly popular language with a _great_ many users across an impressive number of domains; as such evolving the language is a complex undertaking that can't be rushed. The Python Enhancement Proposal (commonly known as PEP) process exists to provide a formal mechanism by which the community can propose, debate, vote on, and ultimately adopt significant changes to the language itself.

Even if you doubt you'll ever submit a PEP it's a good idea to keep abreast of what PEPs are out there and what changes are coming to a Python near you.

Two PEPs in particular will serve as a useful jumping off point:

- [PEP 0](https://www.python.org/dev/peps/) lists all current and historic PEPs.
- [PEP 1](https://www.python.org/dev/peps/pep-0001/) explains the PEP process.
18 changes: 18 additions & 0 deletions reference/concepts/pythonic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Pythonic

An adjective used to describe well-constructed, high-quality Python code that is as easily understood and well designed as is possible for the task at hand. A piece of code that is "more Pythonic" will be easier to read and understand, and therefore more pleasurable to use, then "less Pythonic" code that accomplishes the same task.

A quality admired in a Pythonista -- the community's name for an adept Python user -- is the desire to always write code that is as Pythonic as possible.

## Qualities

Any given piece of code tends to be considered more Pythonic if it:

1. Adheres to the principles of the [Zen of Python](zen_of_python.md).
1. Uses the current "best practice" idioms of the language, as the language and those practices evolve.
1. Uses the common style conventions described in [PEP 8](pep_8_style_guide.md)

## Further Reading

- [What is Pythonic](https://blog.startifact.com/posts/older/what-is-pythonic.html)
- [Python Guide](https://docs.python-guide.org/writing/style/)
27 changes: 27 additions & 0 deletions reference/concepts/zen_of_python.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# The Zen of Python

The _Zen of Python_ by Tim Peters, and also known as [PEP-20](https://www.python.org/dev/peps/pep-0020/) is a philosophical statement of Python's foundational principles and ideals. It's neither exhaustive nor binding, but it's often quoted in whole or in part when there's any need to determine which of two functionally identical idioms or pieces of code is _better_ or more [Pythonic](pythonic.md).

- Beautiful is better than ugly.
- Explicit is better than implicit.
- Simple is better than complex.
- Complex is better than complicated.
- Flat is better than nested.
- Sparse is better than dense.
- Readability counts.
- Special cases aren't special enough to break the rules.
- Although practicality beats purity.
- Errors should never pass silently.
- Unless explicitly silenced.
- In the face of ambiguity, refuse the temptation to guess.
- There should be one-- and preferably only one --obvious way to do it.
- Although that way may not be obvious at first unless you're Dutch.
- Now is better than never.
- Although never is often better than *right* now.
- If the implementation is hard to explain, it's a bad idea.
- If the implementation is easy to explain, it may be a good idea.
- Namespaces are one honking great idea -- let's do more of those!

## Easter Egg

If you ever need a refresher, just `import this`. And if you need an example of code that is explicitly _not_ Zen, check out the source of [this](https://github.com/python/cpython/blob/master/Lib/this.py).
81 changes: 81 additions & 0 deletions reference/exercise-concepts/allergies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Concepts of `allergies`

## Example implementation

After Python 3.4 an `enum.Flag` is the "one obvious" approach:

```python
from enum import Flag, auto

class Allergens(Flag):
eggs = auto()
peanuts = auto()
shellfish = auto()
strawberries = auto()
tomatoes = auto()
chocolate = auto()
pollen = auto()
cats = auto()

class Allergies:

def __init__(self, score):
mask = sum(a.value for a in Allergens)
self.flags = Allergens(score & mask)

def allergic_to(self, item):
return Allergens[item] in self.flags

@property
def lst(self):
return [a.name for a in Allergens if a in self.flags]
```

In prior versions an OrderedDict was necessary to _reliably_ ensure sort order and also O(1) lookup:

```python
from collections import OrderedDict

Allergens = OrderedDict(
eggs = 1,
peanuts = 2,
shellfish = 4,
strawberries = 8,
tomatoes = 16,
chocolate = 32,
pollen = 64,
cats = 128,
)

class Allergies:

def __init__(self, score):
mask = sum(Allergens.values())
self.score = score & mask

def allergic_to(self, item):
return bool(self.score & Allergens[item])

@property
def lst(self):
return [a for a in Allergens if self.allergic_to(a)]
```

There are also various solutions involving lists, but these all come with O(N) lookup.

## Concepts

- [Classes][classes]: the exercise relies on the `class` statement to create a custom class
- [Methods][methods]: the exercise relies on the `def` statement to create an instance method
- [Implied Argument][implied-argument]: the exercise relies on the implied passing of `self` as the first parameter of bound methods
- [Dunder Methods][dunder-methods]: the exercise relies on the `__init__` dunder method to control class instantiation
- [Enumerated Values][enumerated-values]: the exercise relies on a fixed enumeration of possible values in a data structure
- [Data Structures][data-structures]: the exercise requires the use of a collection like enum.Flag or collections.OrderedDict
- [Imports][imports]: a reasonably readable solution will require importing from the standard library
- [Powers of Two][powers-of-two]: the exercise relies on the use of powers of two in fundamental binary (bitwise) operations
- [Bitflags][bitflags]: a general understanding of bitflags is required to solve this exercise
- [Bitwise Operators][bitwise-operators]: this exercise relies on bitwise AND (`&`) and potentially bitwise LSHIFT (`<<`) to inspect the Boolean value of individual bits in a bitflag
- [Property Decorator][property-decorator]: this exercise relies on the `@property` decorator to provide read-only dynamic access to the current list of allergens
- [Membership Testing][membership-testing]: this exercise relies on testing membership of a value in a collection of values
- [Lookup Efficiency][lookup-efficiency]: an efficient solution requires knowing that membership testing is O(1) in **dict** and the **enum.Enum** variants, but is O(N) in **list** and other sequential types

83 changes: 83 additions & 0 deletions reference/exercise-concepts/binary-search-tree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Concepts of binary-search-tree

## Example implementation

From the current [example.py](https://github.com/exercism/python/blob/master/exercises/binary-search-tree/example.py):

```python
class TreeNode:
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right

def __str__(self):
fmt = 'TreeNode(data={}, left={}, right={})'
return fmt.format(self.data, self.left, self.right)


class BinarySearchTree:
def __init__(self, tree_data):
self.root = None
for data in tree_data:
self.add(data)

def add(self, data):
if self.root is None:
self.root = TreeNode(data)
return
inserted = False
cur_node = self.root

while not inserted:
if data <= cur_node.data:
if cur_node.left:
cur_node = cur_node.left
else:
cur_node.left = TreeNode(data)
inserted = True
elif data > cur_node.data:
if cur_node.right:
cur_node = cur_node.right
else:
cur_node.right = TreeNode(data)
inserted = True

def _inorder_traverse(self, node, elements):
if node is not None:
self._inorder_traverse(node.left, elements)
elements.append(node.data)
self._inorder_traverse(node.right, elements)

def data(self):
return self.root

def sorted_data(self):
elements = []
self._inorder_traverse(self.root, elements)
return elements
```

## Concepts

- [class][class]: a general comprehension of class concept and and how it works is required, `class` statement
- [Implied Argument][implied-argument]: student needs to know how to use statement `self` in a class
- [class members][class-members]: student must know how members of a class work
- [class methods][class-methods]: student must know how methods of a class work inside and outside the class, the use and meaning of `def` statement
- [arguments][arguments]: concept over arguments of a function and how to use them is required
- [return value][return-value]: the knowledge of `return` statement could be a useful concept in this exercise
- [Dunder Methods][dunder-methods]: student needs to know when to use dunder methods `__init__` and `__str__`
- [overload][overload]: students need to overload methods and specifically dunder methods in this exercise
- [Constructor][constructor]: student needs to know how to build an object using its constructor
- [None][none]: student needs to know the meaning of `None` and how and when assign it to a variable
- [Identity][identity]: the best way to check if an element is `None` is via the _identity_ operator, `is`
- [Boolean][boolean]: concept required to solve the exercise
- [in][in]: use of the `in` statement is useful to look for an object into a list
- [for][for]: the `for ... in` concept is useful to loop over the lists
- [Loops][loops]: concept required to solve the exercise
- [Integer comparison][integer-comparison]: concept required to solve the exercise
- [Recursion][recursion]: recursion is a core concept in this exercise
- [Lists][lists]: knowledge of lists and iteration on lists is required for this exercise
- [Conditional structures][conditional-structures]: knowledge of conditional conceptis and `if...else` statements are required
- [Methods of list][methods-of-list]: the use of methods of list could be useful in this exercise. Methods like `append`, `pop`...

45 changes: 45 additions & 0 deletions reference/exercise-concepts/clock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Concepts of `clock`

# Example implementation

From the current [example.py](https://github.com/exercism/python/blob/master/exercises/clock/example.py):

```python
class Clock:
'Clock that displays 24 hour clock that rollsover properly'

def __init__(self, hour, minute):
self.hour = hour
self.minute = minute
self.cleanup()

def __repr__(self):
return "{:02d}:{:02d}".format(self.hour, self.minute)

def __eq__(self, other):
return repr(self) == repr(other)

def __add__(self, minutes):
self.minute += minutes
return self.cleanup()

def __sub__(self, minutes):
self.minute -= minutes
return self.cleanup()

def cleanup(self):
self.hour += self.minute // 60
self.hour %= 24
self.minute %= 60
return self
```

## Concepts

- [PEP 8 Style][pep-8-style]: PEP 8 is the Python official style guide. Black is emerging as the defacto "pyfmt" tool: should we recommend it? (since the advent of `gofmt` and then `rustfmt`, I'm totally sold on opinionated auto-format tools: saves time and no more bikeshedding)
- [Constants][constants]: Avoid "magic numbers", defining instead meaningfully named constants. PEP 8 convention for constants: `UPPER_SNAKE_CASE`
- [Classes][classes]: use of `class` to create a custom data structure
- [Methods][methods]: use of `def` to define a class's methods
- [Operator overloading][operator-overloading]: How to overload the `+` and `-` operators using the `__add__` and `__sub__` special methods.
- [Rich comparison methods][rich-comparison-methods]: The `__eq__` method is overloaded
- [String formatting][string-formatting]: How to format strings, ie `%` operator, `str.format`, f-strings
45 changes: 45 additions & 0 deletions reference/exercise-concepts/hamming.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Concepts of `hamming`

## Example implementation

From the current [example.py](https://github.com/exercism/python/blob/master/exercises/hamming/example.py):

``` python
def distance(s1, s2):
if len(s1) != len(s2):
raise ValueError("Sequences not of equal length.")

return sum(a != b for a, b in zip(s1, s2))
```

## Concepts

- [Function definition][function-definition]: functions are defined and named using the `def` keyword
- [Function signature][function-signature]: functions take named arguments which are accessible within the body of the function; this one requires the student to make a function that accepts 2
- [Return value][return-value]: the function must return a number (int)
- [Strings][strings]: strings are used generally
- [Builtin functions][builtin-functions]: strings have a length, accessible by calling `len()`, a builtin python function
- [Iterable][iterable]: strings are iterable, which provides a lot of opportunity to leverage Python functions against them
- [Immutable][immutable]: strings are immutable (*immutability*)
- [Booleans][booleans]: this solution uses Boolean values (`True` / `False`)
- [Inequality][inequality]: this solution checks if `a` is not equal to `b`.
- [Booleans are integers][booleans-are-integers]: Booleans values are just named aliases for the integers 1 (`True`) and 0 (`False`)
- [Zip][zip]: builtin that joins multiple iterables into a single one
- [Enumeration][enumeration]: `zip()` in this solution creates an iterable, which is iterated over by using the `for ... in ` syntax
- [Sum][sum]: another builtin that operates on iterables
- [Tuple unpacking][tuple-unpacking]: the values in an iterable can be unpacked into variables and used, i.e. `for a, b in zip(s1, s2)`
- [Exception handling][exception-handling]: the exercise requires Exception handling
- [Raise][raise]: the student is required to raise an `Exception` for incorrect input
- [Exception hierarchy][exception-hierarchy]: the idiomatic `Exception` type is a `ValueError`, meaning the input is incorrect
- [Exception catching][exception-catching]: `Exceptions` can be caught from outside the scope where they are raised, using the `try/except` syntax. All `Exceptions` types inherit from the base class, `Exception` and thus can be caught by either checking specifically for the type of Exception, or for any Exception
- [Exception message][exception-message]: Custom error messages can (and should) be supplied to an Exception when raised
- [Operators][operators]: `!=` is "not equal", which is not the same thing as `is`, or an identity check, but is the inverse of `==`, which is equality
- [Loops][loops]: the `for ... in` syntax is useful for looping through a list or other iterable object
- [Generators][generators]: generators calculate then `yield` a value one at a time, as opposed to lists which calculate and return all values in memory at once. A generator will pick up where it leaves off, and generate one item at a time, on demand
- [Generator comprehension][generator-comprehension]: a generator comprehension is passed to `sum()` to drive summation without storing all the values in a list first
- [Tuple unpacking][tuple-unpacking]: iterating through a list of tuples, i.e. [(1, 2), (2,3)], each piece of each tuple can be unpacked into a separate variable (syntax: `a, b = (1, 2)`); this works for any sort of iterable (lists, for example, and even strings!) but is commonly used with tuples because they are typically of a known size/length, and so can be safely unpacked into N variables, with names.
- [Dunder Methods][dunder-methods]: "dunder" -> "double under", referring to the names of these methods being prefixed with two underscores, e.g. `__init__`. There is no formal privacy in Python, but conventionally a single underscore indicates a private method, or one that the programmer should assume may change at any time; methods without an underscore are considered part of an object's public API. Double underscores are even more special - they are used by Python's builtin functions like `len()`, for example, to allow objects to implement various interfaces and functionality. They can also be used for operator overloading. If you have a custom class that you would like to be able to compare to other instances of the same class, implementing `__lt__`, `__gt__`, `__eq__` etc. allow programmers to use the `>`, `<`, `=` operators. Dunder methods allow programmers to build useful objects with simple interfaces, i.e. you can add two instances together using `+` instead of writing something like `instance1.add(instance2)`.
- [Builtin Function][builtin-functions]: Python has several handy builtin functions in the stdlib that can operate on many types of data, e.g. `len()`, `max()`, `min()`. Under the hood these are implemented via dunder methods - if an object (and everything in Python is an object) implements the correct dunder methods (see that topic for more information), it can support use in these functions. (For example, if an object implements `__len__`, the len(<object>) will return that value.) Because these functions are not strictly tied to any data type, they can be used almost anywhere, and will crop up again and again as we learn Python. Docs: https://docs.python.org/3/library/functions.html
- [Polymorphism][polymorphism]: Python is "dynamically typed," meaning that variable names are bound to objects only, not to a particular type. You can assign `foo` to a string, and then reassign it to an `int` with no issues. "Polymorphism" formally means that different types respond to the same function - so the ability to add custom class instances together using `+`, for example, shows how Python can define the same function against different types.
- [Duck Typing][duck-typing]: Python is also a good example of "Duck typing," to wit, "if it walks like a duck, talks like a duck, it's a duck.". This is accomplished partly with "magic" or "dunder" methods (double-under) that provide various interfaces to an object. If an object implements `__iter__` and `__next__`, it can be iterated through; it doesn't matter what type the object actually is.

Loading

0 comments on commit ccb7c9d

Please sign in to comment.