On Thu, 20 Jan 2022 at 10:19, Ricky Teachey <ri...@teachey.org> wrote:

> On Thu, Jan 20, 2022 at 3:35 AM Stephen J. Turnbull <
> stephenjturnb...@gmail.com> wrote:
>
>> Christopher Barker writes:
>>
>>  > If this does all come to pass, then:
>>  >
>>  > s = {3,8,2}.frozen()
>>  > will be slightly faster, in some case, than
>>  > s = frozenset({3,8,2}
>>  >
>>  > but the result would be the same.
>>  >
>>  > There are plenty of tricks to in python to get a touch more
>> performance,
>>  > this would just be one more
>>  > and frankly pretty rare that it would make an noticable difference at
>> all.
>>  >
>>  > +1 on this
>>  > +0 on f{}
>>  > -1 on making frozenset a keyword
>>
>> Stated better than I could, expresses my feelings exactly.  Sticking
>> to integers (in floats I'd be less than -0 on f{}), I'll go with
>> Chris's ratings, too.
>>
>> Steve
>>
>
> Another agreement with Chris' ratings:
>
> +1 for .frozen()
> +0 on f{}
> -1 on keyword for frozenset
>

I really don't understand (having read everything above) why anyone prefers
{1,2,3}.frozen() over f{1,2,3}. Yes, some people coming from some other
languages might get confused (e.g. in Mathematica this is function call
syntax) but that's true of anything: you have to learn Python syntax to use
Python. The fact that {1,2,3} is a set and f{1,2,3} is a frozenset is not
difficult to explain or to understand, especially in a language that
already uses single letter prefixes for other things.

The .frozen() method is a strangely indirect way to achieve a minor
optimisation. Outside of attempting to achieve that optimisation it's
basically useless because any time you would have written obj.frozen() you
could have simply written frozenset(obj) so it does nothing to improve code
that uses frozensets.

With f{...} you have a nice syntax that clearly creates a frozenset
directly and that can be used for repr. This is some actual code that I
recently wrote using frozensets to represent monomials in a sparse
representation of a multivariate polynomial:

  >>> poly = {frozenset([(1,2), (3,4)]): 2, frozenset([(0,1)]): 3}
  >>> poly
  {frozenset({(1, 2), (3, 4)}): 2, frozenset({(0, 1)}): 3}

With the f{...} proposal you have actual syntax for this:

  >>> poly = {f{(1,2), (3,4)}: 2, f{(0,1)}): 3}
  >>> poly
  {f{(1, 2), (3, 4)}: 2, f{(0, 1)}): 3}

With .frozen() it's

  >>> poly = {{(1,2), (3,4)}.frozen(): 2, f{(0,1)}.frozen()): 3}
  >>> poly
  ??? does the repr change?

That difference in code/repr may or may not seem like an improvement to
different people but that should be the real point of discussion if talking
about a frozenset literal. The performance impact of frozenset literals is
not going to be noticeable in any real application.

My polynomial class makes extensive use of frozensets and is something that
I do need to be as fast as possible. I just looked through the code I have
for that class and none of the performance sensitive routines could benefit
from this because they all actually need to build their elements in a dict
before converting to a frozenset anyway e.g.:

    def mul(self, other):
        """multiply two (frozenset) monomials"""
        powermap = dict(self)
        for g, n in other:
            other_n = powermap.get(g)
            if other_n is None:
                powermap[g] = n
            else:
                powermap_n = other_n + n
                if powermap_n:
                    powermap[g] = powermap_n
                else:
                    powermap.pop(g)
        return frozenset(powermap.items())

I've just profiled this and the call to frozenset is always dwarfed by the
time taken in the preceding loop which shows how cheap converting between
builtins is compared to pretty much any other code.

If you're using literals then of necessity you are talking about small
sets. Even just using a small set over a small tuple is a hardly noticeable
difference in speed in most situations:

In [12]: s = {1,2,3}

In [13]: t = (1,2,3)

In [14]: timeit 2 in s
44.9 ns ± 0.17 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [15]: timeit 2 in t
59.9 ns ± 5.67 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

--
Oscar
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/5YECLMZ7ACSYOYPVK6U3NYDG5VJRLTUG/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to