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 4 years ago.
Improve this question
Many try/except/finally-clauses not only "uglify" my code, but i find myself often using identical exception-handling for similar tasks. So i was considering reducing redundancy by "outsourcing" them to a ... decorator.
Because i was sure not to be the 1st one to come to this conclusion, I googled and found this - imho - ingenious recipe which added the possibility to handle more than one exception.
But i was surprised why this doesn't seem to be a wide known and used practice per se, so i was wondering if there is maybe an aspect i wasn't considering?
Is it bogus to use the decorator pattern for exception-handling or did i just miss it the whole time? Please enlighten me! What are the pitfalls?
Is there maybe even a package/module out there which supports the creation of such exception-handling in a reasonable way?
The biggest reason to keep the try/except/finally blocks in the code itself is that error recovery is usually an integral part of the function.
For example, if we had our own int() function:
def MyInt(text):
return int(text)
What should we do if text cannot be converted? Return 0? Return None?
If you have many simple cases then I can see a simple decorator being useful, but I think the recipe you linked to tries to do too much: it allows a different function to be activated for each possible exception--in cases such as those (several different exceptions, several different code paths) I would recommend a dedicated wrapper function.
Here's my take on a simple decorator approach:
class ConvertExceptions(object):
func = None
def __init__(self, exceptions, replacement=None):
self.exceptions = exceptions
self.replacement = replacement
def __call__(self, *args, **kwargs):
if self.func is None:
self.func = args[0]
return self
try:
return self.func(*args, **kwargs)
except self.exceptions:
return self.replacement
and sample usage:
#ConvertExceptions(ValueError, 0)
def my_int(value):
return int(value)
print my_int('34') # prints 34
print my_int('one') # prints 0
Basically, the drawback is that you no longer get to decide how to handle the exception in the calling context (by just letting the exception propagate). In some cases this may result in a lack of separation of responsibility.
Decorator in Python is not the same as the Decorator pattern, thought there is some similarity. It is not completely clear waht you mean here, but I think you mean the one from Python (thus, it is better not to use the word pattern)
Decorators from Python are not that useful for exception handling, because you would need to pass some context to the decorator. That is, you would either pass a global context, or hide function definitions within some outer context, which requires, I would say, LISP-like way of thinking.
Instead of decorators you can use contextmanagers. And I do use them for that purpose.
Related
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.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 months ago.
Improve this question
In (some) python libraries, when i look up the code, i see a bunch of functions or class methods which are written like this:
def funcName():
pass
I just want to know how those functions DO stuff even though they only have pass which means that the function should do nothing.
For user-defined functions, pass means doing nothing, but for some library functions (including third-party libraries), they usually mean that their logic is not written in pure Python code, such as NumPy and Python standard library, in order to pursue efficient operation, most functions are written in C language, and provides the corresponding Python interface.
More detailed answer
Functions in python syntactically can't be empty. That's why you need to populate them, usually with pass
Sometimes, functions are declared, but purposely left empty. Then, they can be used in the default implementations, but possibly overridden by classes extending (inheriting) the library class.
Those functions/methods with just the pass statement do nothing in particular. pass is usually a placeholder for code that will be written later.
You can also find the pass statement in classes that define custom exceptions, for instance:
class MyException(Exception):
pass
Usually these are place holder methods in a (possibly abstract) base class that define a template for derived classes.
pass does nothing. It's a filler to let the code run before you implement something. The libraries are probably using pass to:
Leave blank code to finish later
Create a minimal class:
Imply that a section of code does nothing
Loop forever (and do nothing)
So to your question about libraries, they probably do nothing. pass on its own is almost as good as a blank line, but can be mixed with functional statements to achieve a working module. But the function in your question does nothing at all.
Say I wanted to keep a function f in my file, and come back to it later. I could use pass to avoid IndentationError:
>>> def f():
... pass
...
>>> f()
>>>
As without pass, I'd have:
>>> def f():
...
File "<stdin>", line 2
^
IndentationError: expected an indented block after function definition on line 1
>>>
This is also explained in the offical docs:
The pass statement does nothing.
It can be used when a statement is required syntactically but the program requires no action. For example:
>>> while True:
... pass # Busy-wait for keyboard interrupt (Ctrl+C)
...
Python pass is an empty statement to maintain the integrity of the program structure. Pass does not do anything and is generally used as a placeholder statement. Nothing happens when the pass is executed. It results in no operation.
Suppose we have a loop or a function that is not implemented yet, but we want to implement it in the future. They cannot have an empty body. The interpreter would give an error. So, we use the pass statement to construct a body that does nothing.
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 1 year ago.
Improve this question
In both examples, class.method() returns a list.
Example A:
if class.method():
for i in class.method():
# do stuff
Example B
list = class.method()
if list:
for i in list:
# do stuff
Which is better? It would seem to me that in some languages (but I don't know which), example A would result in class.method() being needlessly evaluated twice, and example B would be best practice. However, perhaps other languages (again not knowing which) might retain the output of a method in memory in case that method is called again, therefore avoiding having to do the same evaluation twice and resulting in little difference between examples A and B. Is this so? If so, can you give examples of a language for each case? And the real reason for the question: which is best practice in Python?
Unless your Python interpreter has JIT capabilities, the method will be evaluated every time you call it.
And even when the JIT compilation is possible, methods have to be proven by the compiler / interpreter that they do not have any side effects, that is they are deterministic.
For example, consider a method that pulls data from a database or a method that contains a call to a random number generator:
import random
def method():
return random.uniform(0.0, 1.0)
Output of such a method cannot be saved in memory because the second time you call it, it may change.
On the other hand, getter methods that accumulate data are a great example of a deterministic method, given that they do not call a non-deterministic method in their body.
from dataclasses import dataclass
#dataclass
class Example:
a : list
b : list
def method(self):
return self.a + self.b
In practice, you are better of to not assume anything from the compiler / interpreter and do these small, easy to do optimizations yourself. You also have to consider that your code can be run on multiple platforms, which further complicates things.
So I would recommend you to call the method only once and save its output in a temporary variable:
result = class.method()
if result :
for i in result:
# do stuff
And given that it's Python, I recommend to ask for forgiveness with the try keyword if most of the time you run the method, its output is not None:
result = class.method()
try:
for i in result:
# do stuff
except TypeError:
pass
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.
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 6 years ago.
Improve this question
What is the pythonic way to tell the caller of a function what values a given parameter supports?
He is an example for PyQt (for GUI). Say I have a checkbox,
class checkbox(object):
....
def setCheckState(self, value):
....
Here, setCheckState() should only expect checked or unchecked.
PyQt uses a built-in enumeration (i.e. Qt.Checked or Qt.Unchecked), but this is awful. I am constantly in the documentation looking for the enum for the object I am working with.
Obviously PyQt is written in an unpythonic C++ sytle. How should this or a similar problem be handled in Python? According to PEP 435, enums seem to be a recent addition to the language and for very specific applications, so I would assume there is/was a better way to handle this?
I want to make the code I write easy to use when my functions require specific parameter values--almost like a combobox for functions.
The One Obvious Way is function annotations.
class CheckBox(enum.Enum):
Off = 0
On = 1
def setCheckState(self, value: CheckBox):
...
This says quite clearly that value should be an instance of CheckBox. Having Enum just makes that a bit easier.
Annotations themselves aren't directly supported in 2.7, though. Common workarounds include putting that information in the function doc string (where various tools can find it) or in comments (as we already knew).
If looking for a method for your own code: use an annotating decorator. This has the advantage of continuing to work in 3+:
class annotate(object):
def __init__(self, **kwds):
self.kwds = kwds
def __call__(self, func):
func.__annotations__ = self.kwds
#annotate(value=CheckBox)
def setCheckState(self, value):
...
To be a robust decorator it should check that the contents of kwds matches the function parameter names.
That will do the trick
import collections
def create_enum(container, start_num, *enum_words):
return collections.namedtuple(container, enum_words)(*range(start_num, start_num + len(enum_words)))
Switch = create_enum('enums', 1, 'On', 'Off')
Switch is your enum:
In [20]: Switch.On
Out[20]: 1
In [21]: Switch.Off
Out[21]: 2
OK, I got the error of my ways - I mixed up representation with value.
Nevertheless, if you want to enumerate a larger range - in my fake approach you don't have to add values manually. Of course, if you have sequential numbers.
And I hate extra typing :-)