> On Apr 30, 2020, at 6:32 AM, Joao S. O. Bueno <[email protected]> wrote:
>
> Of course this is meant to be something simple - so there are no "real
> world use cases" that are "wow, it could not have
> been done without it".
The proposed implementation does something risky, it hold holds a non-reentrant
lock across a call to an arbitrary user-defined function. The only reason to
do so is to absolutely guarantee the function will never be called twice. We
really should look for some concrete examples that require that guarantee, and
it would be nice to see how that guarantee is being implemented currently (it
isn't obvious to me).
Also, most initialization functions I've encountered take at least one
argument, so the proposed call_once() implementation wouldn't be usable at all.
> I was one of the first to reply to this on
> "python-ideas", as I often need the pattern, but seldon
> worrying about rentrancy, or parallel calling. Most of the uses are
> just that: initalize a resource lazily, and just
> "lru_cache" could work. My first thought was for something more
> light-weight than lru_cache (and a friendlier
> name).
Right. Those cases could be solved trivially if we added:
call_once = lru_cache(maxsize=None)
which is lightweight, very fast, and has a clear name. Further, it would work
with multiple arguments and would not fail if the underlying function turned
out to be reentrant.
AFAICT, the *only* reason to not use the lru_cache() implementation is that in
multithreaded code, it can't guarantee that the underlying function doesn't get
called a second time while still executing the first time. If those are things
you don't care about, then you don't need the proposed implementation; we can
give you what you want by adding a single line to functools.
> So, one of the points I'd likely have used this is here:
>
> https://github.com/jsbueno/terminedia/blob/d97976fb11ac54b527db4183497730883ba71515/terminedia/unicode.py#L30
Thanks — this is a nice example. Here's what it tells us:
1) There exists at least one use case for a zero argument initialization
function
2) Your current solution is trivially easy, clear, and fast. "if CHAR_BASE:
return".
3) This function returns None, so efforts by call_once() to block and await a
result are wasted.
4) It would be inconsequential if this function were called twice.
5) A more common way to do this is to move the test into the lookup() function
-- see below.
Raymond
-------------------------
CHAR_BASE = {}
def _init_chars():
for code in range(0, 0x10ffff):
char = chr(code)
values = {}
attrs = "name category east_asian_width"
for attr in attrs.split():
try:
values[attr] = getattr(unicodedata, attr)(char)
except ValueError:
values[attr] = "undefined"
CHAR_BASE[code] = Character(char, code, values["name"],
values["category"], values["east_asian_width"])
def lookup(name_part, chars_only=False):
if not CHAR_BASE:
_init_chars()
results = [char for char in CHAR_BASE.values() if re.search(name_part,
char.name, re.IGNORECASE)]
if not chars_only:
return results
return [char.char for char in results]
_______________________________________________
Python-Dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/JZQLF5LXV47SJP6ZSTG27246S6OIYTPM/
Code of Conduct: http://python.org/psf/codeofconduct/