Why are decorators useful? [closed] - python

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
So I read this page about decorators, but I still don't understand when decorators are useful.
Consider a piece of code defining a function f, and then calling it multiple times. For some reason we want f to do some extra work. So we have 2 ways to do it:
define a new function g which calls f, and does the extra work needed. Then in the main code, replace all calls to f by calls to g
define a decorator g, and edit the code to add #g before calls to f
In the end, they both achieve the same result and the advantage of 2) over 1) is not obvious to me. What am i missing?

Suppose you have a lot of functions f1, f2, f3, ... and you want a regular way to make the same change to all of them to do the same extra work.
That's what you're missing and it's why decorators are useful. That is to say, functions that take a function and return a modified version of it.
The decorator # syntax is "just" for convenience. It lets you decorate the function as it is defined:
#decorated
def foo():
# several lines
instead of somewhere after the function definition:
def foo():
# several lines
foo = decorated(foo)
In fact of course the latter code is pretty horrible, since it means that by looking at the first definition of foo in the source, you don't see the same foo that users will call. So without the syntax, decorators wouldn't be so valuable because you'd pretty much always end up using different names for the decorated and undecorated functions.

Related

Return Order of Magic Methods [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 months ago.
Improve this question
I've been programming for a couple of months now and now I actually have a question... So, if I am not completely wrong, there is just one return per call, right? Doesn't matter if its None or a certain return but there cant be like 2 return statements in one call? So lets move on to the magic methods. In which order do they get processed?
def __str__(self):
return f"{self.first} {self.second}"
def __repr__(self):
return "{} {}".format(self.first, self.second)
Always the last one? Or are there differences between certain magic methods in terms of ranking systems? Or do they even get both processed but just one becomes returned=?
There is no return order. Each magic method is a hook called by the Python implementation in order to implement specific protocols.
x.__str__ defines what str(x) means.
x.__repr__ defines what repr(x) means.
And that's it. Well, almost.
You also need to know when str or repr might be used aside from explicit calls. Some examples:
print calls str on each of its arguments to ensure that it has str values to write to the appropriate file.
The interactive interpreter calls repr on the value of each expression it evaluates.
In addition, object.__str__ falls back to use __repr__, I think by invoking x.__repr__() directly (rather than calling repr(x), which would then call x.__repr__()). So str(x) can indirectly be implemented using a __repr__ method if no class involved defined a __str__ method.
Other groups of magic methods might cooperate in order to define a more complicated protocol. For example,
x += y
could involve several options, tried in order:
x = x.__iadd__(y), if x.__iadd__ is defined
x = x.__add__(y), if x.__add__ is defined
x = y.__radd__(x), if x.__add__ is not defined or x.__add__(y) returned NonImplemented.

Why is "wrapper" is better name for a decorator than "adder"? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
A bare-bones example of a decorator is:
def strong(func):
def wrapper():
return '<strong>' + func() + '</strong>'
return wrapper
#strong
def greet():
return 'Hello!'
wrapper is an entitled name for the 'inside first-order-function' inside the Higher-Order function strong.
My question is that the word wrapper has no real meaning except to confuse newbie. Why not use 'adder', because it can be discerned intuitively?
Decorator pattern - Wikipedia
In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class.[1]
The keyword in Wikipedia's explanation is 'added'.
And in Cambridge English Dictionary:
to add something to an object or place, especially in order to make it more attractive:
The keyword is also 'add'.
So why is wrapper better than 'adder'?
When you use a decorator, you've wrapped your original code in another function, making the original function invisible. To continue your example,
def strong(func):
def wrapper():
return '<strong>' + func() + '</strong>'
return wrapper
#strong
def greet():
return 'Hello!'
def weak_greet():
return 'hi'
print(greet)
print(weak_greet)
If you run this, you get the following output.
<function strong.<locals>.wrapper at 0x000000000129A268>
<function weak_great at 0x000000000129A2F0>
When you used the decorator, you took your function, created a new function that wrapped code around your old function and returned that new, anonymous, function.
You can see some unpleasant effects if you try to pickle it.
if you do pickle.dumps(weak_greet), you get b'\x80\x03c__main__\nweak_great\nq\x00.'. but if you try to pickle.dumps(greet), you get AttributeError: Can't pickle local object 'strong.<locals>.wrapper'. (dealing with decorated classes and functions that must be pickled is one of the circles of hell I don't wish to revisit any time soon).
You are not adding to your function. You are wrapping your original function in a shiny new function. That new function says, "There's something I'm hiding in here and I won't tell you what it is (functools.wraps can sometimes help with this, as it would in your case). But, when you give me input, I'll alter it like so (or not at all), pass it to my secret function, (possibly) alter the output and give you that. Your original function is inaccessible (hence pickle's confusion).
NOTE: You can re-create the look of your original function by further wrapping your wrapper with #functools.wraps(original_function), which does not affect output, but wraps everything in a box to make it look exactly like the original function. so,
from functools import wraps
def strong(func):
#wraps(func)
def wrapper():
return '<strong>' + func() + '</strong>'
return wrapper
would now look like your original function and be pickle-able. It would be like wrapping a surprise present, and then wrapping the present again with wrapping paper that told you (in great detail) what the surprise was.

