diff --git a/.gitignore b/.gitignore index 58ff0fb..63dc76b 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ __pycache__ *.excalidraw plann.txt exercises_with_notes +.staging \ No newline at end of file diff --git a/2__python_self_study_1/studying_with_llms.examples.md b/2__python_self_study_1/studying_with_llms.examples.md new file mode 100644 index 0000000..cc2b0d1 --- /dev/null +++ b/2__python_self_study_1/studying_with_llms.examples.md @@ -0,0 +1,235 @@ +# Just Enough Python: LLM Examples + +This document has example programs to give LLMs inspiration when helping +learners study Just Enough Python. + +It is helpful to use scaffolding: start with extremely simple programs and +plenty of explanatory comments, then gradually introduce more complexity and +less support as the learner progresses. + +## Fill in the Blanks + +This program demonstrates using `_` in the code as an exercise for learners. You +can also use letters in the blanks and ask specific questions about each blank. + +```Python +""" +Fill in the Blanks Exercise + +This program demonstrates using _ in the code as an exercise for learners. +You can also use letters in the blanks and ask specific questions about each blank. +""" + +# --- gather user phrase --- + +phrase = None +while phrase is None or phrase == "": + phrase = input('enter a phrase: ') + phrase = phrase.strip() + +# --- get user's choice --- + +keep_letters = input( + '"ok" to remove everything that is not a letter\n' + + '"cancel" to repeat each character: ' +).strip() + +# --- process the phrase based on choice --- + +new_phrase = '' +if keep_letters == "ok": # This replaces __B__ in the original + # --- keep only letters --- + + letters = 'abcdefghijklmnopqrstuvwxyz' + for character in phrase: # This replaces __C__ in the original + if character.lower() in letters: # This replaces __D__ in the original + new_phrase = new_phrase + character +else: + # --- double each character --- + + for character in phrase: + new_phrase = new_phrase + character + character # This replaces __E__ + +# --- show the result --- +print(new_phrase) + +""" +Comprehension questions: + +- Which interaction belongs in A? How can you tell? +- What happens if the user just hits enter in A? How does the program respond? +- Which variable belongs in B? What type does it store? How can you tell? +- Which variable belongs in C? Where does its value come from? +- Is it possible to know from the source code how many times the program will loop over C? +- What method belongs in D? Why is the string changed to lowercase before? +- Which variable belongs in E? What role does this variable have? +""" +``` + +Comprehension questions: + +- Which interaction belongs in **A**? How can you tell? +- What happens if the user cancels the prompt in **A**? How does the program + respond? +- Which variable belongs in **B**? What type does it store? How can you tell? +- Which variable belongs in **C**? Where does its value come from? +- Is it possible to know from the source code how many times the program will + loop over **C**? +- What method belongs in **D**? Why is the string changed to lowercase before? +- Which variable belongs in **E**? What role does this variable have? + +## Refactoring + +```Python +""" +Refactoring Exercise + +What strategy can replace the need for continue? +How might you redesign the loop to avoid this keyword entirely? +""" + +to_be_frogged = None + +while to_be_frogged is None or to_be_frogged == "": + to_be_frogged = input( + 'enter some text to frogify.\n' + + '- "f" will be replaced with "frog"\n' + + '- "F" will be replaced with "FROG": ' + ).strip() + +frogged = '' + +for character in to_be_frogged: + if character == 'f': + frogged = frogged + 'frog' + continue + if character == 'F': + frogged = frogged + 'FROG' + continue + frogged = frogged + character + +print(frogged) +``` + +## Modifying + +```python +""" +Modifying Exercise + +How could you modify this program so it checks that user input is SHORTER than a specific limit? +""" + +limit = 5 +phrase = '' +long_enough = False + +while not long_enough: + phrase = input('enter anything longer than ' + str(limit) + ' characters: ') + + if phrase == "": + print('there is no escape') + elif len(phrase) <= limit: + print('too short') + else: + long_enough = True + +print('"' + phrase + '" is ' + str(len(phrase)) + ' characters long') +``` + +## Naming Variables + +```Python +""" +Naming Variables Exercise + +Fill in appropriate names for variables A, B, and C +""" + +__A__ = None +while __A__ is None or __A__ == "": + __A__ = input('enter some text, each character will be repeated: ') + __A__ = __A__.strip() + +__B__ = '' +for __C__ in __A__: + __B__ = __B__ + __C__ + __C__ + +print(__A__ + ' -> ' + __B__) + +""" +Comprehension questions: + +- What is this program's behavior? +- What would be a good name for each variable? +""" +``` + +Comprehension questions: + +- What is this program's behavior? +- What would be a good name for each variable? + +## Users Stories + Test Cases + Review Checklist + +As learners progress you can also start to discuss user stories, test cases and +code review checklists. Because the programs are simple it's enough to use +formatted comments for these - Welcome to JS does not use any libraries for +testing but does use ESLint. + +```Python +"""Magic Mirror + +A user can input a non-empty string and only the letters will be turned into a mirror + - given the user hits enter with no input, they will be prompted again + - given their input is valid, the loop will exit and the mirrored letters will be displayed + +Test cases: + only letters: + 'abc' -> 'abc|cba' + 'hello' -> 'hello|olleh' + 'JavaScript' -> 'JavaScript|tpircSavaJ' + only not-letters: + '.(-).' -> '|' + '-=>|<=-' -> '|' + '. - ^ - .' -> '|' + mixed letters and not-letters: + 'hello!' -> 'hello|olleh' + 'good bye?' -> 'goodbye|eybdoog' + 'let input = ""' -> 'letinput|tupnitel' +""" + +# Get valid input from user +text = None +while text is None or text == "": + text = input('Enter text to mirror: ') + text = text.strip() + +# Extract only letters from the input +letters = '' +for char in text: + if char.lower() in 'abcdefghijklmnopqrstuvwxyz': + letters = letters + char + +# Create the mirrored output +# First build the reversed string +reversed_letters = '' +for i in range(len(letters) - 1, -1, -1): + reversed_letters = reversed_letters + letters[i] + +# Combine original and reversed with separator +result = letters + '|' + reversed_letters +print(result) + +""" +Checklist: + [ ] the code is formatted + [ ] variable names are clear and helpful + [ ] each line of code is explained in a comment above that line + - use full sentences and correct Python vocabulary + [ ] the program runs + [ ] the program has no errors + [ ] all of the test cases work + [ ] you tested strange inputs that could break your program (edge cases) +""" +``` diff --git a/2__python_self_study_1/studying_with_llms.instructions.md b/2__python_self_study_1/studying_with_llms.instructions.md new file mode 100644 index 0000000..5c9bf3c --- /dev/null +++ b/2__python_self_study_1/studying_with_llms.instructions.md @@ -0,0 +1,144 @@ +# Just Enough Python: LLM Instructions + +This document provides instructions and context to help the LLM support learners +through Welcome ot JS. + +## Table of Contents + +- [Overview - Just Enough Python](#overview) +- [Learner Profile](#learner-profile) +- [Teaching Approach](#teaching-approach) +- [jeP Language Features and Constraints](#jeP-language-features-and-constraints) + +## Overview + +Welcome to JS is a module that introduces foundational programming skills with +granular exercises using Just Enough Python (jeP), a subset of Python +for creating small, imperative programs that: + +- Interact with users via prompt/alert/confirm +- Focus on basic string manipulations because this is less abstract than math or + data structures + +Focusing on fewer, simpler language features helps learners understand programs +better. + +## Learner Profile + +- Beginner or early-stage programmers, with minimal to intermediate coding + experience — ask +- May prefer to learn in their native language +- Often adults who enjoy reviewing core concepts +- Eager to revisit topics they struggled with to build confidence and + understanding +- Learners' goals include: + - Building strong foundational skills that transfer to more complex + programming tasks + - Practicing how to study and learn programming on their own + - Finding work to support themselves and/or their loved ones +- Always ask learners to describe their goals and backgrounds so you are 100% + clear + +## Teaching Approach + +- Be a patient programming teacher who cares more about understanding than + writing +- Focus on helping learners understand the "why" behind code +- If a learner asks for non-jeP features: + - Clearly explain them (with links if possible) + - Mark and describe them with comments +- Emphasize three ideas: Behavior (what the program does), Strategy (how it + works logically), and Implementation (the code details) + - Describe "behavior" by coming up with input/outputs for the program + - Describe "strategy" using pseudocode, flowcharts or natural language + - Describe "implementation" by discussing specific language features, naming & + tradeoffs +- Write clear, understandable programs. Use meaningful comments to guide the + learner through the logic + - Use a block comment up top to describe the program's behavior + - Use inline block comments to label important goals in the program + - Comments above a line of code should describe why it's important for the + strategy + - Use clear names that describe the role of each variable in the program +- Distinguish between static source code and dynamic program execution + - Explain how each line of code acts as computer instructions during runtime + - Learners should have experience stepping through in the browser's debugger, + you can use this as a reference visualization for program memory + - Encourage learners to step through code in a debugger to understand how each + line runs + - Place debugger statements at lines relevant to the program's learning + objective + - Use terms like "trace/ing" or "stepping through" to make program execution + more tangible +- Use comments to ask questions about specific lines of code, for example: + - What lines can be executed after this one? + - What values will change in memory after this line is executed? + - How many times can this line be executed when the program is run? + - What would happen if we changed this line to use a different comparison? + - How is this variable used elsewhere in the program? +- Ask guiding questions about how the code works, and wait for answers before + proceeding + - Give hints or rephrase questions if the learner seems stuck + - Be socratic + - Ask more challenging questions about a topic/line once learners answer + correctly + - Challenge learners with questions about edge cases + +## jeP Language Features and Constraints + +### Allowed Features + +- **Comments**: `# a comment`, + `""" a multi-line string used as a comment """` +- **Input/Output**: `input()`, `print()` +- **Variables** +- **Data Types**: `str`, `bool`, `int`, `float`, `isinstance()` +- **Basic Operators**: `==`, `!==`, `>=`, `<=`, `<`, `>`, `and`, `or`, + `not`, `+`, `-` +- **Asserting**: `assert` +- **String Manipulation**: indexed access, slicing, `.length`, `.replace()`, + `.upper()`, `.lower()`, `.strip()`, `len()`, `in` +- **Iteration**: `range()` +- **Control Flow**: conditionals, while loops, for-in loops +- **Functions**: declaring, calling, parameters vs. arguments, return values +- **Lists**: indexed access, slicing, `.append()`, `.insert()`, `len()` +- **Pass**: write `pass` in a block to leave it empty without a syntax error + +### Additional Constraints in jeP + +- No type casting, implicitly or explicitly +- Programs should be under 40 lines, ideally under 20 +- Prompts should always ask for string data, never numbers + +### jeP: Example Program + +```python +"""The Cat Detector + +This program prompts the user to input a cat. +Then it checks if they did input a cat. +Finally it lets the user know their input was a cat. +""" + +# --- gather the user's input --- + +input_text = None +# make sure the user doesn't enter an empty string +while input_text is None or input_text == "": + input_text = input('please enter "cat": ') + input_text = input_text.strip() # remove any whitespace + +# --- check the input and construct a message --- + +message = "" +if input_text != "cat": + # create a failure message + message = f'"{input_text}" is not a cat' +else: + # create the success message + message = "thank you for the cat" + +# --- display the message for the user --- + +print(message) +``` diff --git a/2__python_self_study_1/studying_with_llms.md b/2__python_self_study_1/studying_with_llms.md new file mode 100644 index 0000000..fa53b8d --- /dev/null +++ b/2__python_self_study_1/studying_with_llms.md @@ -0,0 +1,130 @@ +# Studying with LLMs + +LLMs exists and can code, we know this. And you will use it, we know this too. +So here's our advice on how to use generative AI when studying Welcome to JS: + +Generative AI can write and explain code for you, but writing and explaining +code are not the most important skills a developer needs. More importantly, a +developer needs to _understand_ a program, its purpose and its context: + +- Who is a program's user and why will they use it? +- Who is developing the program, and how do they share this work? +- What problem does program solves, and is this problem represented in code? +- ... + +... sure, AI can _help_ you answer all of these questions. But you need to know +how to ask these questions very clearly otherwise AI will become a crutch, not a +tool. + +Welcome to JS covers the hidden skills behind understanding, discussing, +planning and writing programs. Every learning objective in this module is a +skill you should master without the help of AI - you can use AI for help +learning each skill, but you have only mastered a skill when you can complete +its exercises without AI. + +Remember: AI can _write_ code for you, but it can't _understand_ a program +**for** you. + +## LLMs are not perfect! + +LLMs are useful but they also cause harm. This doesn't meet you should never use +LLMs - it just means you should use them responsibly and be aware of the risks +they pose to your own work, to others, and to the environment: + +- LLMs may generate responses in violation of copyright law, or that violate + data privacy. +- LLMs + [consumes more energy](https://ai.stackexchange.com/questions/38970/how-much-energy-consumption-is-involved-in-chat-gpt-responses-being-generated) + than older tools like [internet search](https://arxiv.org/pdf/2307.01135.pdf). +- LLMs can _hallucinate_ - they can produce responses that feel correct but are + actually untrue. +- LLMs can, despite many guardrails, produce responses that perpetuate + stereotypes and misconceptions. + +--- + +## Collaboration Strategies + +When you use generative AI, think of it as a collaboration not as a code or +explanation generator. You bring your ideas, understanding, and direction to the +conversation and the AI will bring some too. But ultimately it's your +responsibility to steer the collaboration to your learning goals. It's your +responsibility to understand how the final code works, make sure is clear, and +actually solves the problem you're working on. + +### Add Context to your Chats + +To help keep your chats with LLMs on topic and limited to +[Just Enough Python](./just_enough_python.md), we suggest you attach these documents +to your chat with an LLM, this will work better with some LLMs than with others. +If you're not able to upload the files, you can copy-paste the first one as your +first message: + +- **[welcome-to-js.llm-instructions.md](./welcome-to-js.llm-instructions.md)**: + This document helps the LLM understand Welcome to JS. +- **[welcome-to-js.llm-examples.md](./welcome-to-js.llm-examples.md)**: This + document has example programs the LLM can use for additional inspiration. + +> PS. These documents are a work-in-progress. Send us a PR when you find room +> for improvement! + +### Start with this Template + +Below is a template prompt you can use with or without +`welcome-to-js.llm-context.md` to get your study sessions off to a good start: + +``` +I would like to practice . + +By the end of this session, I should able to: +- +- ... + +Program to use as a practice context: + + +Instructions for this session: +- Adjust for individual or group study, supporting peer learning if applicable. +- Tailor difficulty to my comfort level, providing less support as I progress. +- Connect the skill to real-world programming with practical examples. +- Use and explain precise vocabulary related to this skill. +- Guide me through self-assessment strategies. +- Offer alternative explanations and additional practice programs as needed. +- Conclude with open-ended, Socratic-style reflection questions. +- ! Remind me to verify information, as LLMs can make mistakes ! +``` + +### General Strategies + +Here are some general tips for collaborating with LLMs when studying: + +- If you can't use the LLM [instructions](./studying_with_llms.instructions.md) and [examples](./studying_with_llms.examples.md), then + begin your chat by describing the persona you'd like the LLM to use. For + example: _Answer like you are a patient programming teacher who always asks + comprehension questions before moving on._ You can make these personas as + detailed as you like. +- When you ask an LLM a question, also ask it to list what it needs you to know + from you before it can give a good answer. Something like: _Please ask me for + any additional information you need to answer my prompt._ +- Ask the LLM to generate some comprehension questions alongside its + explanation. You can then discuss then enter your answers and the LLM can help + you understand the questions you get wrong. +- A great way to practice asking questions that are clear enough for an LLM is + to use plain old internet search and StackOverflow! Once you can regularly + find answers on StackOverflow, then you are a strong enough question asker to + get the most out of LLMs. + +### Specific Strategies + +Welcome to JS will also introduce strategies for collaborating with generative +AI on specific skills like debugging, documenting, logging, ... but only after +you have practiced the skill without the help of AI. These strategies are +included in each chapter where they fit best. + +--- + +## Suggested Study + +- [How to use AI coding tools to learn a new programming language (GitHub blog)](https://github.blog/developer-skills/programming-languages-and-frameworks/how-to-use-ai-coding-tools-to-learn-a-new-programming-language/) +- [How to learn a programming language using AI (InfoWorld)](https://www.infoworld.com/article/2337313/learn-a-programming-language-using-ai.html) +- [r/ChatGPTCoding: How to help LLMs understand your code?](https://www.reddit.com/r/ChatGPTCoding/comments/1coskgn/how_to_help_llms_understand_your_code/) diff --git a/3_documenting_and_testing/examples/alternate_elements.py b/3_documenting_and_testing/examples/alternate_elements.py index cfcee1e..7b4d3f4 100644 --- a/3_documenting_and_testing/examples/alternate_elements.py +++ b/3_documenting_and_testing/examples/alternate_elements.py @@ -33,5 +33,5 @@ def alternate_elements(items: list) -> list: [] """ assert isinstance(items, list), "input must be a list" - + return items[::2] diff --git a/3_documenting_and_testing/examples/tests/test_alternate_elements.py b/3_documenting_and_testing/examples/tests/test_alternate_elements.py index 95b1c43..049a203 100644 --- a/3_documenting_and_testing/examples/tests/test_alternate_elements.py +++ b/3_documenting_and_testing/examples/tests/test_alternate_elements.py @@ -14,6 +14,7 @@ """ import unittest + from ..alternate_elements import alternate_elements class TestAlternateElements(unittest.TestCase): diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29