Discussion of Python in High Energy Physics https://hepsoftwarefoundation.org/activities/pyhep.html
repr
is implemented as type(func).__repr__(func)
with func
being your function. Therefore, some kind of wrapping is necessary. Either with a function wrapper as desribed in your link or, depending on your context you may even need to change more, by creating a class instead of a function and implement the __call__
.
Did you use the functools.wraps
? Should be used anyway for any wrapping, like:
def decorator(func):
@functools.wraps(func)
def new_func():
print(f"Wrapped {func}")
return new_func
the problem arises from name clash, e.g. your wrapped function has the same name as the unwrapped. functools.wraps
solves that. Explanation e.g. here
__call__()
).
In [11]: def nice_repr(func):
...: class NiceFunction:
...: def __repr__(self):
...: return f"Nice repr function of {func.__name__}"
...: @functools.wraps(func)
...: def __call__(self, *args, **kargs):
...: return func(*args, **kargs)
...: return NiceFunction()
In [17]: @nice_repr
...: def f(x: float):
...: 'Squares a float'
...: return x**2
In [18]: f
Out[18]: Nice repr function of f
In [19]: f(2)
Out[19]: 4
In [20]: f?
Signature: f()
Type: NiceFunction
String form: Nice repr function of f
Docstring: <no docstring>
Call docstring: Squares a float
f
AttributeError: Can't pickle local object 'nice_repr.<locals>.NiceFunction'
class NiceFunction:
def __init__(self, function):
self.func = function
def __repr__(self):
return f"Nice repr function of {self.func.__name__}"
def __call__(self, *args, **kargs):
return self.func(*args, **kargs)
def nice_repr(func):
return NiceFunction(func)
def f(x: float):
'Squares a float'
return x**2
ff = nice_repr(f)
f(3)
9
f
<function __main__.f(x: float)>
import pickle
pickle.dumps(ff)
b'\x80\x03c__main__\nNiceFunction\nq\x00)\x81q\x01}q\x02X\x04\x00\x00\x00funcq\x03c__main__\nf\nq\x04sb.'
OK, it might be simple, but I cannot see it atm.
I am looking at a dictionary of generators and want to unpack the values. The straight-forward way is to unpack the generators first and then match them up against against the keys (AFAIK the order is preserved). However, this uses two for-loops and an additional dictionary.
Is there an easy way to shorten this?
generators = dict(
t1 = range(0, 20, 2),
t2 = range(10),
t3 = range(0, 100, 10),
)
for g in six.moves.zip(*six.itervalues(generators)):
data = {}
for name, value in six.moves.zip(generators, g):
data[name] = value
print(data)
# desired output per iteration:
# {'t1':0, 't2': 0, 't3': 0}
# {'t1':2, 't2': 1, 't3': 10}
# ...
def iter_dict(gen):
for g in six.moves.zip(*six.itervalues(gen)):
data = {name:value for name, value in six.moves.zip(gen, g)}
yield data
for item in iter_dict(generators):
print(item)
(Copying here from our other communication, @kreczko): I think a generator comprehension in modern python could also work nicely:
from six.moves import zip as s_zip
out_gen = (dict(s_zip(generators, g)) for g in s_zip(*six.itervalues(generators)))
Not likely faster than Henry's code, but a bit less code.
:=
.” - as you may know, that’s no longer true, Python 3.8 will have :=
(along with shared memory multiprocessing and positional-only parameters)
print(f”{1+2=}")
prints 1+2=3
Dear all,
as part of our work in zfit, we have released a standalone package for multibody phasespace generation à la TGenPhaseSpace. It's pure python, based of tensorflow. On top of simple phasespace generation, it can build more complex decay chains, handle resonances, etc, all in a very simple manner.
The package is called phasespace (https://github.com/zfit/phasespace), it's well documented and fairly easy to use, so no excuses for not trying :-)
Let us know what you think, we highly appreciate any feedback and suggestions from the software community here
Jonas+Albert