Python Style Guide: Should print() commands be in or out of defs? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
Which is more stylistically accepted to do?
This:
def example_function(stuff):
thing = stuff
print(thing)
example_function('words')
Or:
def example_function(stuff):
thing = stuff
return thing
print(example_function('words'))
I'm still figuring out my way through Python, so any help would be greatly appreciated!
Consider how the function will be used. If it includes the print, you can never call the function without it producing output (ignoring monkey patching and the like). If it does not include the print, you can always print its return value explicitly if you decide you want to output the value.
In other words, lean towards printing a return value unless you have a very good reason to print from inside the function. Printing to standard output isn't actually as common as most beginner programs would leave you to believe. Most of the code one writes is intended to be used by other code, rather than communicating directly with a human.
You could take a clue from the __str__ and __repr__ methods of objects. They return a string representation, allowing you to do things like
print(dict(a=1))
print([1,2,3,4])
In general returning a string gives you more flexibility.
But while debugging code, I often include diagnostic print statements within a function.
The argparse module has:
parser.print_help()
parser.format_help()
methods. The print calls the format, and takes a file=None parameter. The default action is to write to stdout (or stderr) but the user can redirect it.

Assign lambda to an expression to make a recursion? (PEP8) [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I know that PEP8 dictates to not assign lambda to an expression because it misses the entire point of a lambda function.
But what about a recursive lambda function? I've found that in many cases, it's really simple, clean and efficient to make a recursion with lambda assigning it to an expression instead of defining a function. And pep8 doesn't mention recursive lambda.
For example, let's compare a function that returns the greatest common divisor between two numbers:
def gcd(a,b):
if b == 0:
return a
return gcd(b, a % b)
vs
gcd = lambda a, b: a if b == 0 else gcd(b, a % b)
So, what should I do?
You have "cheated" a bit in your question, since the regular function could also be rewritten like this:
def gcd(a,b):
return a if b == 0 else gcd(b, a % b)
Almost as short as the lambda version, and even this can be further squeezed into a single line, but at the expense of readability.
The lambda syntax is generally used for simple anonymous functions that are normally passed as arguments to other functions. Assigning a lambda function to a variable doesn't make much sense, it is just another way of declaring a named function, but is less readable and more limited (you can't use statements in it).
A lot of thought has been put into PEP8 and the recommendations in it are there for a reason, thus I would not recommend deviating from it, unless you have a very good reason for doing so.
Go with the normal function definition. There's absolutely no benefit of using lambda over def, and normal function definition is (for most people) much more readable. With lambda, you gain nothing, but you often lose readability.
I would recommend you to read this answer. Recursion doesn't change anything. In fact, in my opinion, it favours normal def even more.
If you assign a lambda to a variable, you won't be able to pass it as an argument nor return it in the same line, which is the exact purpose of lambda.

Hand over global variables to methods in python? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
This is more a question about good programming style. I usually work with Java, and now I do some working with Python. In Python, there is no need to hand over global variables if you only want to read from them. On the other hand, I think the Java syntax is more helpful in his regard. You have to hand over required variables, and so you can see what variables are used by what method, which I am sure is helpful for somebody who is reading your code.
Now do you hand over variables in Python although you could already access them because they're global? What is the good 'pythonic' way?
Thanks,
ZerO
def foo(a):
a = 2
foo(1)
1 is 'handed over' to method foo().
Yes, this
def foo(a):
a = 2
foo(1)
is preferred over this
a = 1
def foo():
a = 2
foo()
Imagine you have 3 methods that all do something to a list.
a_list_name = []
def a()
a_list_name.something
def b()
a_list_name.something
def c()
a_list_name.something
a()
b()
c()
If you define the list 'global' you will have to refer that exact list in each method. If you for some reason want to change the list name you now have to edit all 3 methods.
However if you pass in the list through a parameter you only have to edit the method calls and the method code can remain untouched. Like this
def a(l)
l.something
def b(l)
l.something
def c(l)
l.something
my_list = []
a(my_list)
b(my_list)
c(my_list)
This makes your code more modular, and most of all it makes your code (methods) testable because they don't depend on some variable that is defined somewhere else

Categories

Resources