Compare commits
47 Commits
Author | SHA1 | Date |
---|---|---|
waldek | e6a747a22f | |
waldek | b40e4d8eb4 | |
waldek | 1a6966dae4 | |
waldek | ebb13f83e3 | |
Yousri | 62ddfad1a6 | |
waldek | 598d499356 | |
Yousri | 9a09ff821f | |
Yousri | 920982a741 | |
Yousri | 93422cad7f | |
Yousri | cd7343dec8 | |
Yousri | a52ad43855 | |
Yousri | 6a7f4d1205 | |
Yousri | 1bc82d4956 | |
Yousri | 5d2a4e677e | |
waldek | 3fa1ede369 | |
waldek | 9468c221c1 | |
waldek | 0fb66a9009 | |
Yousri | 53a61c5331 | |
waldek | 417f3a909b | |
Yousri | 335c987261 | |
waldek | c0e37e0b7e | |
waldek | 350a3b6a45 | |
waldek | 5700c73318 | |
waldek | b6ce0eaf47 | |
waldek | e3b2a98376 | |
waldek | 063615621f | |
waldek | 98f189fc9b | |
waldek | 6f2b949408 | |
waldek | 00ea8253cb | |
waldek | fb23fbca2e | |
waldek | d10bee235c | |
waldek | 5368c5023f | |
waldek | d4c452f6c7 | |
waldek | f8e18a62c7 | |
waldek | 27a862bb77 | |
waldek | 31be912721 | |
Yousri | 607c0b8ec6 | |
Yousri | 4a6d1ef41d | |
Yousri | 9b651f9374 | |
Yousri | a80ec966e8 | |
waldek | 46fe6d8276 | |
waldek | 108236dcf3 | |
waldek | 69234aaa9c | |
waldek | 842f182d44 | |
waldek | 9d95179707 | |
waldek | cabe212449 | |
waldek | dabb20053a |
|
@ -2,3 +2,4 @@
|
||||||
*.pdf
|
*.pdf
|
||||||
*.docx
|
*.docx
|
||||||
.~lock*
|
.~lock*
|
||||||
|
.idea/
|
||||||
|
|
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 176 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 149 KiB |
After Width: | Height: | Size: 183 KiB |
After Width: | Height: | Size: 153 KiB |
After Width: | Height: | Size: 159 KiB |
After Width: | Height: | Size: 183 KiB |
After Width: | Height: | Size: 193 KiB |
After Width: | Height: | Size: 180 KiB |
After Width: | Height: | Size: 97 KiB |
After Width: | Height: | Size: 86 KiB |
After Width: | Height: | Size: 97 KiB |
After Width: | Height: | Size: 193 KiB |
After Width: | Height: | Size: 151 KiB |
After Width: | Height: | Size: 169 KiB |
After Width: | Height: | Size: 233 KiB |
After Width: | Height: | Size: 129 KiB |
After Width: | Height: | Size: 150 KiB |
After Width: | Height: | Size: 135 KiB |
After Width: | Height: | Size: 175 KiB |
After Width: | Height: | Size: 120 KiB |
After Width: | Height: | Size: 159 KiB |
After Width: | Height: | Size: 130 KiB |
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 98 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 144 KiB |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 135 KiB |
|
@ -0,0 +1,47 @@
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
LINK = "https://github.com/ekalinin/github-markdown-toc"
|
||||||
|
OUTPUT = "readme.md"
|
||||||
|
OUTLINE = "outline.md"
|
||||||
|
INPUT = [
|
||||||
|
"learning_python3.md",
|
||||||
|
"introduction_to_solid.md",
|
||||||
|
"learning_python3_gui.md",
|
||||||
|
"learning_git.md",
|
||||||
|
"what_is_next.md",
|
||||||
|
]
|
||||||
|
CMD = "gh-md-toc"
|
||||||
|
FILTER = "(#"
|
||||||
|
TITLE = "Table of Contents"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
p = subprocess.Popen([CMD], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
output, err = p.communicate()
|
||||||
|
except Exception as e:
|
||||||
|
print("please install {}".format(LINK))
|
||||||
|
exit()
|
||||||
|
CONTENT = []
|
||||||
|
for f in INPUT:
|
||||||
|
p = subprocess.Popen([CMD, f], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
output, err = p.communicate()
|
||||||
|
output = output.decode().split("\n")
|
||||||
|
for line in output:
|
||||||
|
if CMD in line:
|
||||||
|
continue
|
||||||
|
if FILTER in line:
|
||||||
|
line = line.replace(FILTER, "(./{}#".format(f))
|
||||||
|
if TITLE in line:
|
||||||
|
title = " ".join(f.replace(".md", "").split("_")).capitalize()
|
||||||
|
title = title.replace("/", ": ")
|
||||||
|
line = title
|
||||||
|
CONTENT.append(line)
|
||||||
|
p = subprocess.Popen(["cp", OUTLINE, OUTPUT], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
p.wait()
|
||||||
|
print("writing")
|
||||||
|
with open(OUTPUT, "a") as fp:
|
||||||
|
for line in CONTENT:
|
||||||
|
fp.write("{}\n".format(line))
|
||||||
|
print("done...")
|
|
@ -0,0 +1,341 @@
|
||||||
|
# Object-Oriented class design
|
||||||
|
|
||||||
|
|
||||||
|
## SOLID
|
||||||
|
SOLID coding is a principle created by Robert C.Martin, he is a famous computer scientist.
|
||||||
|
SOLID is an acronym for his five conventions of coding.
|
||||||
|
With their conventions, you can improve the structure of your code, reduce time to implement changes and technical debts, etc.
|
||||||
|
It is a collection of best practices.
|
||||||
|
And it was developed through this decade.
|
||||||
|
Principles of SOLID acronym are:
|
||||||
|
|
||||||
|
* The Single-Responsibility Principle (**SRP**)
|
||||||
|
* The Open-Closed Principle (**OCP**)
|
||||||
|
* The Liskov Substitution Principle (**LSP**)
|
||||||
|
* The Interface Segregation Principle (**ISP**)
|
||||||
|
* The Dependency inversion Principle (**DIP**)
|
||||||
|
|
||||||
|
The first convention is **SRP**, that means that all classes of your code must do one thing.
|
||||||
|
That is an important principle.
|
||||||
|
That is the best way to work with others people in the same project.
|
||||||
|
Version control is easier,
|
||||||
|
You will never have _Merge conflicts_, because other people work in other operations.
|
||||||
|
So, he will never have two same things in the code.
|
||||||
|
|
||||||
|
### Single-Responsibility
|
||||||
|
Let's start something !
|
||||||
|
We will make common mistake that violate **SRP** and correct them.
|
||||||
|
Let's code a bookstore invoice.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Book(object):
|
||||||
|
def __init__(self, name, authorName, year, price, isbn):
|
||||||
|
self.name = name
|
||||||
|
self.authorName = authorName
|
||||||
|
self.year = year
|
||||||
|
self.price = price
|
||||||
|
self.isbn = isbn
|
||||||
|
```
|
||||||
|
|
||||||
|
As you can see, there is a class named Book with some fields.
|
||||||
|
This fields are public and characterize a book.
|
||||||
|
|
||||||
|
OK ! Now we can start the invoice class.
|
||||||
|
This class will calculate the final price for a customer.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Invoice(object):
|
||||||
|
def __init__(self, book, quantity, discountRate, taxRate, total):
|
||||||
|
self.book = book
|
||||||
|
self.quantity = quantity
|
||||||
|
self.discountRate = discountRate
|
||||||
|
self.taxRate = taxRate
|
||||||
|
self.total = total
|
||||||
|
|
||||||
|
|
||||||
|
def calculateTotal(self):
|
||||||
|
self.price = ((self.book.price - self.book.price * self.discountRate)*self.quantity)
|
||||||
|
|
||||||
|
self.priceWithTaxes = self.price * (1 + self.taxRate)
|
||||||
|
|
||||||
|
return self.priceWithTaxes
|
||||||
|
|
||||||
|
def printInvoice(self):
|
||||||
|
print(self.quantity, "x", self.book.name,"", self.book.price, "$");
|
||||||
|
print("Discount Rate: ", self.discountRate)
|
||||||
|
print("Tax Rate: ", self.taxRate)
|
||||||
|
print("Total: ", self.total)
|
||||||
|
|
||||||
|
|
||||||
|
def saveToFile(self, fileName):
|
||||||
|
pass
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Alright, now we have the _Invoice_ class, he had 3 methods (calculateTotal, printInvoice, saveToFile) and some fields too.
|
||||||
|
Why this code violate the first convention of **SOLID** ?
|
||||||
|
|
||||||
|
|
||||||
|
The _printInvoice_ method violate this one because the **SRP** told us to make just one thing per classes.
|
||||||
|
Here, our printing logic is in the same class than _calculateTotal_ method.
|
||||||
|
So, the printing logic is mixed with business logic in the same class.
|
||||||
|
As you think, the _saveToFile_ method violate this convention too.
|
||||||
|
|
||||||
|
Let's correct this example.
|
||||||
|
```python
|
||||||
|
class InvoicePrinter(object):
|
||||||
|
def __init__(self, invoice):
|
||||||
|
self.invoice = invoice
|
||||||
|
def printInvoice(self):
|
||||||
|
print(self.invoice.quantity, "x", self.invoice.book.name,"", self.invoice.book.price, "$");
|
||||||
|
print("Discount Rate: ", self.invoice.discountRate)
|
||||||
|
print("Tax Rate: ", self.invoice.taxRate)
|
||||||
|
print("Total: ", self.invoice.total)
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
class InvoicePersistence(object):
|
||||||
|
def __init__(self, invoice):
|
||||||
|
self.invoice = invoice
|
||||||
|
|
||||||
|
def saveToFile(self):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
We have now two others classes, _InvoicePrinter_ class and _InvoicePersistence_ class.
|
||||||
|
The _InvoicePrinter_ is used to print information.
|
||||||
|
And the _InvoicePersistence_ is used to save information.
|
||||||
|
|
||||||
|
With these three classes, we respect the first principle of **SOLID**.
|
||||||
|
|
||||||
|
### Open-Closed Principle
|
||||||
|
|
||||||
|
This principle says that classes are open for extension and closed to modification.
|
||||||
|
Extension mean news functionalities and modification mean modifying your code.
|
||||||
|
If you want to add new functionalities, you are able to add it without manipulating the existing program.
|
||||||
|
If you touch the existing code, you have a risk to have news bugs.
|
||||||
|
So, if you want to add something else, you can use abstract classes and help of interface.
|
||||||
|
|
||||||
|
Ok so, let's add new functionality in the _InvoicePersistence_ class.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class InvoicePersistence(object):
|
||||||
|
def __init__(self, invoice):
|
||||||
|
self.invoice = invoice
|
||||||
|
|
||||||
|
def saveToFile(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def saveToDataBase(self):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
The _saveToDataBase_ method is used to save information in a Data Base.
|
||||||
|
We have modified the _InvoicePersistence_ class.
|
||||||
|
And this class will be more difficult to make easily extendable.
|
||||||
|
So, we violate the **OCP** convention.
|
||||||
|
If you want to respect this principle, you have to create a new class.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class InvoicePersistence(abc.ABC):
|
||||||
|
@abstractmethod
|
||||||
|
def save(self, invoice):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
The new _InvoicePersistence_ class has an abstract method.
|
||||||
|
So, if a class inherits the _InvoicePersistence_ class, you have to implement the _save_ method.
|
||||||
|
|
||||||
|
And for example, we will create a _DataBasePersistence_ class, and this class inherits the abstract _InvoicePersistence_ class.
|
||||||
|
```python
|
||||||
|
class DatabasePersistence(InvoicePersistence):
|
||||||
|
def __init__(self, invoice):
|
||||||
|
self.invoice = invoice
|
||||||
|
self.save(self.invoice)
|
||||||
|
|
||||||
|
def save(self, invoice):
|
||||||
|
print("Save in database ...")
|
||||||
|
```
|
||||||
|
Let's do the same thing with _FilePersistence_ class.
|
||||||
|
```python
|
||||||
|
class FilePersistence(InvoicePersistence):
|
||||||
|
def __init__(self, invoice):
|
||||||
|
self.invoice = invoice
|
||||||
|
self.save(self.invoice)
|
||||||
|
|
||||||
|
def save(self, invoice):
|
||||||
|
print("Save to file ...")
|
||||||
|
```
|
||||||
|
Ok, we do a lot of things, let's make a UML to represent our class structure.
|
||||||
|
|
||||||
|
<center>
|
||||||
|
<img src="./assets/UML_Solid" alt="" width="1000"/>
|
||||||
|
</center>
|
||||||
|
|
||||||
|
That will be more simple to do extension.
|
||||||
|
|
||||||
|
### Liskov Substitution Principle
|
||||||
|
|
||||||
|
This convention tells us to create a substitutable subclass for their parents.
|
||||||
|
So, if you want to create an object in the subclass, you have to be able to pass it in the interface.
|
||||||
|
|
||||||
|
Let's make an example !
|
||||||
|
We will write a _Walk_ class and his subclass, _Jump_ class.
|
||||||
|
```python
|
||||||
|
class Walk(abc.ABC):
|
||||||
|
def __init__(self):
|
||||||
|
abc.ABC.__init__(self)
|
||||||
|
@abc.abstractmethod
|
||||||
|
def Speed(self):
|
||||||
|
pass
|
||||||
|
@abc.abstractmethod
|
||||||
|
def Ahead(self):
|
||||||
|
pass
|
||||||
|
'''the player walk ahead'''
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def Behind(self):
|
||||||
|
pass
|
||||||
|
'''the player walk behind'''
|
||||||
|
```
|
||||||
|
And the _Jump_ subclass.
|
||||||
|
```python
|
||||||
|
class Jump(Walk):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def Speed(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def Ahead(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def Behind(self):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
As you can see, the _Jump_ subclass has all abstract method of _Walk_ class.
|
||||||
|
But we have a big problem !
|
||||||
|
The _Jump_ subclass need a new method, the _height_ method.
|
||||||
|
And he does not need the _Ahead_ and _Behind_ method.
|
||||||
|
If you remove abstract method and add a new method in _Jump_ subclass, you will be in a big trouble.
|
||||||
|
This subclass will be different about mother class.
|
||||||
|
The simple way to resolve this trouble is to create a new mother class for _Walk_ and _Jump_ class.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Movement(abc.ABC):
|
||||||
|
def __init__(self):
|
||||||
|
abc.ABC.__init__(self)
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def Speed(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def Animation(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def Direction(self):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
The _Movement_ class will be the mother class of _Walk_ and _Jump_ classes.
|
||||||
|
These subclasses will have three methods (_Speed_, _Animation_ and _Direction_ methods).
|
||||||
|
The problems that we had is resolved with the _Direction_ method.
|
||||||
|
With this method, you have choices to go ahead, behind, height, etc.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
Subclasses
|
||||||
|
</summary>
|
||||||
|
The _Walk_ subclass:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Walk(Movement):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def Speed(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def Animation(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def Direction(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
```
|
||||||
|
And the _Jump_ subclass:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Jump(Movement):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
def Speed(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def Animation(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def Direction(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Interface Segregation Principle
|
||||||
|
|
||||||
|
The _Interface Segregation Principle_ means that all interfaces have to be separated.
|
||||||
|
That means that clients has not functions that they do not need.
|
||||||
|
|
||||||
|
OK ! So, let's make an example with client manager.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class GoodCustomer(abc.ABC):
|
||||||
|
def __init__(self):
|
||||||
|
abc.ABC.__init__(self)
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def FirstName(self):
|
||||||
|
pass
|
||||||
|
@abc.abstractmethod
|
||||||
|
def LastName(self):
|
||||||
|
pass
|
||||||
|
@abc.abstractmethod
|
||||||
|
def Address(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def Work(self):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
The _GoodCustomer_ mother class is a class where good customer information are saved.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class BadCustomer(GoodCustomer):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def FirstName(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def LastName(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def Address(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def Work(self):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
The _BadCustomer_ subclass is a class where bad customer information are saved.
|
||||||
|
For this example, we don't want to know the addresses of bad guys.
|
||||||
|
So what can we do ?
|
||||||
|
|
||||||
|
You have to create a new mother class for these two classes like the preceding example.
|
||||||
|
### Dependency Inversion Principle
|
||||||
|
|
||||||
|
This convention says that all classes that we use depends on the interface or abstract classes.
|
||||||
|
Like precedents example, all methods was abstracts.
|
||||||
|
|
||||||
|
>The Dependency Inversion principle states that our classes should depend upon interfaces or abstract classes instead of concrete classes and functions.
|
||||||
|
>We want our classes to be open to extension, so we have reorganized our dependencies to depend on interfaces instead of concrete classes.
|
|
@ -0,0 +1,306 @@
|
||||||
|
# About
|
||||||
|
|
||||||
|
Git is a Version Control System.
|
||||||
|
It is an advanced open source project.
|
||||||
|
That is the most popular VCS with his advantage like security, efficiency, speed etc.
|
||||||
|
He was developed in 2005 by Linus Torvalds, the Linux's father.
|
||||||
|
Many companies projects using Git (Google, Gnome, Netflix, etc).
|
||||||
|
In 2016 12 million people were using Git.
|
||||||
|
|
||||||
|
All project histories were saved in the work file.
|
||||||
|
You can publish, with all histories, projects in a Git platform like Gitea, GitHub, Bitbucket, GitLab, etc.
|
||||||
|
With this tool, you can commit projects, compare projects.
|
||||||
|
That is the best tool for teamwork.
|
||||||
|
|
||||||
|
![git flow](./assets/git-flow.png)
|
||||||
|
|
||||||
|
# Git via `bash`
|
||||||
|
|
||||||
|
## Initialing a git repo
|
||||||
|
To initialize an empty git repository, you can tap _**git init**_ in a text editor like Git Bash.
|
||||||
|
This command will create a git repository in the initial branch **master**.
|
||||||
|
You will be able to add, commit, push, etc.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$ git status
|
||||||
|
fatal: not a git repository (or any of the parent directories): .git
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$ git init .
|
||||||
|
hint: Using 'master' as the name for the initial branch. This default branch name
|
||||||
|
hint: is subject to change. To configure the initial branch name to use in all
|
||||||
|
hint: of your new repositories, which will suppress this warning, call:
|
||||||
|
hint:
|
||||||
|
hint: git config --global init.defaultBranch <name>
|
||||||
|
hint:
|
||||||
|
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
|
||||||
|
hint: 'development'. The just-created branch can be renamed via this command:
|
||||||
|
hint:
|
||||||
|
hint: git branch -m <name>
|
||||||
|
Initialized empty Git repository in /home/local/waldek/Documents/my_first_git_repository/.git/
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$ git status
|
||||||
|
On branch master
|
||||||
|
|
||||||
|
No commits yet
|
||||||
|
|
||||||
|
nothing to commit (create/copy files and use "git add"
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to see if you are in a git repository, you can use _**git status**_.
|
||||||
|
He will inform you which branch that you are and how many commits in this repository.
|
||||||
|
Be careful with commands because you have to be in a folder.
|
||||||
|
In the preceding example, the new repository was in the "my_first_git_repository" folder.
|
||||||
|
## What's in this repo
|
||||||
|
You can see all files of your git repository with the command **_ls_**.
|
||||||
|
```
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$ ls -la
|
||||||
|
total 12
|
||||||
|
drwxr-xr-x 3 waldek waldek 4096 May 2 22:06 .
|
||||||
|
drwxr-xr-x 4 waldek waldek 4096 May 2 22:06 ..
|
||||||
|
drwxr-xr-x 7 waldek waldek 4096 May 2 22:07 .git
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$ ls -la .git/
|
||||||
|
total 40
|
||||||
|
drwxr-xr-x 7 waldek waldek 4096 May 2 22:07 .
|
||||||
|
drwxr-xr-x 3 waldek waldek 4096 May 2 22:06 ..
|
||||||
|
drwxr-xr-x 2 waldek waldek 4096 May 2 22:06 branches
|
||||||
|
-rw-r--r-- 1 waldek waldek 92 May 2 22:06 config
|
||||||
|
-rw-r--r-- 1 waldek waldek 73 May 2 22:06 description
|
||||||
|
-rw-r--r-- 1 waldek waldek 23 May 2 22:06 HEAD
|
||||||
|
drwxr-xr-x 2 waldek waldek 4096 May 2 22:06 hooks
|
||||||
|
drwxr-xr-x 2 waldek waldek 4096 May 2 22:06 info
|
||||||
|
drwxr-xr-x 4 waldek waldek 4096 May 2 22:06 objects
|
||||||
|
drwxr-xr-x 4 waldek waldek 4096 May 2 22:06 refs
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding and tracking content
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$ cat readme.md
|
||||||
|
# Hello world
|
||||||
|
|
||||||
|
I am a paragraph.
|
||||||
|
I can contain multiple sentences, each on one line.
|
||||||
|
|
||||||
|
A blank line separates multiple paragraphs.
|
||||||
|
|
||||||
|
1. lists
|
||||||
|
1. will
|
||||||
|
1. auto increment in most HTML render engines
|
||||||
|
* sublists
|
||||||
|
* are possible
|
||||||
|
* on multiple
|
||||||
|
* levels
|
||||||
|
1. but I keep counting...
|
||||||
|
|
||||||
|
[I will become](https://kernel.org) a link.
|
||||||
|
|
||||||
|
And I'm a line:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$ git status
|
||||||
|
On branch master
|
||||||
|
|
||||||
|
No commits yet
|
||||||
|
|
||||||
|
Untracked files:
|
||||||
|
(use "git add <file>..." to include in what will be committed)
|
||||||
|
readme.md
|
||||||
|
|
||||||
|
nothing added to commit but untracked files present (use "git add" to track)
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we can `add` and `commit` our changes.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$ git add readme.md
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$ git status
|
||||||
|
On branch master
|
||||||
|
|
||||||
|
No commits yet
|
||||||
|
|
||||||
|
Changes to be committed:
|
||||||
|
(use "git rm --cached <file>..." to unstage)
|
||||||
|
new file: readme.md
|
||||||
|
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$ git commit -m "adds a readme file"
|
||||||
|
[master (root-commit) 8278e12] adds a readme file
|
||||||
|
1 file changed, 22 insertions(+)
|
||||||
|
create mode 100644 readme.md
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$ git status
|
||||||
|
On branch master
|
||||||
|
nothing to commit, working tree clean
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$
|
||||||
|
```
|
||||||
|
|
||||||
|
We can use `git log` to inspect the list of commits.
|
||||||
|
Add the `--no-pager` to bypass `less` and print the output straight to the console.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$ git --no-pager log
|
||||||
|
commit 8278e1273d1438920c1063cdca179eb70d5926d8 (HEAD -> master)
|
||||||
|
Author: waldek <waldek@mailbox.org>
|
||||||
|
Date: Mon May 2 22:16:50 2022 +0200
|
||||||
|
|
||||||
|
adds a readme file
|
||||||
|
waldek@metal:~/Documents/my_first_git_repository$
|
||||||
|
```
|
||||||
|
|
||||||
|
## The main workflow
|
||||||
|
|
||||||
|
1. edit your files
|
||||||
|
1. `git status` to verify what's new or has been modified
|
||||||
|
1. `git add` the files you want to commit
|
||||||
|
1. `git commit -m "A RELEVANT COMMIT MESSAGE"`
|
||||||
|
1. `git push` to wherever you have your repository
|
||||||
|
1. repeat step one...
|
||||||
|
|
||||||
|
# Git via Atom
|
||||||
|
|
||||||
|
# Git via Pycharm
|
||||||
|
|
||||||
|
## Starting a version controlled project
|
||||||
|
|
||||||
|
In Pycharm, you have to enable a version control integration.
|
||||||
|
There are many choices, but we will use Git.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_00.png)
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_01.png)
|
||||||
|
|
||||||
|
As you can see, Git appears in the toolbar and a git window appear bottom of the window.
|
||||||
|
And you can identify the current branch that you are in.
|
||||||
|
So the default branch name is **master**.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_02.png)
|
||||||
|
|
||||||
|
Let's try to write some code.
|
||||||
|
And add all contents that we write in a git repository.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_03.png)
|
||||||
|
|
||||||
|
In the commit window, we can see which file had changed.
|
||||||
|
But we had three important things too.
|
||||||
|
We have a textBox and two buttons.
|
||||||
|
In the textBox, you can write a comment when you commit.
|
||||||
|
The _Commit_ button is used to save all change of your project in a git repository.
|
||||||
|
The _Commit and Push_ is used to commit and push the project in a Git.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_04.png)
|
||||||
|
|
||||||
|
When you press the _Commit and Push_, a new window appears.
|
||||||
|
You can see which branch and which commit that you push.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_05.png)
|
||||||
|
|
||||||
|
## Creating an online repository
|
||||||
|
|
||||||
|
If you use Gitea and you want to create a new repository.
|
||||||
|
That is pretty simple, you have to press the button **New Repository**.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_06.png)
|
||||||
|
|
||||||
|
And then, you can add the repository name, and others parameters like description, the visibility, etc.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_07.png)
|
||||||
|
|
||||||
|
When you have finish, you have to press the button **Create Repository**.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_08.png)
|
||||||
|
|
||||||
|
Et voila, you have created a new repository on Gitea and you receive an https link.
|
||||||
|
This link is used if you want to share your project with someone, or you want to clone this repository.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_09.png)
|
||||||
|
|
||||||
|
If you want to work in your repository in Pycharm, you have to clone it.
|
||||||
|
In the toolbar, you can click on Git and you will find the button **Clone**.
|
||||||
|
Then, a window will be open, and you have to copy and paste the https link of your repository.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_10.png)
|
||||||
|
|
||||||
|
When the clone is successfully does, you can change the project.
|
||||||
|
And if you have finished your job, you can **Commit and Push**.
|
||||||
|
If you want to commit and push all changes that you have made, you have to check all changes in the left window.
|
||||||
|
And then, you can press **Commit and Push**.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_11.png)
|
||||||
|
|
||||||
|
In the bottom git window, you can see all commits, and their comments, of this repository.
|
||||||
|
If you clone a another repository, you will be able to see all commits that people made and their comment.
|
||||||
|
That is pretty cool !
|
||||||
|
|
||||||
|
## Adding some changes to our local code
|
||||||
|
|
||||||
|
In Gitea, you can see what the git repository contain and the last comment of commits.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_12.png)
|
||||||
|
|
||||||
|
If you check all changes and you want to **Commit and Push**, don't forget the comment.
|
||||||
|
That is important for a good teamwork.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_13.png)
|
||||||
|
|
||||||
|
If you commit twice, you are able to verify how many commits and when commits have done.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_14.png)
|
||||||
|
|
||||||
|
<!---
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_15.png)
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Cloning the remote project into a new project
|
||||||
|
In the main menu of PyCharm, you can click in **Get from VCS**.
|
||||||
|
If you click in it, you have just copy and paste the https link of the git repository.
|
||||||
|
|
||||||
|
To arrive at the *startup screen* shown below you need to close all open projects.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_clone_00.png)
|
||||||
|
|
||||||
|
You have to trust the git repository.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_clone_01.png)
|
||||||
|
|
||||||
|
And then, you can go to settings and choice your **Python interpreter**.
|
||||||
|
If you don't have one, you can add one.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_clone_02.png)
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_clone_03.png)
|
||||||
|
|
||||||
|
If you want to push your local repository, you have to identify with your name and your e-mail.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_clone_04.png)
|
||||||
|
|
||||||
|
Now, we have a new window where you can push yours commits.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_clone_05.png)
|
||||||
|
|
||||||
|
And if you push it, you have to login to Gitea.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_clone_06.png)
|
||||||
|
|
||||||
|
<!---
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_16.png)
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_17.png)
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Updating the original project
|
||||||
|
|
||||||
|
If someone adds something to your git repository, and you want to refresh your git repository.
|
||||||
|
You can tap to Git in the toolbar and then press **Pull**.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_18.png)
|
||||||
|
|
||||||
|
A window will appear to ask you which repository do you want to pull.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_19.png)
|
||||||
|
|
||||||
|
Et voila, your git repository is refreshed.
|
||||||
|
|
||||||
|
![screenhot](./assets/git_pycharm_source_20.png)
|
|
@ -65,6 +65,22 @@ TODO animated overview of the shell and the world of OOP
|
||||||
|
|
||||||
# Installing pycharm
|
# Installing pycharm
|
||||||
|
|
||||||
|
Depending on the platform you use, you can install Pycharm in multiple ways.
|
||||||
|
The computers in the classroom come with Pycharm installed but if you want to continue working from home you can follow the instructions [here](https://www.jetbrains.com/pycharm/download/#section=windows).
|
||||||
|
|
||||||
|
If you run Windows at home you will probably need to install python as well.
|
||||||
|
Download the latest version from [here](https://www.python.org/downloads/).
|
||||||
|
On Linux and Mac OSX there will probably be some version of python installed.
|
||||||
|
From a terminal you can check the version that's installed by executing the following commmands.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
waldek@metal:~$ python3 --version
|
||||||
|
Python 3.9.2
|
||||||
|
waldek@metal:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
## Virtual environments
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
# Your first project
|
# Your first project
|
||||||
|
@ -80,14 +96,10 @@ print("Hello World!")
|
||||||
Just for reference below are a few helloworld programs in different languages.
|
Just for reference below are a few helloworld programs in different languages.
|
||||||
First `c#` then `c` then `c++` and last but not least `javascript`.
|
First `c#` then `c` then `c++` and last but not least `javascript`.
|
||||||
|
|
||||||
### c#
|
|
||||||
|
|
||||||
```c#
|
```c#
|
||||||
Console.WriteLine("Hello World!");
|
Console.WriteLine("Hello World!");
|
||||||
```
|
```
|
||||||
|
|
||||||
### c
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
@ -97,8 +109,6 @@ int main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### c++
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// Your First C++ Program
|
// Your First C++ Program
|
||||||
|
|
||||||
|
@ -110,8 +120,6 @@ int main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### javascript
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
alert( 'Hello, world!' );
|
alert( 'Hello, world!' );
|
||||||
```
|
```
|
||||||
|
@ -209,7 +217,7 @@ But how can we **get** some information from the user?
|
||||||
This is done with the built-in `input` function.
|
This is done with the built-in `input` function.
|
||||||
If we open up a python shell we can observe it's behaviour.
|
If we open up a python shell we can observe it's behaviour.
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
>>> input()
|
>>> input()
|
||||||
hello world
|
hello world
|
||||||
'hello world'
|
'hello world'
|
||||||
|
@ -428,6 +436,41 @@ What about one that takes floating point numbers?
|
||||||
|
|
||||||
* [realpython](https://realpython.com/python-conditional-statements/) conditional logic
|
* [realpython](https://realpython.com/python-conditional-statements/) conditional logic
|
||||||
|
|
||||||
|
# Coding challenge - Currency converter
|
||||||
|
|
||||||
|
I would like you to write a program that converts EUR to DOLLAR.
|
||||||
|
You should do this in a **new** python file.
|
||||||
|
I suggest you call it `euro_to_dollar.py` or something that makes sense to you.
|
||||||
|
The result of this program *could* be as follows.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
➜ python_course_doc git:(master) ✗ python3 test.py
|
||||||
|
How much EUR would you like to convert into DOLLAR? 140
|
||||||
|
140 EUR is 159.6 DOLLAR
|
||||||
|
➜ python_course_doc git:(master) ✗ python3 test.py
|
||||||
|
How much EUR would you like to convert into DOLLAR? blablabla
|
||||||
|
That's not a number I understand...
|
||||||
|
➜ python_course_doc git:(master) ✗
|
||||||
|
```
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Spoiler warning</summary>
|
||||||
|
|
||||||
|
```python
|
||||||
|
result = input("How much EUR would you like to convert into DOLLAR? ")
|
||||||
|
|
||||||
|
rate = 1.14
|
||||||
|
|
||||||
|
if result.isdigit():
|
||||||
|
eur = int(result)
|
||||||
|
dollar = eur * rate
|
||||||
|
print("{} EUR is {} DOLLAR".format(eur, dollar))
|
||||||
|
else:
|
||||||
|
print("That's not a number I understand...")
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
# Coding challenge - Celsius to Fahrenheit converter
|
# Coding challenge - Celsius to Fahrenheit converter
|
||||||
|
|
||||||
Your first challenge!
|
Your first challenge!
|
||||||
|
@ -436,7 +479,7 @@ You should do this in a **new** python file.
|
||||||
I suggest you call it `c_to_f.py` or something that makes sense to you.
|
I suggest you call it `c_to_f.py` or something that makes sense to you.
|
||||||
The result of this program *could* be as follows.
|
The result of this program *could* be as follows.
|
||||||
|
|
||||||
```bash
|
```
|
||||||
➜ ~ git:(master) ✗ python3 ex_celcius_to_fahrenheit.py
|
➜ ~ git:(master) ✗ python3 ex_celcius_to_fahrenheit.py
|
||||||
What's the temperature?30
|
What's the temperature?30
|
||||||
30°C equals 86.0°F
|
30°C equals 86.0°F
|
||||||
|
@ -480,42 +523,6 @@ else:
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
# Coding challenge - Currency converter
|
|
||||||
|
|
||||||
I would like you to write a program that converts EUR to DOLLAR.
|
|
||||||
You should do this in a **new** python file.
|
|
||||||
I suggest you call it `euro_to_dollar.py` or something that makes sense to you.
|
|
||||||
The result of this program *could* be as follows.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
➜ python_course_doc git:(master) ✗ python3 test.py
|
|
||||||
How much EUR would you like to convert into DOLLAR? 140
|
|
||||||
140 EUR is 159.6 DOLLAR
|
|
||||||
➜ python_course_doc git:(master) ✗ python3 test.py
|
|
||||||
How much EUR would you like to convert into DOLLAR? blablabla
|
|
||||||
That's not a number I understand...
|
|
||||||
➜ python_course_doc git:(master) ✗
|
|
||||||
```
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Spoiler warning</summary>
|
|
||||||
|
|
||||||
```python
|
|
||||||
result = input("How much EUR would you like to convert into DOLLAR? ")
|
|
||||||
|
|
||||||
rate = 1.14
|
|
||||||
|
|
||||||
if result.isdigit():
|
|
||||||
eur = int(result)
|
|
||||||
dollar = eur * rate
|
|
||||||
print("{} EUR is {} DOLLAR".format(eur, dollar))
|
|
||||||
else:
|
|
||||||
print("That's not a number I understand...")
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
## Some links to read up on
|
## Some links to read up on
|
||||||
|
|
||||||
* how to convert string to float, Look at the response here: [str.isfloat()](https://stackoverflow.com/questions/736043/checking-if-a-string-can-be-converted-to-float-in-python)?
|
* how to convert string to float, Look at the response here: [str.isfloat()](https://stackoverflow.com/questions/736043/checking-if-a-string-can-be-converted-to-float-in-python)?
|
||||||
|
@ -1184,19 +1191,17 @@ while counter <= 10:
|
||||||
|
|
||||||
print("after the loop, counter: {}".format(counter))
|
print("after the loop, counter: {}".format(counter))
|
||||||
```
|
```
|
||||||
<details>
|
|
||||||
<summary>Another example</summary>
|
Or with only variables and a more verbose way of incrementing the numbers.
|
||||||
|
|
||||||
```python3
|
```python3
|
||||||
FirstValue = 2
|
first_value = 20
|
||||||
SecondValue = 0
|
second_value = 0
|
||||||
while FirstValue>SecondValue:
|
while first_value > second_value:
|
||||||
print("The second value is bigger")
|
print("second value {} is smaller than {}".format(second_value, first_value))
|
||||||
SecondValue = SecondValue + 1
|
second_value = second_value + 1
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
Two *extra* things might look new to you here.
|
Two *extra* things might look new to you here.
|
||||||
First the `import time` and `time.sleep(1)`, can you tell me what it does?
|
First the `import time` and `time.sleep(1)`, can you tell me what it does?
|
||||||
Next the `counter += 1` which is called [incrementing](https://stackoverflow.com/questions/1485841/behaviour-of-increment-and-decrement-operators-in-python).
|
Next the `counter += 1` which is called [incrementing](https://stackoverflow.com/questions/1485841/behaviour-of-increment-and-decrement-operators-in-python).
|
||||||
|
@ -1247,12 +1252,17 @@ print("after the loop, counter: {}".format(counter))
|
||||||
Infinite loops are a cornerstone of modern programming.
|
Infinite loops are a cornerstone of modern programming.
|
||||||
While they might look scary, don't overthink it, you'll get used to them very quickly.
|
While they might look scary, don't overthink it, you'll get used to them very quickly.
|
||||||
|
|
||||||
|
Logical procedures can be drawn out with flow charts.
|
||||||
|
An example can be seen in the image below.
|
||||||
|
|
||||||
|
![flowchart while loop](./assets/flowchart_while_01.png)
|
||||||
|
|
||||||
⛑ **When testing out an infinite loop it's sometimes handy to insert a `time.sleep` in it to slow down the execution a bit so you can wrap your head around what's happening.**
|
⛑ **When testing out an infinite loop it's sometimes handy to insert a `time.sleep` in it to slow down the execution a bit so you can wrap your head around what's happening.**
|
||||||
|
|
||||||
🏃 Try it
|
🏃 Try it
|
||||||
---
|
---
|
||||||
|
|
||||||
Go back to the Celsius to Farenheit converter and add a while loop to ensure the user puts in only numbers.
|
Go back to the Celsius to Fahrenheit converter and add a while loop to ensure the user puts in only numbers.
|
||||||
|
|
||||||
|
|
||||||
# Coding challenge - Guess the number
|
# Coding challenge - Guess the number
|
||||||
|
@ -1312,6 +1322,69 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
|
||||||
|
<summary> The Object Oriented program of Guess The Number </summary>
|
||||||
|
|
||||||
|
```python
|
||||||
|
import random
|
||||||
|
|
||||||
|
class ChoiceNumberInTheRange(object):
|
||||||
|
def ReturnRandomNumber(self, range):
|
||||||
|
return random.randint(0,int(range))
|
||||||
|
|
||||||
|
class GetTheNumberOfPlayer(object):
|
||||||
|
def GetNumber(self):
|
||||||
|
try:
|
||||||
|
Number = int(input("What is the number in your mind ?"))
|
||||||
|
return Number
|
||||||
|
except:
|
||||||
|
print("I need number !!")
|
||||||
|
|
||||||
|
class Right(object):
|
||||||
|
|
||||||
|
def Verification(self, right_number, number_guessed):
|
||||||
|
if right_number == number_guessed:
|
||||||
|
SayCorrect()
|
||||||
|
exit()
|
||||||
|
else:
|
||||||
|
NotCorrect(right_number, number_guessed)
|
||||||
|
|
||||||
|
|
||||||
|
class NotCorrect(object):
|
||||||
|
def __init__(self, right_number, number_guessed):
|
||||||
|
if right_number < number_guessed:
|
||||||
|
SayBigger()
|
||||||
|
elif right_number > number_guessed :
|
||||||
|
SaySmaller()
|
||||||
|
|
||||||
|
class SayBigger(object):
|
||||||
|
def __init__(self):
|
||||||
|
print("Your number is bigger")
|
||||||
|
|
||||||
|
class SaySmaller(object):
|
||||||
|
def __init__(self):
|
||||||
|
print("Your number is smaller")
|
||||||
|
|
||||||
|
class SayCorrect(object):
|
||||||
|
def __init__(self):
|
||||||
|
print("You win")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
Range = input("What is the range do you want")
|
||||||
|
RandomValue = ChoiceNumberInTheRange().ReturnRandomNumber(Range)
|
||||||
|
while True:
|
||||||
|
TheGuestResponse = GetTheNumberOfPlayer().GetNumber()
|
||||||
|
Right().Verification(right_number= RandomValue, number_guessed= TheGuestResponse)
|
||||||
|
|
||||||
|
```
|
||||||
|
All classes have a different task.
|
||||||
|
As you can see, there are classes for getting a random value in a range value (_ChoiceNumberInTheRange_ class).
|
||||||
|
Class for checking if the number is right or not (_Right_ class).
|
||||||
|
Classes for talking with the player if he wins or not.
|
||||||
|
If player getting the right value, you can use exit() method to stop the program.
|
||||||
|
</details>
|
||||||
|
|
||||||
🏃 Try it
|
🏃 Try it
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1381,9 +1454,10 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
#Logical Operators
|
# Logical Operators
|
||||||
|
|
||||||
There is three types of logical operators. All operators returns boolean.
|
There is three types of logical operators.
|
||||||
|
All operators return boolean values, ie `True` or `False`.
|
||||||
|
|
||||||
| Operator | Result |
|
| Operator | Result |
|
||||||
|-----------------|---------------------------------------------|
|
|-----------------|---------------------------------------------|
|
||||||
|
@ -1402,13 +1476,15 @@ DealerName = "Paul"
|
||||||
DealerAgreement = True
|
DealerAgreement = True
|
||||||
|
|
||||||
if CustomerAgreement and DealerAgreement :
|
if CustomerAgreement and DealerAgreement :
|
||||||
print(f"Youpi !!! {CustomerName} and {DealerName} are agreed ")
|
print(f"Youpi !!! {CustomerName} and {DealerName} agree")
|
||||||
else:
|
else:
|
||||||
print(f"Oh no {CustomerName} and {DealerName} are disagreed ;( ")
|
print(f"Oh no, {CustomerName} and {DealerName} don't agree... ;(")
|
||||||
```
|
```
|
||||||
As you can guess, Jean and Paul are agreeing to the deal. If I had put 'False' in DealerAgreement boolean, the result will be inverse.
|
|
||||||
|
|
||||||
Let's show an another example with the `Or` operator.
|
As you can guess, Jean and Paul are agreeing to the deal.
|
||||||
|
If I had put `False` in `DealerAgreement` boolean, the result would be reversed.
|
||||||
|
|
||||||
|
Let's show another example but this time with the `Or` operator.
|
||||||
|
|
||||||
````python3
|
````python3
|
||||||
def Choice_cold_hot(Temperature):
|
def Choice_cold_hot(Temperature):
|
||||||
|
@ -1417,13 +1493,18 @@ def Choice_cold_hot(Temperature):
|
||||||
else:
|
else:
|
||||||
print("Let's go to the beach")
|
print("Let's go to the beach")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
Temperature = int(input("What is the temperature"))
|
Temperature = int(input("What is the temperature"))
|
||||||
Choice_cold_hot(Temperature)
|
Choice_cold_hot(Temperature)
|
||||||
````
|
````
|
||||||
Look at this code, if the temperature is smaller than 20° or bigger than 40°, you must stay home and don't go to the beach. So, if I put 35° for temperature, it will say that you should go to the beach.
|
|
||||||
|
|
||||||
Let's make an exercise. You have to take the previous code and use the `And` operator.
|
Look at this code, if the temperature is smaller than 20° or bigger than 40°, you must stay home and don't go to the beach.
|
||||||
|
So, if I put 35° as temperature, it will say that you should go to the beach.
|
||||||
|
|
||||||
|
Let's try this out as an exercise!
|
||||||
|
Reuse the previous code but integrate the `And` operator.
|
||||||
|
The result should be identical.
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Spoiler warning</summary>
|
<summary>Spoiler warning</summary>
|
||||||
|
@ -1434,13 +1515,15 @@ def Choice_cold_hot(Temperature):
|
||||||
print("Let's go to the beach")
|
print("Let's go to the beach")
|
||||||
else:
|
else:
|
||||||
print("Don't go outside")
|
print("Don't go outside")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
Temperature = int(input("What is the temperature"))
|
Temperature = int(input("What is the temperature"))
|
||||||
Choice_cold_hot(Temperature)
|
Choice_cold_hot(Temperature)
|
||||||
````
|
````
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
Now, we have used that operators, we can use the last logical operator. The `Not` operator sends the reverse of the result.
|
Now that we have discovered the base operators we can learn the last logical operator `not` which gives us the reverse of the expected result.
|
||||||
|
|
||||||
````python3
|
````python3
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -1450,7 +1533,9 @@ if __name__ == "__main__":
|
||||||
else:
|
else:
|
||||||
print("That will be expensive")
|
print("That will be expensive")
|
||||||
````
|
````
|
||||||
|
|
||||||
In this example, if you tap yes, the result will be reversed.
|
In this example, if you tap yes, the result will be reversed.
|
||||||
|
|
||||||
# Lists
|
# Lists
|
||||||
|
|
||||||
The different built-in objects we've seen until now, such as `str` and `int` are simple [text](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str) and [numeric](https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex) types.
|
The different built-in objects we've seen until now, such as `str` and `int` are simple [text](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str) and [numeric](https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex) types.
|
||||||
|
|
|
@ -3,134 +3,136 @@
|
||||||
## Tkinter helloworld
|
## Tkinter helloworld
|
||||||
|
|
||||||
The absolute most basic way to have a *hello world* GUI program up and running with Tkinter is the following.
|
The absolute most basic way to have a *hello world* GUI program up and running with Tkinter is the following.
|
||||||
|
It creates an *application*, sets the *title* as `hello world` and enters the **main eventloop**.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from tkinter import *
|
import tkinter as tk
|
||||||
|
|
||||||
root = Tk()
|
root = tk.Tk()
|
||||||
|
root.title("hello world")
|
||||||
MyLabel = Label(root,text="hello world")
|
|
||||||
MyLabel.pack()
|
|
||||||
|
|
||||||
root.mainloop()
|
root.mainloop()
|
||||||
```
|
```
|
||||||
Tkinter have two popular architectures, the Tcl and Tk. This two architectures are different, they have their own functionality and their own official documentation.
|
|
||||||
We are gonna use the Tk architecture.
|
|
||||||
|
|
||||||
The Tk architecture is used to create a GUI widget. He adds a lot of custom commands, so the widget is very customizable.
|
Tkinter has two popular architectures, Tcl and Tk.
|
||||||
|
These two architectures are quite different as they each have their own functionality and their own official documentation.
|
||||||
|
We are going use the Tk architecture.
|
||||||
|
|
||||||
In the previous code,the `mainloop()` instruction allows us to open the main window and to not close immediately the window.
|
The Tk architecture is used to create a GUI widget which has a lot of **methods** and **attributes** so it's quite customizable.
|
||||||
And then, the `Label()` method creates label in a layout. This method has many parameters to customize a label. The instruction `pack()` will be always call , this instruction can
|
|
||||||
add and adjust a widget.
|
In the previous code,the `mainloop()` method allows us to open the main window and to not close the window immediately .
|
||||||
|
This **event loop** will process all mouse event, button clicks, and changes.
|
||||||
|
|
||||||
While it works we know better by now.
|
While it works we know better by now.
|
||||||
We should include the `if __name__ == "__main__"` statement.
|
We should include the `if __name__ == "__main__"` statement so let's do this!
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from tkinter import *
|
import tkinter as tk
|
||||||
if __name__ == "__main__":
|
|
||||||
root = Tk()
|
|
||||||
|
|
||||||
MyLabel = Label(root,text="hello world")
|
if __name__ == "__main__":
|
||||||
MyLabel.pack()
|
root = tk.Tk()
|
||||||
|
root.title("hello world")
|
||||||
|
|
||||||
root.mainloop()
|
root.mainloop()
|
||||||
```
|
```
|
||||||
|
|
||||||
The instance of `Tk()` is what will actually process our event loop and the `root` is the content of our window. We can customize `root` with instruction like geometry, title,etc.
|
The instance of `tk.Tk()` is what will actually process our event loop and the `root` is the content of our window. We can customize `root` with instruction like geometry, title, etc.
|
||||||
In the latter we will create our button and labels so should create our own class and inherit from it.
|
To this instance we can attach other widgets and display them.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from tkinter import *
|
import tkinter as tk
|
||||||
|
|
||||||
class MainWindow(Frame):
|
|
||||||
|
class Application(tk.Tk):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Label.__init__(self, text="hello world")
|
tk.Tk.__init__(self)
|
||||||
self.pack()
|
self.title("hello world")
|
||||||
|
self.geometry("500x400")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
root = Tk()
|
app = Application()
|
||||||
root.title("title of the window")
|
app.mainloop()
|
||||||
root.geometry("500x300")
|
|
||||||
MainWindow()
|
|
||||||
root.mainloop()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
We can add content to the *frame*, such as labels, input boxes and buttons as follows.
|
## Adding widgets
|
||||||
|
|
||||||
|
We can add content to this window, such as labels, input boxes and buttons as follows.
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from tkinter import *
|
import tkinter as tk
|
||||||
|
|
||||||
class MainWindow(Frame):
|
|
||||||
|
class Application(tk.Tk):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Label.__init__(self, text="hello world")
|
tk.Tk.__init__(self)
|
||||||
#Label
|
self.title("hello world")
|
||||||
MyLabel = Label(self, text="This is a label")
|
self.geometry("500x400")
|
||||||
MyLabel.pack()
|
self.resizable(0, 0)
|
||||||
|
self.label = tk.Label(self, text="This is a label", bg="yellow")
|
||||||
|
self.label.pack()
|
||||||
|
|
||||||
self.config(bg="yellow")
|
|
||||||
self.pack()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
root = Tk()
|
app = Application()
|
||||||
root.title("title of the window")
|
app.mainloop()
|
||||||
root.geometry("500x300")
|
|
||||||
MainWindow()
|
|
||||||
root.mainloop()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Let's try to put multiple visual object into the same frame.
|
Let's try to put multiple visual object into the same window.
|
||||||
|
|
||||||
```python3
|
```python3
|
||||||
from tkinter import *
|
import tkinter as tk
|
||||||
|
|
||||||
class MainWindow(Frame):
|
|
||||||
|
class Application(tk.Tk):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Label.__init__(self, text="hello world")
|
tk.Tk.__init__(self)
|
||||||
#Label
|
self.title("hello world")
|
||||||
MyLabel = Label(self, text="This is a label")
|
self.geometry("500x400")
|
||||||
MyLabel.pack()
|
self.label = tk.Label(text="This is a label")
|
||||||
#Button
|
self.label.pack()
|
||||||
MyButton = Button(self, text="I'm clickable!")
|
|
||||||
MyButton.pack()
|
self.button = tk.Button(text="I'm clickable!")
|
||||||
|
self.button.pack()
|
||||||
self.config(bg="yellow")
|
|
||||||
self.pack()
|
self.output = tk.Label(text="I'm a second label")
|
||||||
|
self.output.pack()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
root = Tk()
|
app = Application()
|
||||||
root.title("title of the window")
|
app.mainloop()
|
||||||
root.geometry("500x300")
|
|
||||||
MainWindow()
|
|
||||||
root.mainloop()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
You see how they are *stacked* one on top of the other?
|
You see how they are *stacked* one on top of the other?
|
||||||
We can overcome this problem with parameters of [pack()](https://wxpython.org/Phoenix/docs/html/sizers_overview.html).
|
We can overcome this problem with parameters of [pack()](https://wxpython.org/Phoenix/docs/html/sizers_overview.html) or we can use other geometry managers like [grid()](https://www.pythontutorial.net/tkinter/tkinter-grid/) and [place()](https://www.pythontutorial.net/tkinter/tkinter-place/).
|
||||||
We can also use other geometry managers like [grid()](https://www.pythontutorial.net/tkinter/tkinter-grid/) and [place()](https://www.pythontutorial.net/tkinter/tkinter-place/).
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from tkinter import *
|
import tkinter as tk
|
||||||
|
|
||||||
class MainWindow(Frame):
|
|
||||||
|
class Application(tk.Tk):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Frame.__init__(self, master=None)
|
tk.Tk.__init__(self)
|
||||||
MyPanel = PanedWindow.__init__(self, bg="Blue")
|
self.title("hello world")
|
||||||
#Label
|
self.geometry("500x400")
|
||||||
MyLabel = Label(MyPanel, text="this is a label", bg= "yellow")
|
self.resizable(0, 0)
|
||||||
MyLabel.pack(fill="x")
|
self.label = tk.Label(self, text="This is a label", bg="yellow")
|
||||||
#Bouton
|
self.label.grid(column=0, row=0, sticky=tk.W, padx=5, pady=5)
|
||||||
MyButton = Button(MyPanel, text="I'm clickable!")
|
|
||||||
MyButton.place(x=10, y=50)
|
self.button = tk.Button(self, text="I'm clickable!")
|
||||||
self.pack(fill=BOTH,expand=True)
|
self.button.grid(column=1, row=0, sticky=tk.E, padx=5, pady=5)
|
||||||
|
|
||||||
|
self.output = tk.Label(self, text="I'm a second label")
|
||||||
|
self.output.grid(column=1, row=1, sticky=tk.E, padx=5, pady=5)
|
||||||
|
|
||||||
|
self.config(bg="yellow")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
root = Tk()
|
app = Application()
|
||||||
root.title("this is the title of the window")
|
app.mainloop()
|
||||||
root.geometry("500x300")
|
|
||||||
win = MainWindow()
|
|
||||||
root.mainloop()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This is looking better!
|
This is looking better!
|
||||||
|
@ -152,353 +154,408 @@ Each time we click the button, that method will be called.
|
||||||
Because it is a *method* it has access to *self* so it can modify *anything* within the scope of the instance.
|
Because it is a *method* it has access to *self* so it can modify *anything* within the scope of the instance.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from tkinter import *
|
import tkinter as tk
|
||||||
class MainWindow(Frame):
|
|
||||||
def __init__(self):
|
|
||||||
Frame.__init__(self, master=None)
|
|
||||||
MyPanel = PanedWindow.__init__(self, bg="Blue")
|
|
||||||
#Label
|
|
||||||
MyLabel = Label(MyPanel, text="this is a label", bg= "yellow")
|
|
||||||
MyLabel.pack(fill="x")
|
|
||||||
#Bouton
|
|
||||||
MyButton = Button(MyPanel, text="I'm clickable!", command=lambda : self.ButtonEnable(MyLabel))
|
|
||||||
MyButton.place(x=10, y=50)
|
|
||||||
self.pack(fill=BOTH,expand=True)
|
|
||||||
|
|
||||||
def ButtonEnable(self, Label):
|
|
||||||
global number
|
|
||||||
number += 1
|
|
||||||
counter = "You have press the button {} time".format(number)
|
|
||||||
Label.config(text=counter)
|
|
||||||
|
|
||||||
|
|
||||||
number=0
|
class Application(tk.Tk):
|
||||||
|
def __init__(self):
|
||||||
|
tk.Tk.__init__(self)
|
||||||
|
self.title("hello world")
|
||||||
|
self.geometry("500x400")
|
||||||
|
self.resizable(0, 0)
|
||||||
|
self.label = tk.Label(self, text="This is a label", bg="yellow")
|
||||||
|
self.label.pack()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
self.button = tk.Button(self, text="I'm clickable!", command=self.clicked)
|
||||||
root = Tk()
|
self.button.pack()
|
||||||
root.title("this is the title of the window")
|
|
||||||
root.geometry("500x300")
|
|
||||||
win = MainWindow()
|
|
||||||
root.mainloop()
|
|
||||||
|
|
||||||
|
self.output = tk.Label(self, text="I'm a second label")
|
||||||
|
self.output.pack()
|
||||||
|
|
||||||
```
|
self.config(bg="yellow")
|
||||||
|
|
||||||
We can use the same *idea* to grab input from the textbox.
|
def clicked(self):
|
||||||
|
print("hello world!")
|
||||||
```python
|
|
||||||
from tkinter import *
|
|
||||||
|
|
||||||
class MainWindow(Frame):
|
|
||||||
def __init__(self):
|
|
||||||
Frame.__init__(self, master=None)
|
|
||||||
MyPanel = PanedWindow.__init__(self, bg="Blue")
|
|
||||||
#Label
|
|
||||||
MyLabel = Label(MyPanel, text="this is a label", bg= "yellow")
|
|
||||||
MyLabel.pack(fill="x")
|
|
||||||
#TextBox
|
|
||||||
MyEntry = Entry(MyPanel)
|
|
||||||
MyEntry.place(x=200,y=50)
|
|
||||||
#Bouton
|
|
||||||
MyButton = Button(MyPanel, text="I'm clickable!", command=lambda : self.ButtonEnable(MyLabel,MyEntry))
|
|
||||||
MyButton.place(x=10, y=50)
|
|
||||||
self.pack(fill=BOTH,expand=True)
|
|
||||||
|
|
||||||
|
|
||||||
def ButtonEnable(self, MyLabel, MyEntry):
|
|
||||||
MyText = MyEntry.get()
|
|
||||||
MyLabel.config(text=MyText)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
root = Tk()
|
app = Application()
|
||||||
root.title("this is the title of the window")
|
app.mainloop()
|
||||||
root.geometry("500x300")
|
|
||||||
win = MainWindow()
|
|
||||||
root.mainloop()
|
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Tkinter guess the number
|
We can see *hello world!* printed to the console with each click!
|
||||||
|
As we're using a `class` we have *access* to the instance of the application so we can use the `self.output` label to show our messages.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import time
|
import tkinter as tk
|
||||||
from tkinter import *
|
|
||||||
|
|
||||||
|
class Application(tk.Tk):
|
||||||
|
def __init__(self):
|
||||||
|
tk.Tk.__init__(self)
|
||||||
|
self.title("hello world")
|
||||||
|
self.geometry("500x400")
|
||||||
|
self.resizable(0, 0)
|
||||||
|
self.label = tk.Label(self, text="This is a label", bg="yellow")
|
||||||
|
self.label.pack()
|
||||||
|
|
||||||
|
self.button = tk.Button(self, text="I'm clickable!", command=self.clicked)
|
||||||
|
self.button.pack()
|
||||||
|
|
||||||
|
self.output = tk.Label(self, text="I'm a second label")
|
||||||
|
self.output.pack()
|
||||||
|
|
||||||
|
self.config(bg="yellow")
|
||||||
|
self.counter = 0
|
||||||
|
|
||||||
|
def clicked(self):
|
||||||
|
self.counter += 1
|
||||||
|
self.output.config(text="butter has been clicked {} times".format(self.counter))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = Application()
|
||||||
|
app.mainloop()
|
||||||
|
```
|
||||||
|
|
||||||
|
🏃 Try it
|
||||||
|
---
|
||||||
|
|
||||||
|
We can use the same *idea* to grab input from the input boxes called `tk.Entry`.
|
||||||
|
The code below *adds* two numbers but it's not working properly.
|
||||||
|
Can you fix it for me please?
|
||||||
|
|
||||||
|
```python
|
||||||
|
import tkinter as tk
|
||||||
|
|
||||||
|
|
||||||
|
class Application(tk.Tk):
|
||||||
|
def __init__(self):
|
||||||
|
tk.Tk.__init__(self)
|
||||||
|
self.title("hello world")
|
||||||
|
self.geometry("500x400")
|
||||||
|
self.resizable(0, 0)
|
||||||
|
self.label_one = tk.Label(self, text="Number 1:", bg="yellow")
|
||||||
|
self.label_one.grid(column=0, row=0, sticky=tk.W, padx=5, pady=5)
|
||||||
|
|
||||||
|
self.label_two = tk.Label(self, text="Number 2:", bg="yellow")
|
||||||
|
self.label_two.grid(column=0, row=1, sticky=tk.W, padx=5, pady=5)
|
||||||
|
|
||||||
|
self.input_one = tk.Entry(self)
|
||||||
|
self.input_one.grid(column=1, row=0, sticky=tk.W, padx=5, pady=5)
|
||||||
|
self.input_two = tk.Entry(self)
|
||||||
|
self.input_two.grid(column=1, row=1, sticky=tk.W, padx=5, pady=5)
|
||||||
|
|
||||||
|
self.button = tk.Button(self, text="add two numbers", command=self.clicked)
|
||||||
|
self.button.grid(column=0, row=3, sticky=tk.W, padx=5, pady=5)
|
||||||
|
|
||||||
|
self.output = tk.Label(self, text="...")
|
||||||
|
self.output.grid(column=1, row=3, sticky=tk.W, padx=5, pady=5)
|
||||||
|
|
||||||
|
self.config(bg="yellow")
|
||||||
|
|
||||||
|
def clicked(self):
|
||||||
|
number_one = self.input_one.get()
|
||||||
|
number_two = self.input_two.get()
|
||||||
|
total = number_one + number_two
|
||||||
|
self.output.config(text="sum: {}".format(total))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = Application()
|
||||||
|
app.mainloop()
|
||||||
|
```
|
||||||
|
|
||||||
|
# Coding challenge - Guess the number
|
||||||
|
|
||||||
|
Can you code me a *guess the number* game but using `tkinter`?
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Spoiler warning</summary>
|
||||||
|
|
||||||
|
```python
|
||||||
|
import tkinter as tk
|
||||||
import random
|
import random
|
||||||
|
|
||||||
class MainWindow(Frame):
|
|
||||||
|
class Application(tk.Tk):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Frame.__init__(self, master=None, bg="white")
|
tk.Tk.__init__(self)
|
||||||
MyPanel = PanedWindow.__init__(self)
|
self.title("hello world")
|
||||||
|
self.geometry("500x400")
|
||||||
|
self.resizable(0, 0)
|
||||||
|
|
||||||
MyNumber = random.randint(0, 100)
|
self.number = random.randint(0, 10)
|
||||||
|
|
||||||
#Label
|
self.header = tk.Label(text="I have a number in mind...")
|
||||||
self.MyLabel = Label(MyPanel, text="I have a number in mind...", bg= "blue")
|
self.header.grid(column=0, row=0, sticky=tk.W)
|
||||||
self.MyLabel.pack(fill="x", ipadx=25, ipady=20)
|
|
||||||
#TextBox
|
|
||||||
MyEntry = Entry(MyPanel)
|
|
||||||
MyEntry.place(x=200,y=90)
|
|
||||||
#Bouton
|
|
||||||
MyButton = Button(MyPanel, text="I'm clickable!", command=lambda : self.ButtonEnable(MyEntry, MyNumber))
|
|
||||||
MyButton.place(x=10, y=90)
|
|
||||||
|
|
||||||
self.pack(fill=BOTH,expand=True)
|
self.question = tk.Label(self, text="What's your guess?")
|
||||||
|
self.question.grid(column=0, row=1, sticky=tk.W)
|
||||||
|
|
||||||
|
self.input = tk.Entry(self)
|
||||||
|
self.input.grid(column=1, row=1, sticky=tk.W)
|
||||||
|
|
||||||
def ButtonEnable(self, MyEntry, MyNumber):
|
self.button = tk.Button(self, text="check", command=self.clicked)
|
||||||
if self.IsCorrect(MyEntry.get()):
|
self.button.grid(column=0, row=2, sticky=tk.W)
|
||||||
number = int(MyEntry.get())
|
|
||||||
if number != MyNumber:
|
self.output = tk.Label(self, text="...")
|
||||||
self.GameOver(number, MyNumber)
|
self.output.grid(column=1, row=2, sticky=tk.W)
|
||||||
else:
|
|
||||||
self.Win()
|
def _is_entry_digit(self):
|
||||||
|
number = self.input.get()
|
||||||
|
if number.isdigit():
|
||||||
|
number = int(number)
|
||||||
|
return number
|
||||||
|
|
||||||
|
def clicked(self):
|
||||||
|
number = self._is_entry_digit()
|
||||||
|
if not number:
|
||||||
|
msg = "numbers please..."
|
||||||
else:
|
else:
|
||||||
self.MyLabel.config(text="I need numbers!")
|
if number < self.number:
|
||||||
|
msg = "my number is bigger"
|
||||||
def GameOver(self, number, MyNumber):
|
elif number > self.number:
|
||||||
if number > MyNumber:
|
msg = "my number is smaller"
|
||||||
self.MyLabel.config(text="My number is smaller")
|
elif number == self.number:
|
||||||
else:
|
msg = "bingo!"
|
||||||
self.MyLabel.config(text="My number is bigger")
|
self.output.config(text=msg)
|
||||||
|
|
||||||
def Win(self):
|
|
||||||
self.MyLabel.config(text="You WIN!")
|
|
||||||
|
|
||||||
def IsCorrect(self, MyEntry):
|
|
||||||
x = str(MyEntry)
|
|
||||||
if x.isdigit() == True:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
root = Tk()
|
app = Application()
|
||||||
root.title("Guess the number")
|
app.mainloop()
|
||||||
root.geometry("500x300")
|
```
|
||||||
win = MainWindow()
|
</details>
|
||||||
root.mainloop()
|
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>With replay function</summary>
|
||||||
|
|
||||||
|
```python
|
||||||
|
import tkinter as tk
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
class Application(tk.Tk):
|
||||||
|
def __init__(self):
|
||||||
|
tk.Tk.__init__(self)
|
||||||
|
self.title("hello world")
|
||||||
|
self.geometry("500x400")
|
||||||
|
self.resizable(0, 0)
|
||||||
|
|
||||||
|
self.header = tk.Label(text="I have a number in mind...")
|
||||||
|
self.header.grid(column=0, row=0, sticky=tk.W)
|
||||||
|
|
||||||
|
self.question = tk.Label(self, text="What's your guess?")
|
||||||
|
self.question.grid(column=0, row=1, sticky=tk.W)
|
||||||
|
|
||||||
|
self.input = tk.Entry(self)
|
||||||
|
self.input.grid(column=1, row=1, sticky=tk.W)
|
||||||
|
|
||||||
|
self.button = tk.Button(self, text="check", command=self.clicked)
|
||||||
|
self.button.grid(column=0, row=2, sticky=tk.W)
|
||||||
|
|
||||||
|
self.output = tk.Label(self, text="...")
|
||||||
|
self.output.grid(column=1, row=2, sticky=tk.W)
|
||||||
|
|
||||||
|
self.init_new_game()
|
||||||
|
|
||||||
|
def _is_entry_digit(self):
|
||||||
|
number = self.input.get()
|
||||||
|
if number.isdigit():
|
||||||
|
number = int(number)
|
||||||
|
return number
|
||||||
|
|
||||||
|
def compare_numbers(self):
|
||||||
|
number = self._is_entry_digit()
|
||||||
|
if not number:
|
||||||
|
msg = "numbers please..."
|
||||||
|
else:
|
||||||
|
if number < self.number:
|
||||||
|
msg = "my number is bigger"
|
||||||
|
elif number > self.number:
|
||||||
|
msg = "my number is smaller"
|
||||||
|
elif number == self.number:
|
||||||
|
msg = "bingo!"
|
||||||
|
self.won = True
|
||||||
|
self.button.config(text="play again!")
|
||||||
|
self.output.config(text=msg)
|
||||||
|
|
||||||
|
def init_new_game(self):
|
||||||
|
self.won = False
|
||||||
|
self.number = random.randint(0, 100)
|
||||||
|
print(self.number)
|
||||||
|
self.button.config(text="check")
|
||||||
|
self.output.config(text="")
|
||||||
|
self.input.delete(0, 'end')
|
||||||
|
|
||||||
|
def clicked(self):
|
||||||
|
if self.won:
|
||||||
|
self.init_new_game()
|
||||||
|
else:
|
||||||
|
self.compare_numbers()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = Application()
|
||||||
|
app.mainloop()
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
</detail>
|
||||||
|
|
||||||
## MVC design pattern
|
## MVC design pattern
|
||||||
|
|
||||||
A simple console only MVC.
|
A simple console only MVC.
|
||||||
We'll add the GUI view in a bit.
|
We'll add the GUI view in a bit.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from tkinter import *
|
import tkinter as tk
|
||||||
|
|
||||||
|
|
||||||
class ConsoleView(object):
|
class ConsoleView(object):
|
||||||
"""A view for console."""
|
"""A view for console."""
|
||||||
|
|
||||||
def select_task(self):
|
def __init__(self, controller):
|
||||||
"""Asks which index to look up."""
|
|
||||||
idx = input("which task do you want to see? ")
|
|
||||||
return idx
|
|
||||||
|
|
||||||
def show(self, task):
|
|
||||||
"""Displays the task to the console. This method is called from the
|
|
||||||
controller."""
|
|
||||||
print("your task: {}".format(task))
|
|
||||||
|
|
||||||
def error(self, msg):
|
|
||||||
"""Prints error messages coming from the controller."""
|
|
||||||
print("error: {}".format(msg))
|
|
||||||
|
|
||||||
class Model(object):
|
|
||||||
"""The model houses add data and should implement all methods related to
|
|
||||||
adding, modifying and deleting tasks."""
|
|
||||||
|
|
||||||
db = ["go to the shops", "dryhop beer", "drop of motorbike"]
|
|
||||||
|
|
||||||
def get_task(self, idx):
|
|
||||||
"""Performs a task lookun into the database and returns it when found.
|
|
||||||
If no task is found, it returns an error message that will be displayed
|
|
||||||
in the view (via the controller)."""
|
|
||||||
try:
|
|
||||||
task = Model.db[idx]
|
|
||||||
except IndexError:
|
|
||||||
task = "task with {} not found!".format(idx)
|
|
||||||
return task
|
|
||||||
|
|
||||||
|
|
||||||
class Controller(object):
|
|
||||||
"""Binds the model and the view together."""
|
|
||||||
|
|
||||||
def __init__(self, view):
|
|
||||||
self.model = Model()
|
|
||||||
self.view = view
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
"""The controller's main function. Depending on what type of view is
|
|
||||||
selected, a different event loop is setup. Do note that the ConsoleView
|
|
||||||
is not a real event loop, just a basic flow of action."""
|
|
||||||
if self.view is ConsoleView:
|
|
||||||
self.view = self.view()
|
|
||||||
self._run_console_view()
|
|
||||||
elif self.view is TkinterView:
|
|
||||||
root = Tk()
|
|
||||||
root.title("Task Manager")
|
|
||||||
root.geometry("500x300")
|
|
||||||
self.view = self.view()
|
|
||||||
self.view._set_controller(self)
|
|
||||||
root.mainloop()
|
|
||||||
|
|
||||||
def get_task_from_model(self, idx):
|
|
||||||
"""Needed for the TkinterView to communicate with the controller."""
|
|
||||||
task = self.model.get_task(idx)
|
|
||||||
self.view.show_task(task)
|
|
||||||
|
|
||||||
def _run_console_view(self):
|
|
||||||
"""Super simple event loop."""
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
idx = self.view.select_task()
|
|
||||||
idx = int(idx)
|
|
||||||
except Exception as e:
|
|
||||||
self.view.error(e)
|
|
||||||
continue
|
|
||||||
task = self.model.get_task(idx)
|
|
||||||
self.view.show(task)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
view = ConsoleView
|
|
||||||
app = Controller(view)
|
|
||||||
app.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
And now with the implemented `TkinterView` class.
|
|
||||||
|
|
||||||
```python
|
|
||||||
from tkinter import *
|
|
||||||
|
|
||||||
class ConsoleView(object):
|
|
||||||
"""A view for console."""
|
|
||||||
|
|
||||||
def select_task(self):
|
|
||||||
"""Asks which index to look up."""
|
|
||||||
idx = input("which task do you want to see? ")
|
|
||||||
return idx
|
|
||||||
|
|
||||||
def show(self, task):
|
|
||||||
"""Displays the task to the console. This method is called from the
|
|
||||||
controller."""
|
|
||||||
print("your task: {}".format(task))
|
|
||||||
|
|
||||||
def error(self, msg):
|
|
||||||
"""Prints error messages coming from the controller."""
|
|
||||||
print("error: {}".format(msg))
|
|
||||||
|
|
||||||
|
|
||||||
class TkinterView(Frame):
|
|
||||||
"""A view using a wx.Dialog window"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
Frame.__init__(self, master=None)
|
|
||||||
#Panel
|
|
||||||
self.panel = PanedWindow(self, bg="green")
|
|
||||||
self.panel.pack(fill=BOTH, expand=True)
|
|
||||||
|
|
||||||
#Task Label
|
|
||||||
self.task = Label(self.panel, text="your task")
|
|
||||||
self.task.pack(expand=True)
|
|
||||||
|
|
||||||
#SpinBox
|
|
||||||
self.idx = Spinbox(self.panel, from_=0, to=2, wrap=True )
|
|
||||||
self.idx.pack(side= TOP)
|
|
||||||
|
|
||||||
#Button
|
|
||||||
self.button = Button(self.panel, text="submit", command=lambda : self.select_task())
|
|
||||||
self.button.pack(ipadx=60, ipady=30)
|
|
||||||
|
|
||||||
self.pack(fill=BOTH, expand=True)
|
|
||||||
|
|
||||||
def _set_controller(self, controller):
|
|
||||||
"""Set the controller so the view can communicate it's requests to it
|
|
||||||
and update it's values too."""
|
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
|
|
||||||
def select_task(self):
|
def select_task(self):
|
||||||
"""Gets the index to look up in the model and submits the request to
|
"""Asks which index to look up."""
|
||||||
the controller."""
|
idx = input("which task do you want to see? ")
|
||||||
idx = self.idx.get()
|
return idx
|
||||||
self.controller.get_task_from_model(idx)
|
|
||||||
|
|
||||||
def show_task(self, task):
|
def show_message(self, msg):
|
||||||
"""Updates the visual label in the view with the task. This method is
|
print("MSG: {}".format(msg))
|
||||||
called from the controller."""
|
|
||||||
self.task.config(text=task)
|
def show(self, task):
|
||||||
|
"""Displays the task to the console. This method is called from the
|
||||||
|
controller."""
|
||||||
|
print("your task: {}".format(task))
|
||||||
|
|
||||||
|
def error(self, msg):
|
||||||
|
"""Prints error messages coming from the controller."""
|
||||||
|
print("error: {}".format(msg))
|
||||||
|
|
||||||
|
def mainloop(self):
|
||||||
|
"""Super simple event loop."""
|
||||||
|
while True:
|
||||||
|
self.controller.request_number_of_tasks_from_model()
|
||||||
|
try:
|
||||||
|
idx = self.select_task()
|
||||||
|
idx = int(idx)
|
||||||
|
except Exception as e:
|
||||||
|
self.error(e)
|
||||||
|
continue
|
||||||
|
self.controller.request_task_from_model(idx)
|
||||||
|
|
||||||
|
|
||||||
class Model(object):
|
class Model(object):
|
||||||
"""The model houses add data and should implement all methods related to
|
"""The model houses add data and should implement all methods related to
|
||||||
adding, modifying and deleting tasks."""
|
adding, modifying and deleting tasks."""
|
||||||
|
|
||||||
db = ["go to the shops", "dryhop beer", "drop of motorbike"]
|
def __init__(self):
|
||||||
|
self.db = ["go to the shops", "dryhop beer", "drop of motorbike"]
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.db)
|
||||||
|
|
||||||
def get_task(self, idx):
|
def get_task(self, idx):
|
||||||
"""Performs a task lookun into the database and returns it when found.
|
"""Performs a task lookun into the database and returns it when found.
|
||||||
If no task is found, it returns an error message that will be displayed
|
If no task is found, it returns an error message that will be displayed
|
||||||
in the view (via the controller)."""
|
in the view (via the controller)."""
|
||||||
try:
|
try:
|
||||||
task = Model.db[int(idx)]
|
task = self.db[idx]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
task = "task with {} not found!".format(idx)
|
task = None
|
||||||
return task
|
return task
|
||||||
|
|
||||||
|
|
||||||
class Controller(object):
|
class Controller(object):
|
||||||
"""Binds the model and the view together."""
|
"""Binds the model and the view together."""
|
||||||
|
|
||||||
def __init__(self, view):
|
def __init__(self, model):
|
||||||
self.model = Model()
|
self.model = model
|
||||||
|
|
||||||
|
def set_view(self, view):
|
||||||
self.view = view
|
self.view = view
|
||||||
|
if isinstance(view, TkinterView):
|
||||||
|
self.request_number_of_tasks_from_model()
|
||||||
|
|
||||||
def run(self):
|
def request_number_of_tasks_from_model(self):
|
||||||
"""The controller's main function. Depending on what type of view is
|
number = len(self.model)
|
||||||
selected, a different event loop is setup. Do note that the ConsoleView
|
self.view.show_message("you have {} tasks".format(number))
|
||||||
is not a real event loop, just a basic flow of action."""
|
|
||||||
if self.view is ConsoleView:
|
|
||||||
self.view = self.view()
|
|
||||||
self._run_console_view()
|
|
||||||
elif self.view is TkinterView:
|
|
||||||
root = Tk()
|
|
||||||
root.title("Task Manager")
|
|
||||||
root.geometry("500x300")
|
|
||||||
self.view = self.view()
|
|
||||||
self.view._set_controller(self)
|
|
||||||
root.mainloop()
|
|
||||||
|
|
||||||
def get_task_from_model(self, idx):
|
def request_task_from_model(self, idx):
|
||||||
"""Needed for the TkinterView to communicate with the controller."""
|
"""Needed for the ConsoleView and TkinterView to communicate with the controller."""
|
||||||
task = self.model.get_task(idx)
|
task = self.model.get_task(idx)
|
||||||
self.view.show_task(task)
|
if task is None:
|
||||||
|
self.view.error("task not found!")
|
||||||
def _run_console_view(self):
|
else:
|
||||||
"""Super simple event loop."""
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
idx = self.view.select_task()
|
|
||||||
idx = int(idx)
|
|
||||||
except Exception as e:
|
|
||||||
self.view.error(e)
|
|
||||||
continue
|
|
||||||
task = self.model.get_task(idx)
|
|
||||||
self.view.show(task)
|
self.view.show(task)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
view = TkinterView
|
model = Model()
|
||||||
app = Controller(view)
|
controller = Controller(model)
|
||||||
app.run()
|
view = ConsoleView(controller)
|
||||||
|
controller.set_view(view)
|
||||||
|
view.mainloop()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Below you can see a `tkinter` class that acts as a drop in replacement for the `ConsoleView` class.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class TkinterView(tk.Tk):
|
||||||
|
def __init__(self, controller):
|
||||||
|
tk.Tk.__init__(self)
|
||||||
|
self.controller = controller
|
||||||
|
self.title("hello world")
|
||||||
|
self.geometry("500x400")
|
||||||
|
self.resizable(0, 0)
|
||||||
|
|
||||||
|
self.header = tk.Label()
|
||||||
|
self.header.grid(column=0, row=0, sticky=tk.W)
|
||||||
|
|
||||||
|
self.question = tk.Label(self, text="Which task do you want to see?")
|
||||||
|
self.question.grid(column=0, row=1, sticky=tk.W)
|
||||||
|
|
||||||
|
self.input = tk.Entry(self)
|
||||||
|
self.input.grid(column=1, row=1, sticky=tk.W)
|
||||||
|
|
||||||
|
self.button = tk.Button(self, text="lookup", command=self.clicked)
|
||||||
|
self.button.grid(column=0, row=2, sticky=tk.W)
|
||||||
|
|
||||||
|
self.output = tk.Label(self, text="...")
|
||||||
|
self.output.grid(column=1, row=2, sticky=tk.W)
|
||||||
|
|
||||||
|
def _is_entry_digit(self):
|
||||||
|
number = self.input.get()
|
||||||
|
if number.isdigit():
|
||||||
|
number = int(number)
|
||||||
|
return number
|
||||||
|
|
||||||
|
def clicked(self):
|
||||||
|
number = self._is_entry_digit()
|
||||||
|
if not number:
|
||||||
|
msg = "numbers please..."
|
||||||
|
else:
|
||||||
|
msg = self.controller.request_task_from_model(number)
|
||||||
|
|
||||||
|
def show_message(self, msg):
|
||||||
|
self.header.config(text=msg)
|
||||||
|
|
||||||
|
def show(self, task):
|
||||||
|
"""Displays the task to the console. This method is called from the
|
||||||
|
controller."""
|
||||||
|
self.output.config(text=task)
|
||||||
|
|
||||||
|
def error(self, msg):
|
||||||
|
"""Prints error messages coming from the controller."""
|
||||||
|
self.output.config(text=msg)
|
||||||
|
```
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
For a GUI only login generator an implementation without MVC could look a bit like this.
|
For a GUI only login generator an implementation without MVC could look a bit like this.
|
||||||
Note that the actual calculation is done inside the window itself.
|
Note that the actual calculation is done inside the window itself.
|
||||||
This is not a good idea because we should separate responsibilities into classes!
|
This is not a good idea because we should separate responsibilities into classes!
|
||||||
|
@ -964,10 +1021,16 @@ if __name__ == "__main__":
|
||||||
app.mainloop()
|
app.mainloop()
|
||||||
````
|
````
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
## Coding challenge - Login generator with GUI
|
## Coding challenge - Login generator with GUI
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
## Coding challenge - Trivial pursuit with GUI
|
## Coding challenge - Trivial pursuit with GUI
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
# WXpython
|
# WXpython
|
||||||
|
|
||||||
## wxpython helloworld
|
## wxpython helloworld
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Some links
|
||||||
|
|
||||||
|
* [MVC with tkinter](https://www.pythontutorial.net/tkinter/tkinter-mvc/)
|
||||||
|
* [principles of OOP](https://www.freecodecamp.org/news/solid-principles-explained-in-plain-english/)
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Program
|
||||||
|
|
||||||
|
| Day | Goal |
|
||||||
|
|-----|-----------------------------------------|
|
||||||
|
| 1 | coding challenge: temperature convertor |
|
||||||
|
| 2 | coding challenge: memento mori |
|
||||||
|
| 3 | coding challenge: guess the number |
|
||||||
|
| 4 | coding challenge: ROT13 |
|
||||||
|
| 5 | |
|
||||||
|
| 6 | coding challenge: task manager |
|
||||||
|
| 7 | useful scripting with pathlib |
|
||||||
|
| 8 | convert login manager to OOP |
|
||||||
|
| 9 | |
|
||||||
|
| 10 | |
|
||||||
|
| 11 | |
|
||||||
|
| 12 | coding challenge: hangman non-OOP/OOP |
|
||||||
|
| 13 | introduction to tkinter |
|
||||||
|
| 14 | |
|
||||||
|
| 15 | |
|
||||||
|
|
288
readme.md
|
@ -1,112 +1,186 @@
|
||||||
# Python course
|
# Program
|
||||||
|
|
||||||
This repository contains some notes and exercises for learning python3.
|
| Day | Goal |
|
||||||
|
|-----|-----------------------------------------|
|
||||||
|
| 1 | coding challenge: temperature convertor |
|
||||||
|
| 2 | coding challenge: memento mori |
|
||||||
|
| 3 | coding challenge: guess the number |
|
||||||
|
| 4 | coding challenge: ROT13 |
|
||||||
|
| 5 | |
|
||||||
|
| 6 | coding challenge: task manager |
|
||||||
|
| 7 | useful scripting with pathlib |
|
||||||
|
| 8 | convert login manager to OOP |
|
||||||
|
| 9 | |
|
||||||
|
| 10 | |
|
||||||
|
| 11 | |
|
||||||
|
| 12 | coding challenge: hangman non-OOP/OOP |
|
||||||
|
| 13 | introduction to tkinter |
|
||||||
|
| 14 | |
|
||||||
|
| 15 | |
|
||||||
|
|
||||||
## Initiation to programming
|
|
||||||
|
|
||||||
* Day 1
|
Learning python3
|
||||||
* What we'll learn
|
=================
|
||||||
* Concepts
|
|
||||||
* Syntax
|
* [What we'll learn](./learning_python3.md#what-well-learn)
|
||||||
* Tools
|
* [Concepts](./learning_python3.md#concepts)
|
||||||
* Writing code
|
* [Syntax](./learning_python3.md#syntax)
|
||||||
* Running code
|
* [Tools](./learning_python3.md#tools)
|
||||||
* The python3 shell
|
* [Writing code](./learning_python3.md#writing-code)
|
||||||
* Installing pycharm
|
* [Running code](./learning_python3.md#running-code)
|
||||||
* Your first project
|
* [The python3 shell](./learning_python3.md#the-python3-shell)
|
||||||
* c
|
* [Installing pycharm](./learning_python3.md#installing-pycharm)
|
||||||
* c
|
* [Virtual environments](./learning_python3.md#virtual-environments)
|
||||||
* c++
|
* [Your first project](./learning_python3.md#your-first-project)
|
||||||
* javascript
|
* [How to execute](./learning_python3.md#how-to-execute)
|
||||||
* How to execute
|
* [Simple printing](./learning_python3.md#simple-printing)
|
||||||
* Simple printing
|
* [Try it](./learning_python3.md#-try-it)
|
||||||
* 🏃 Try it
|
* [Try it](./learning_python3.md#-try-it-1)
|
||||||
* 🏃 Try it
|
* [String replacement](./learning_python3.md#string-replacement)
|
||||||
* String replacement
|
* [String formatting](./learning_python3.md#string-formatting)
|
||||||
* String formatting
|
* [Some links to read up](./learning_python3.md#some-links-to-read-up)
|
||||||
* Some links to read up
|
* [Taking input](./learning_python3.md#taking-input)
|
||||||
* Taking input
|
* [Some functions are blocking](./learning_python3.md#some-functions-are-blocking)
|
||||||
* Some functions are blocking
|
* [Functions can return something](./learning_python3.md#functions-can-return-something)
|
||||||
* Functions can return something
|
* [Try it](./learning_python3.md#-try-it-2)
|
||||||
* 🏃 Try it
|
* [Functions can take arguments](./learning_python3.md#functions-can-take-arguments)
|
||||||
* Functions can take arguments
|
* [Try it](./learning_python3.md#-try-it-3)
|
||||||
* 🏃 Try it
|
* [Taking input and evaluation](./learning_python3.md#taking-input-and-evaluation)
|
||||||
* Taking input and evaluation
|
* [Conditional logic](./learning_python3.md#conditional-logic)
|
||||||
* Conditional logic
|
* [Class string methods](./learning_python3.md#class-string-methods)
|
||||||
* Class string methods
|
* [Try it](./learning_python3.md#-try-it-4)
|
||||||
* Some links to read up on
|
* [Some links to read up on](./learning_python3.md#some-links-to-read-up-on)
|
||||||
* Coding challenge - Celsius to Fahrenheit converter
|
* [Coding challenge - Currency converter](./learning_python3.md#coding-challenge---currency-converter)
|
||||||
* Day 2
|
* [Coding challenge - Celsius to Fahrenheit converter](./learning_python3.md#coding-challenge---celsius-to-fahrenheit-converter)
|
||||||
* A text based adventure game
|
* [Some links to read up on](./learning_python3.md#some-links-to-read-up-on-1)
|
||||||
* Creating your own functions
|
* [A text based adventure game](./learning_python3.md#a-text-based-adventure-game)
|
||||||
* Functions that *do* something
|
* [Creating your own functions](./learning_python3.md#creating-your-own-functions)
|
||||||
* Variable scope
|
* [Functions that <em>do</em> something](./learning_python3.md#functions-that-do-something)
|
||||||
* Functions that *return* something
|
* [Variable scope](./learning_python3.md#variable-scope)
|
||||||
* 🏃 Try it
|
* [Functions that <em>return</em> something](./learning_python3.md#functions-that-return-something)
|
||||||
* Some links to read up on
|
* [Try it](./learning_python3.md#-try-it-5)
|
||||||
* Coding challenge - Pretty Print
|
* [Some links to read up on](./learning_python3.md#some-links-to-read-up-on-2)
|
||||||
* Using the standard library
|
* [Coding challenge - Pretty Print](./learning_python3.md#coding-challenge---pretty-print)
|
||||||
* Coding challenge - Memento Mori calculator
|
* [Using the standard library](./learning_python3.md#using-the-standard-library)
|
||||||
* Day 3
|
* [Coding challenge - Memento Mori calculator](./learning_python3.md#coding-challenge---memento-mori-calculator)
|
||||||
* Writing your first library
|
* [Writing your first library](./learning_python3.md#writing-your-first-library)
|
||||||
* 🏃 Try it
|
* [Try it](./learning_python3.md#-try-it-6)
|
||||||
* How do we write libraries?
|
* [How do we write libraries?](./learning_python3.md#how-do-we-write-libraries)
|
||||||
* What is `__name__ == "__main__"`?
|
* [What is __name__ == "__main__"?](./learning_python3.md#what-is-__name__--__main__)
|
||||||
* Anatomy of a program
|
* [Anatomy of a program](./learning_python3.md#anatomy-of-a-program)
|
||||||
* 🏃 Try it
|
* [Try it](./learning_python3.md#-try-it-7)
|
||||||
* While loop
|
* [While loop](./learning_python3.md#while-loop)
|
||||||
* 🏃 Try it
|
* [Try it](./learning_python3.md#-try-it-8)
|
||||||
* Coding challenge - Guess the number
|
* [Coding challenge - Guess the number](./learning_python3.md#coding-challenge---guess-the-number)
|
||||||
* 🏃 Try it
|
* [Try it](./learning_python3.md#-try-it-9)
|
||||||
* Day 4
|
* [Logical Operators](./learning_python3.md#logical-operators)
|
||||||
* Lists
|
* [Lists](./learning_python3.md#lists)
|
||||||
* Creating lists
|
* [Creating lists](./learning_python3.md#creating-lists)
|
||||||
* List methods
|
* [List methods](./learning_python3.md#list-methods)
|
||||||
* 🏃 Try it
|
* [Try it](./learning_python3.md#-try-it-10)
|
||||||
* Picking elements and slicing lists
|
* [Picking elements and slicing lists](./learning_python3.md#picking-elements-and-slicing-lists)
|
||||||
* 🏃 Try it
|
* [Try it](./learning_python3.md#-try-it-11)
|
||||||
* For loop
|
* [For loop](./learning_python3.md#for-loop)
|
||||||
* Coding challenge - Cheerleader chant
|
* [Coding challenge - Cheerleader chant](./learning_python3.md#coding-challenge---cheerleader-chant)
|
||||||
* Coding challenge - ROT13
|
* [Coding challenge - ROT13](./learning_python3.md#coding-challenge---rot13)
|
||||||
* 🏃 Try it
|
* [Try it](./learning_python3.md#-try-it-12)
|
||||||
* List comprehension
|
* [Coding challenge - Christmas Tree](./learning_python3.md#coding-challenge---christmas-tree)
|
||||||
* Day 5
|
* [List comprehension](./learning_python3.md#list-comprehension)
|
||||||
* Handling files
|
* [Handling files](./learning_python3.md#handling-files)
|
||||||
* Reading from a file
|
* [Reading from a file](./learning_python3.md#reading-from-a-file)
|
||||||
* In-line way
|
* [In-line way](./learning_python3.md#in-line-way)
|
||||||
* Pythonic way
|
* [Pythonic way](./learning_python3.md#pythonic-way)
|
||||||
* Writing to a file
|
* [Writing to a file](./learning_python3.md#writing-to-a-file)
|
||||||
* Coding challenge - Login generator
|
* [Coding challenge - Login generator](./learning_python3.md#coding-challenge---login-generator)
|
||||||
* Dictionaries as data containers
|
* [Dictionaries as data containers](./learning_python3.md#dictionaries-as-data-containers)
|
||||||
* Coding challenge - Task manager
|
* [Two dimensional lists](./learning_python3.md#two-dimensional-lists)
|
||||||
* Text based databases
|
* [Dictionaries](./learning_python3.md#dictionaries)
|
||||||
* Day 6
|
* [Try it](./learning_python3.md#-try-it-13)
|
||||||
* Now for some useful scripting
|
* [Coding challenge - Task manager](./learning_python3.md#coding-challenge---task-manager)
|
||||||
* Day 7
|
* [CSV based task manager](./learning_python3.md#csv-based-task-manager)
|
||||||
* Creating our own objects
|
* [Text based databases](./learning_python3.md#text-based-databases)
|
||||||
* First some *abstract* examples
|
* [Try it](./learning_python3.md#-try-it-14)
|
||||||
* 🏃 Try it
|
* [Now for some useful scripting](./learning_python3.md#now-for-some-useful-scripting)
|
||||||
* Class inheritance
|
* [Creating our own objects](./learning_python3.md#creating-our-own-objects)
|
||||||
* 🏃 Try it
|
* [First some <em>abstract</em> examples](./learning_python3.md#first-some-abstract-examples)
|
||||||
* A *practical* example
|
* [Try it](./learning_python3.md#-try-it-15)
|
||||||
* Now some *practical* improvements
|
* [Magic methods](./learning_python3.md#magic-methods)
|
||||||
* Improve the login generator
|
* [Class inheritance](./learning_python3.md#class-inheritance)
|
||||||
* Improve the task manager
|
* [Try it](./learning_python3.md#-try-it-16)
|
||||||
* Day 8
|
* [Coding challenge - Chalet floor](./learning_python3.md#coding-challenge---chalet-floor)
|
||||||
* Infinite programs
|
* [Now some <em>practical</em> improvements](./learning_python3.md#now-some-practical-improvements)
|
||||||
* Logic breakdown of a simple game
|
* [Improve the login generator](./learning_python3.md#improve-the-login-generator)
|
||||||
* Trivial pursuit multiple choice game
|
* [Improve the task manager](./learning_python3.md#improve-the-task-manager)
|
||||||
* Introduction to the `requests` library
|
* [Infinite programs](./learning_python3.md#infinite-programs)
|
||||||
* Threading
|
* [Logic breakdown of a simple game](./learning_python3.md#logic-breakdown-of-a-simple-game)
|
||||||
* Day 9
|
* [A non object orientated solution](./learning_python3.md#a-non-object-orientated-solution)
|
||||||
* GUI programming
|
* [An object orientated solution](./learning_python3.md#an-object-orientated-solution)
|
||||||
* Tkinter helloworld
|
* [Trivial pursuit multiple choice game](./learning_python3.md#trivial-pursuit-multiple-choice-game)
|
||||||
* Tkinter guess the number
|
* [Introduction to the requests library](./learning_python3.md#introduction-to-the-requests-library)
|
||||||
* MVC design pattern
|
* [Threading](./learning_python3.md#threading)
|
||||||
* Day 10-12
|
|
||||||
* Coding challenge - Login generator with GUI
|
|
||||||
* Coding challenge - Trivial pursuit with GUI
|
|
||||||
|
Introduction to solid
|
||||||
|
=================
|
||||||
|
|
||||||
|
* [Object-Oriented class design](./introduction_to_solid.md#object-oriented-class-design)
|
||||||
|
* [SOLID](./introduction_to_solid.md#solid)
|
||||||
|
* [Single-Responsibility](./introduction_to_solid.md#single-responsibility)
|
||||||
|
* [Open-Closed Principle](./introduction_to_solid.md#open-closed-principle)
|
||||||
|
* [Liskov Substitution Principle](./introduction_to_solid.md#liskov-substitution-principle)
|
||||||
|
* [Interface Segregation Principle](./introduction_to_solid.md#interface-segregation-principle)
|
||||||
|
* [Dependency Inversion Principle](./introduction_to_solid.md#dependency-inversion-principle)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Learning python3 gui
|
||||||
|
=================
|
||||||
|
|
||||||
|
* [tkinter](./learning_python3_gui.md#tkinter)
|
||||||
|
* [Tkinter helloworld](./learning_python3_gui.md#tkinter-helloworld)
|
||||||
|
* [Adding widgets](./learning_python3_gui.md#adding-widgets)
|
||||||
|
* [Try it](./learning_python3_gui.md#-try-it)
|
||||||
|
* [Coding challenge - Guess the number](./learning_python3_gui.md#coding-challenge---guess-the-number)
|
||||||
|
* [MVC design pattern](./learning_python3_gui.md#mvc-design-pattern)
|
||||||
|
* [Coding challenge - Login generator with GUI](./learning_python3_gui.md#coding-challenge---login-generator-with-gui)
|
||||||
|
* [Coding challenge - Trivial pursuit with GUI](./learning_python3_gui.md#coding-challenge---trivial-pursuit-with-gui)
|
||||||
|
* [WXpython](./learning_python3_gui.md#wxpython)
|
||||||
|
* [wxpython helloworld](./learning_python3_gui.md#wxpython-helloworld)
|
||||||
|
* [wxpython guess the number](./learning_python3_gui.md#wxpython-guess-the-number)
|
||||||
|
* [MVC design pattern](./learning_python3_gui.md#mvc-design-pattern-1)
|
||||||
|
* [Coding challenge - Login generator with GUI](./learning_python3_gui.md#coding-challenge---login-generator-with-gui-1)
|
||||||
|
* [Coding challenge - Trivial pursuit with GUI](./learning_python3_gui.md#coding-challenge---trivial-pursuit-with-gui-1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Learning git
|
||||||
|
=================
|
||||||
|
|
||||||
|
* [About](./learning_git.md#about)
|
||||||
|
* [Git via bash](./learning_git.md#git-via-bash)
|
||||||
|
* [Initialing a git repo](./learning_git.md#initialing-a-git-repo)
|
||||||
|
* [What's in this repo](./learning_git.md#whats-in-this-repo)
|
||||||
|
* [Adding and tracking content](./learning_git.md#adding-and-tracking-content)
|
||||||
|
* [The main workflow](./learning_git.md#the-main-workflow)
|
||||||
|
* [Git via Atom](./learning_git.md#git-via-atom)
|
||||||
|
* [Git via Pycharm](./learning_git.md#git-via-pycharm)
|
||||||
|
* [Starting a version controlled project](./learning_git.md#starting-a-version-controlled-project)
|
||||||
|
* [Creating an online repository](./learning_git.md#creating-an-online-repository)
|
||||||
|
* [Adding some changes to our local code](./learning_git.md#adding-some-changes-to-our-local-code)
|
||||||
|
* [Cloning the remote project into a new project](./learning_git.md#cloning-the-remote-project-into-a-new-project)
|
||||||
|
* [Updating the original project](./learning_git.md#updating-the-original-project)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
What is next
|
||||||
|
=================
|
||||||
|
|
||||||
|
* [Some random recommendations](./what_is_next.md#some-random-recommendations)
|
||||||
|
* [IDE](./what_is_next.md#ide)
|
||||||
|
* [Syntax](./what_is_next.md#syntax)
|
||||||
|
* [Concepts](./what_is_next.md#concepts)
|
||||||
|
* [Books](./what_is_next.md#books)
|
||||||
|
* [Linux](./what_is_next.md#linux)
|
||||||
|
|
||||||
## Linux system administrator
|
|
||||||
|
|
||||||
**TODO**
|
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
# Some random recommendations
|
||||||
|
|
||||||
|
After our twenty days of python together you should have a solid understanding of the world of programming.
|
||||||
|
The foundation of all essential concepts should be clear enough to understand code when it is in front of you.
|
||||||
|
A blank slate could still pose a challenge but for that, here are some links and recommendations.
|
||||||
|
|
||||||
|
## IDE
|
||||||
|
|
||||||
|
Maybe try out some other IDE to see if you like the workflow or layout better.
|
||||||
|
I'm a big fan of [vim](https://en.wikipedia.org/wiki/Vim_(text_editor)), especially with some good [plugins](https://gitea.86thumbs.net/waldek/linux_course_doc/src/branch/master/modules/qualifying/learning_vim_configuration.md).
|
||||||
|
It's not an *easy* editor to learn but the payoff is pretty great.
|
||||||
|
For the more *normal* people I would recommend having a look at the following editors, in no particular order.
|
||||||
|
|
||||||
|
* [atom](https://atom.io/)
|
||||||
|
* [vscode](https://code.visualstudio.com/)
|
||||||
|
* [brackets](https://brackets.io/)
|
||||||
|
* [spyder](https://www.spyder-ide.org/) for a more scientific approach
|
||||||
|
|
||||||
|
Don't hop around too much though.
|
||||||
|
If you're a bit bored with pycharm it could be refreshing to *see* your code through a different window.
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
|
Start paying attention to the style guides that pop up in your IDE and follow up on them by reading the actual rules.
|
||||||
|
It can be good way to discover some do's and don't and help you to make your code more readable.
|
||||||
|
I would also recommend you start browsing online for some coding projects in a field of your interests.
|
||||||
|
The bigger the project, the higher the chance it follows a specific style.
|
||||||
|
By reading and trying to understand their code, you'll start to build a better feel how to annotate, structure and make your code more readable.
|
||||||
|
As this is a *very* subjective topic I can only point you to projects I like.
|
||||||
|
|
||||||
|
* [python-language-server](https://github.com/palantir/python-language-server)
|
||||||
|
* [python-osc](https://github.com/attwad/python-osc)
|
||||||
|
* [urwid](https://urwid.org/index.html)
|
||||||
|
* [natural language toolkit](https://www.nltk.org/)
|
||||||
|
|
||||||
|
## Concepts
|
||||||
|
|
||||||
|
We touched on *most* of the elementary concepts but we did go over them quite quickly.
|
||||||
|
Take your time to review all base concepts with small exercises and try to chain them together into bigger projects.
|
||||||
|
Some python specific *new* concepts I would highly advise you to look into are the following.
|
||||||
|
|
||||||
|
* [decorators](https://realpython.com/primer-on-python-decorators/)
|
||||||
|
* [getters and setters](https://stackoverflow.com/questions/2627002/whats-the-pythonic-way-to-use-getters-and-setters)
|
||||||
|
* [concurrency](https://realpython.com/python-concurrency/)
|
||||||
|
* [threading vs async vs multiprocessing](https://leimao.github.io/blog/Python-Concurrency-High-Level/)
|
||||||
|
* [design patterns](https://python-patterns.guide/)
|
||||||
|
* [memory management in python](https://realpython.com/python-memory-management/)
|
||||||
|
* [virtual environments](https://docs.python.org/3/tutorial/venv.html)
|
||||||
|
|
||||||
|
If you're interested in creating web applications I would start out with [bottle](https://bottlepy.org/docs/dev/), work your way up to [flask](https://www.fullstackpython.com/flask.html) and maybe move over to [django](https://www.djangoproject.com/).
|
||||||
|
You'll definitely need to learn [SQL](https://en.wikipedia.org/wiki/SQL) at some point but you can make your life easier by using [sqlalchemy](https://www.sqlalchemy.org/).
|
||||||
|
|
||||||
|
If you want to dive deep into data science you'll need get comfortable with [numpy](https://numpy.org/), [pandas](https://pandas.pydata.org/) and [matplotlib](https://matplotlib.org/).
|
||||||
|
The easiest way to get comfortable with all of those is probably [jupyter notebook](https://jupyter-notebook.readthedocs.io/en/stable/index.html) which is an IDE that you use in your browser.
|
||||||
|
It's quite different from the pycharm you're used to but it's a very good tool to do data analysis.
|
||||||
|
|
||||||
|
If robotics is your thing you might want to give [micropython](https://micropython.org/) a go.
|
||||||
|
I've never used it myself but I've heard good things about it.
|
||||||
|
|
||||||
|
## Books
|
||||||
|
|
||||||
|
These are some books I've actually read and enjoyed.
|
||||||
|
|
||||||
|
* [mastering python design patterns](https://www.amazon.de/-/en/Kamon-Ayeva/dp/1788837487/ref=sr_1_2?keywords=python+design+muster&qid=1651784267&sprefix=python+des%2Caps%2C82&sr=8-2)
|
||||||
|
* [fluent python](https://www.amazon.de/-/en/Luciano-Ramalho-dp-1492056359/dp/1492056359/ref=dp_ob_title_bk)
|
||||||
|
* [design patterns](https://www.amazon.de/-/en/Erich-Gamma/dp/9332555400/ref=sr_1_9?keywords=gang+of+four+design+muster&qid=1651784413&sprefix=gang+of+%2Caps%2C68&sr=8-9)
|
||||||
|
* [learn python the hard way](https://learnpythonthehardway.org/python3/)
|
||||||
|
* [automate the boring stuff](https://automatetheboringstuff.com/)
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
|
||||||
|
If you enjoyed the experience of the computers at the school you should give [linux](https://en.wikipedia.org/wiki/Linux) a go at home!
|
||||||
|
You used a [debian](https://www.debian.org/) machine with [GNOME](https://www.gnome.org/) as a graphical interface.
|
||||||
|
If you're really motivated you could read through my [introduction to linux](https://gitea.86thumbs.net/waldek/linux_short) course.
|
||||||
|
It's a work in progress and all feedback is welcome.
|