Well, I think I will come back to flask later on. I thought my python knowledge was okay but the flask code was quite hard to follow. I have no idea what decorators are since we skipped them in class, etc.
Decorators are pretty simple if you have some basis in math... it's just function composition.
Quick'n dirty explanation...
For example, suppose you have a function
and another function
When you write
Code:
def g(foo) :
....
...
@g
def f( x ) :
...
You basically write
Code:
def temporary_f( x ) :
... (code of f) ...
f = g( temporary_f )
so f actually means (g o _f) where _f is the function you've defined when you wrote def f( x ) : ...
It mostly make sense when g returns a function...
It's easier with an example. You probably know the Fibonacci function:
Code:
def fibo(n) :
if n <= 0 :
return 0
if n == 1 :
return 1
return fibo(n-2) + fibo(n-1)
You know it's slow (try fibo(40) for example)
To understand why it's slow, define (before fibo)
Code:
def log(foo) :
def bar(arg) :
print("Call with argument", arg)
return foo(arg)
return bar
and add the @log decorator on the line before fibo :
Try fibo(10)... With only the decorator, you get all the informations on the calls (and you can decorate any fuction that takes a single argument this way)
Now, you want to speed up the function... Let's use memoization. Add another function before fibo
Code:
def memoize(foo) :
mem = dict()
def bar(arg) :
try :
return mem[arg]
except KeyError :
mem[arg] = foo(arg)
return mem[arg]
return bar
Now, add a second decorator:
Code:
@log
@memoize
def fibo(n) :
...
Now, try again fibo(40) or even fibo(100) and enjoy the magic...
Of course, it can be tricky to write decorator functions, especially if you're not into functional programming. But once you get the grip, it's terribly powerful.
That being said, there's ONE awful thing with Python decorators: it messes with the help string (you get the help string and the arguments of the decorator, not of the function). It's really, really bad for users. There's some awful tricks to preserve part of those data (there's a whole module for it) but it's far from perfect.
As I said, decorators usually return a function that call their argument (and do something else). But you can be nasty:
Code:
def blop(foo) :
return False
@blop
def bar(x) :
return True
Basically, in the above case, bar isn't even a function anymore, it's now the boolean False (the result of blop).
There's plently of functions in Python modules that are designed to act as decorators...
But yes, it worth the time studying a bit classes, special methods, decorators, etc. Feel free to ask for help here if you're stuck.
I was taught to use getters and setters in python but was told online that is not python like - what would I do instead then?
Directly use the attributes?
Who told you to use setters/getters? Most of the time, it's indeed unpythonic, and you won't get a lot of safety with those (since there's nothing private in Python).
If you need to do some value check, as Eridani said, @property is useful to create various kind of setters/getters, but you need a good reason to do this....
And please don't use __XXXXX to make something "private", even if you see it use elsewhere. There's no access control in Python like in other languages, the double leading underscore is used for name mangling, not to make objects private.
_XXXXX is sufficient to say to the user "You shouldn't use it". As some says, "we're all consenting adults here", and if people want to shot at their own feet, that's their problem, you did your job, no need to go extra mile and misuse something just to add a "protection" layer that actually won't prevent them to do something nasty if they want.