#esoteric-python

1 messages · Page 30 of 1

mental vector
#

yeah that was the only one I'm familiar with

finite blaze
#

i don't want to be like all these cool big languages out here ;p

mental vector
#

so you want to do it in like a bizarre way, or still practical but just unique?

fleet bridge
#

Lambdas in python do that too (but they cannot contain statements at all)

fleet bridge
#

Pascal and delphi have special variable result
To return something from function, you should assign to result and then exit from function

function add(a: integer; b: integer): integer
begin
  result := a + b;
  exit; // not needed in this particular case; does the same as plain return in other languages
end;
``` probably i messed syntax somewhere, but you get the idea
finite blaze
#

Yeah, so result is a key word and probably can't be used as a variable name?

fleet bridge
#

Idk, probably it is special-cased

#

Like this in cpp

#

Other idea: dont return anything from functions

All functions have side effect: they assign their result to global variable result

add(1, 2)
print(result) # 3
brazen geyser
#

a language called DM has a special variable inside functions called ., which is returned by default if the function ends without an explicit return

finite blaze
#

^ i wanted to suggest that too

#

something like

#
fn max(a,b)
{
  if(a > b)
  {
    .= a;
  }
  else
  {
    .= b;
  }
}
#

and its quick to type

brazen geyser
#

oh, also, a bare return without a value also returns .

fleet bridge
#

I like and dont like that at the same time

oak anchor
#

big yikes from me

#

so if you don't assign to . it doesn't return anything? actually that kinda works

brazen geyser
oak anchor
#

on the other hand, x .= y as a shorthand for x = getattr(x, y) doesn't sound bad at all

#

it'll remove most needs of the ?. operator

brazen geyser
#

DM is fairly weird... it started out as a scripting language for making MUDs back in the 90s, then grew quite a bit from there. it's got a few idiosyncrasies.

finite blaze
#
fn max(a, b) .= a > b ? a : b;
#

Looks fun

proper vault
#

Nim has a similar thing, it's just called result

#

Could probably make that work in python

finite blaze
#

Btw, what functionalities would u like to see in python?

#

And what would you change?

#

I would for sure add i++, i--

sage viper
#

Is this the best channel to ask about the nitty gritty of "faster cpython" optimizations in 3.11? Please let me know if there is a better channel for this question.

I'm curious how the "Load attribute" optimization works, and when it works.

Similar to loading global variables. The attribute’s index inside the class/object’s namespace is cached. In most cases, attribute loading will require zero namespace lookups.

https://docs.python.org/3/whatsnew/3.11.html#whatsnew311-faster-cpython

If I have a class Foo: pass and I make two instances a = Foo() ; a.bar = 1 ; a.foo = 1 ; b = Foo() ; b.foo = 1 ; b.biff = 1

Does this mean a_or_b.foo is optimized? And how? Because a and b have different dictionary layouts.

mental vector
sage viper
#

thanks, I didn't see that one, sounds good

finite blaze
#

Okay, how about for loops

#

how would you guys do it?

#

I was thinking about doing it in rust style

#

but when I saw this abomination

for i in 0..array.len()
#

i decided not to ;p

fleet bridge
sage viper
#

I'm guessing that the dictionaries have some sort of a field describing their "shape ID" or something? So if each dictionary has identical shape -- same keys stored in the same layout -- then they share a "shape ID" and the optimization checks this shape ID to see if the cached offset is valid?

My worry is that the optimization actually never works for different objects, only the same object.
So foo.some_method is optimized because it's doing a lookup on the class itself (singleton)
And math.PI is optimized because math is similarly a singleton
But a_or_b.foo is not optimized because the object is different each time, not a singleton

sage viper
#

I see how split-table dictionaries work now, and understand what you meant about assigning all attributes in __init__
https://peps.python.org/pep-0412/#split-table-dictionaries
I guess the optimization also fails if the code is generic and accepts subclasses of Foo, because each subclass that adds its own fields will have different __dict__ keys

finite blaze
#

that sucks

brazen geyser
#

for var in 1 to 10:

finite blaze
#

what about step?

brazen geyser
#

hmm

#

1 to 10, step x:

proper vault
#

look into kotlin syntax

fleet bridge
#

In pascal there are for x := a to b do ... and for x := a downto b do ...

dreamy pier
#
for var from 1 to 10 with step 3
fleet bridge
#

with step - combined keyword 💀

#

Keyword that consists of two words

#

a not in b a is not b

stark granite
dreamy pier
#

a better one

#
for var with values from 1 to 10 with step 3
#
for var with all values from 1 to 10 with step 3
for var with last 2 values from 1 to 10 with step 3
for var with first 2 values from 1 to 10 with step 3
finite blaze
#

Maybe just

for var with all values from one to ten with step three
dreamy pier
#

hmm yeah

#

i think double with is not really good

#
for var in all values from one to ten with step three

hmm how to color all values

proper vault
#

haskell syntax may also be worth considering, [1,3..11] for all odd numbers e.g.

finite blaze
#

How does this work?

proper vault
#

It computes the difference between the second and first element and uses it as step

finite blaze
#

So it would print 3,5,7,9,11?

proper vault
#

Yes

#

I did say all odd numbers, that's incorrect. [1,3..] is all odd numbers

#

If you want really in depth syntax, raku has more syntax for ranges than some languages have total. But I wouldn't recommend copying raku, there is a reason it took so long to implement

fleet bridge
#

is [1,3..12] same as [1,3..11]?

#

or it just explodes?

finite blaze
#

same as in other languages i guess

for(int i=1; i <= 12; i+=2)
#
for(i+=2, @arrA.Len()) // same as @(0, arrA.Len()), range(0, len(arrA)) in python
{
  Print(arrA[i]);
}
#

^ i think thats how i will do this in my lang

#

!e

arrA = [1,2,3,4,5,6]
for i in range(0, len(arrA), 2):
  print(arrA[i])
night quarryBOT
#

@finite blaze :white_check_mark: Your 3.11 eval job has completed with return code 0.

001 | 1
002 | 3
003 | 5
finite blaze
#

@ will create an iterator

proper vault
digital mesa
proper vault
#

fair enough

fleet bridge
#

how to express iterator over all odd numbers from -inf to +inf?

#

how would it iterate over them 🤔

mental vector
#

Like in order?

fleet bridge
#

what is the first odd number?

astral rover
#

-inf + 1 obvs :)

#

everyone knows inf is even

mental vector
#

-sys.maxint maybe. Idk what the mathematicians did before the sys library

fleet bridge
fleet bridge
mental vector
#

Lol that was just a joke

fleet bridge
#

there is this: ```py

hex(sys.maxsize)
'0x7fffffffffffffff'

oak anchor
astral rover
#

still hasnt been merged lemon_angrysad

mental vector
#

Wow this is cool, I haven't seen this yet

sage viper
versed eagle
#

!e

# fib
p=5**.5/2+.5;a=lambda n:round((p**n-(-p)**-n)/5**.5)
b=lambda n:round((5**.5/2+.5)**n/5**.5)

# correctness check
print(all(a(i)==b(i) for i in (__import__("random").randint(0, 1000) for _ in range(100))))
night quarryBOT
#

@versed eagle :white_check_mark: Your 3.11 eval job has completed with return code 0.

True
quartz wave
#

also that was half a year ago

versed eagle
#

mhm

#

i know how long ago it was

vast wave
stark granite
sonic birch
#

Hi guys) Is it possible to inherite class from GeneratorType. Are there any tricks?

quartz wave
stark granite
#

wait you can include variables in f-strings? (like {foo:^{bar}})

quartz wave
#

yep

stark granite
#

i thought it had be pre-defined

#

._.

quartz wave
#

well that's -46b

stark granite
#

hm?

quartz wave
stark granite
#

b?

quartz wave
#

bytes

stark granite
#

why in bytes?

#

and not characters

quartz wave
# stark granite and not characters

because this is 74c but 172b ```py
exec(bytes("硜晦硜敦潦⁲⁩湩爠湡敧⠨㩢椽瑮椨灮瑵∨祐慲業⁤慢敳猠穩㩥∠⤩⼩㈯ㄫ㨩牰湩⡴≦❻✣⠪╢⬲⭩⥩帺扻絽⤢",'u16')[2:])

stark granite
#

what is it even doing

stark granite
#

i thought it would be bytecode

serene stratus
#

No because then you'd need to marshal load it

fleet bridge
#

You can create code objects manually

serene stratus
delicate pagoda
#

I worked on an open source project that embeds the Mozilla SpiderMonkey JS engine in Python --> https://github.com/Distributive-Network/PythonMonkey

it lets you interoperate with JS and Python really easily and you get some cool extra benefits out of it like being able to run WebAssembly from JS super easily. Since its just a python library, you can install it with pip install pythonmonkey

import pythonmonkey as pm

js_func = pm.eval("(x) => { console.log(`${x} is an awesome number!`); }")

js_func(4) # 4 is an awesome number

PLay around with the colab https://colab.research.google.com/drive/1INshyn0gNMgULQVtXlQWK1QuDGwdgSGZ?usp=sharing

GitHub

A Mozilla SpiderMonkey JavaScript engine embedded into the Python VM, using the Python engine to provide the JS host environment. - GitHub - Distributive-Network/PythonMonkey: A Mozilla SpiderMonke...

#

later down the line we want to evolve it into a Node.JS / Deno / Bun killer that would be like a drop in replacement for node.js that lets you import python modules like esms

#

I'm gonna be busy driving for the next few hours so apologies if I dont respond until like noon for any questions anyone has

fleet bridge
#

Never heard of it

dapper walrus
#

how you write this in the longest form possbile

for i in string:
   lst.append(i)
quartz wave
dapper walrus
#

ty

stark granite
dapper walrus
#

lst could be a variable name, donno

stark granite
#

ok i think i am done

#

idk how else to expand it

versed eagle
#

the only real limit is how much time you're willing to spend making it longer

#

or how big of a file you're able to store

#

you could literally just use whitespace

for i in range(string):
                             lst.append(i)
#

indentation can be as long as you want it to be

astral rover
#

That's not true is it? There's a max indent

restive void
#

Also, the maximum indents apply to levels, not amount of spaces IIRC

fleet bridge
#

!e exec('if 1:\n' + ' ' * 10**6 + 'print(123)')

#

!e exec('if 1:\n' + ' ' * 10**7 + 'print(123)')

#

!e exec('if 1:\n' + ' ' * 10**8 + 'print(123)')

#

!e exec('if 1:\n' + ' ' * 3 * 10**7 + 'print(123)')

#

!e exec('if 1:\n' + ' ' * 2 * 10**7 + 'print(123)')

night quarryBOT
#

@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.

123
brazen geyser
#

hmm, not sure if it's the right channel for this but it probably falls under the 'python weirdness' category so here goes

#

let's say you have a function that you can't/don't want to change the code of. iter is used inside this function multiple times to create iterators from an arbitrary collection of items. for debug purposes, you want to replace the iterators made in this function with special ones that contain extra info which can help track down bugs.

#

would it be ok to just remake the function with new globals?
i.e.


def mask_globals(function: types.FunctionType, masked_globals: dict):
    return types.FunctionType(
        code=function.__code__,
        globals={**function.__globals__, **masked_globals},
        name=function.__name__,
        argdefs=function.__defaults__,
        closure=function.__closure__,
    )
#

then

new_function = mask_globals(original_function, {'iter': DebugIterator})
#

would there be any major pitfalls here?

proper vault
brazen geyser
#

how would i specify iter as a target? module.iter doesn't seem to work

#

in any case, i've already got it working with mask_globals above. just wondering if there are any potential issues i might've overlooked with replacing a function's globals like that.

proper vault
restive void
#

The solution by @brazen geyser is also leaky: if the global state is mutated after this patch, that wouldn't be seen in the patched function.

brazen geyser
brazen geyser
#

ah
TypeError: function() argument 'globals' must be dict, not ChainMap

#

so...

class ChainMap(collections.ChainMap, dict):
  pass

😃

sonic birch
#

!e

from types import SimpleNamespace

def esoteric_class(gen):
  def wrapper(*args, **kwargs):
    g = gen(*args, **kwargs)
    next(g)
    return SimpleNamespace(**g.gi_frame.f_locals)
  return wrapper
    

@esoteric_class
def User(first_name: str, second_name: str):

  full_name: str = f'{first_name} {second_name}'
  
  def is_jack():
    return first_name.lower()=='jack'
  
  yield

user = User('Jack', 'Smith')
print(user.is_jack())
night quarryBOT
#

@sonic birch :white_check_mark: Your 3.11 eval job has completed with return code 0.

True
sonic birch
#

Cool 🙂

fleet bridge
brazen geyser
#

!e

from collections import ChainMap
class ChainMap(ChainMap, dict): pass
print(eval('iter', ChainMap({'iter': 123}, globals())))
night quarryBOT
#

@brazen geyser :white_check_mark: Your 3.11 eval job has completed with return code 0.

123
brazen geyser
#

this works in 3.10 and above, but in 3.9 and below it seems global lookups use dict.__getitem__ regardless of mro, so rip to that.

astral rover
delicate pagoda
astral rover
#

i cant dm you without adding you 😉

delicate pagoda
# astral rover i cant dm you without adding you 😉

I will note that the node compatibility isn't perfect at the moment. Although it works with some npm packages like crypto-js its an area for improvement

But you can replace it / use it as a base to get stuff working. for instance I needed to use fs.readFileSync from nodejs so I had to replace it with open in python

#

But we'll be improving it over time, and honestly it might be the closest python library you can get to running nodejs libraries at the moment even though its only in alpha

versed eagle
#

(ignoring physical memory limits)

astral rover
#
  Cell In[2], line 101
    if True:
    ^
IndentationError: too many levels of indentation```
#

took a while but you can get there

versed eagle
#

can you send the entire file?

#

cause this works on my machine:

exec(f"if True:\n {' ' * 2**32}print('hello world')")
astral rover
#

i stacked if True: a lot not just used a tonne of ws

versed eagle
#

oh

#

indentation levels

#

not the actual indentation itself

#

oh something interesting did happen though

#
exec(f"if True:\n {' ' * 2**32}print('hello world')")

for this, when using a value of 2**31, i get a system error

#

it doesnt happen when creating the string, just when exec'ing it

#
>>> _=f"if True:\n {' '*2**31}print('hello world')"
>>> exec(_)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
SystemError: Negative size passed to PyUnicode_New
#

creating the string is fine, but exec'ing it does that

#

but thats not caused by the indentation

astral rover
#

hmm

versed eagle
#

am testing 2**34 now

versed eagle
#

yeah

burnt gust
#

didneylan inspired this

from itertools import permutations as a

p = lambda s,c:'\n'.join(' '.join(''.join(h)for h in g)for g in zip(*([a(s)]*c)))

print(p('disneyland', 10))

fleet bridge
#

!e

from itertools import permutations as a

p = lambda s,c:'\n'.join(' '.join(''.join(h)for h in g)for g in zip(*([a(s)]*c)))

print(p('disneyland', 10))

night quarryBOT
#

@fleet bridge :warning: Your 3.11 eval job timed out or ran out of memory.

[No output]
fleet bridge
#

Useful!

delicate pagoda
#

I don't want to be too annoying but it really makes a difference!

#

And if you have any questions about it let me know!

quartz wave
sonic birch
quartz wave
sonic birch
sacred sphinx
#

!e

import subprocess
subprocess.check_output(["ls", "-la"])
night quarryBOT
#

@sacred sphinx :x: Your 3.11 eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "/home/main.py", line 2, in <module>
003 |     subprocess.check_output(["ls", "-la"])
004 |   File "/usr/local/lib/python3.11/subprocess.py", line 466, in check_output
005 |     return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
006 |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
007 |   File "/usr/local/lib/python3.11/subprocess.py", line 548, in run
008 |     with Popen(*popenargs, **kwargs) as process:
009 |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
010 |   File "/usr/local/lib/python3.11/subprocess.py", line 1026, in __init__
011 |     self._execute_child(args, executable, preexec_fn, close_fds,
... (truncated - too many lines)

Full output: https://paste.pythondiscord.com/CDW4K7KBJCJ5ZGV33WOUSXDYTU

versed eagle
burnt gust
stark granite
floral meteor
#

Me on my way to make a programming teacher quit their job if they tell me to make one more sorting algorithm:

sort = lambda a:[*{*a}]
#

why manually sort it when you can just convert it to unsorted then convert it back to sorted?

#

although I'll just check that it works in new versions

#

!e ```py
a = [1,6,2,5,3,4,9,8,7]
print( a, "sorted is", [*{*a}] )

night quarryBOT
#

@floral meteor :white_check_mark: Your 3.11 eval job has completed with return code 0.

[1, 6, 2, 5, 3, 4, 9, 8, 7] sorted is [1, 2, 3, 4, 5, 6, 7, 8, 9]
finite blaze
#

how does this work?

astral rover
#

it doesnt work for numbers bigger than 255 tho

proper vault
#

It's a consequence of how set works internally, and is not reliable for larger numbers

floral meteor
finite blaze
#

doesn't set remove duplicates?

#

if i remember correctly

floral meteor
#

yes

finite blaze
#

👍

#

also, why won't it work for 255+ numbers

astral rover
#

because they arent allocated in order neccesarily

floral meteor
#

lmao I tested it for larger numbers, it listed them backwards

finite blaze
#

what would be the shortest way to reverse the order of ^ list?

floral meteor
#

[::-1]

astral rover
#

listing them backwards there was purely coincidental

floral meteor
#

!e ```py
a = [255, 1530, 510, 1275, 765, 1020, 2295, 2040, 1785]
print([*{*a}][::-1])

night quarryBOT
#

@floral meteor :white_check_mark: Your 3.11 eval job has completed with return code 0.

[255, 510, 765, 1020, 1275, 1530, 1785, 2040, 2295]
floral meteor
#

nope

#

that's sorted

#

💪

astral rover
#

!e py a = [255, 1530, 510, 1275, 765, 102, 2295, 2040, 1785] print([*{*a}][::-1])

night quarryBOT
#

@astral rover :white_check_mark: Your 3.11 eval job has completed with return code 0.

[255, 510, 765, 1275, 1530, 1785, 2040, 2295, 102]
astral rover
#

that time at least with different numbers it broke

floral meteor
#

102 isn't over 255

astral rover
#

!e ok then what about this

a = [255, 1530, 510, 1275, 765, 1022, 2295, 2040, 1785]
print([*{*a}][::-1])```
night quarryBOT
#

@astral rover :white_check_mark: Your 3.11 eval job has completed with return code 0.

[255, 510, 765, 1275, 1530, 1785, 2040, 2295, 1022]
floral meteor
#

in which case what we can do is test for being under 255 and list them first then concatenate the backwards sort for over 255

astral rover
#

no you cant

astral rover
#

random chance

floral meteor
#

it seems to work a little over 255

#

it doesn't work either way for arbitrary integers though like keyboard mashed ones:

earnest wing
#

you can't rely on it for anything version-agnostic

static knoll
versed eagle
#

got that output from it

#

so uh

#

yeah

versed eagle
night quarryBOT
#

@versed eagle :white_check_mark: Your 3.11 eval job has completed with return code 0.

True
versed eagle
#

works up to 10000 ¯_(ツ)_/¯

astral rover
#

thats probably cause they got allocated in order

versed eagle
#

interesting

#

so you're saying its a valid sorting algorithm, as long as you preallocate all the numbers in a sorted manner

astral rover
#

i think so

versed eagle
#

thats actually really interesting

astral rover
#

its to do with either their hash or id

#

(id probably controls hash but idr)

versed eagle
#

cause im able to allocate certain numbers beforehand and still get them returned sorted

astral rover
#

what numbers?

#

and are you in a repl or just a script?

versed eagle
versed eagle
#

first test was range(10000) after preallocating 3005, second test was range(10010) after preallocating 10005

#

i went ahead and wrote a script

#
TEST_PREALLOCS = tuple(map(list, (
    range(250, 300),
    range(3000, 4000),
)))

import random

sort = lambda a:(n:=[])or(any(n.extend((v,)*a.count(v))for(v)in{*a}))or(type(a)(n))

testlist = list(range(10000))
random.shuffle(testlist)

print(sort(testlist) == sorted(testlist))
#

this prints True for me

#

its true up to 100_000 as well

#

it breaks as soon as negative numbers are involved but thats not important

#

for non-negative integers up to 100_000, it is a correct (albeit (extremely) slow) sorting algorithm

versed eagle
fleet bridge
versed eagle
fleet bridge
#

Yes

#

hash(-1) is -2

distant salmon
#

!e

x = 2**61 - 1
print(hash(1000 * x + 127))
print(hash(-1000 * x - 127))
print(hash(x))
night quarryBOT
#

@distant salmon :white_check_mark: Your 3.11 eval job has completed with return code 0.

001 | 127
002 | -127
003 | 0
distant salmon
#

Which is one reason why hash tables with integer keys in Python are super fragile. You can easily create tons of integers with the same exact hash.

humble blade
#

pretty rare to accidentally create a whole bunch of numbers with this pathologic hash though

distant salmon
#

Most programmers just assume that it is safe to store integers in set or to use integers as keys in a dict, but it is in fact not safe.

humble blade
#

i feel like just the memory needed to store that many numbers (of that size, especially) would be an issue long before it slows down the dict

distant salmon
humble blade
#

mm

distant salmon
#

!e

x = 2**61 - 1
[x * i for i in range(10**5)]
night quarryBOT
#

@distant salmon :warning: Your 3.11 eval job has completed with return code 0.

[No output]
distant salmon
#

!e

x = 2**61 - 1
set(x * i for i in range(10**5))
night quarryBOT
#

@distant salmon :warning: Your 3.11 eval job timed out or ran out of memory.

[No output]
fleet bridge
#

Interesting

distant salmon
# astral rover is this a dos attack?

It is also possible to construct ddos hashtable attacks with carefully designed smaller numbers too. But the easy "attack" is just to use multiples of 2^61 - 1

languid hare
#
>>> s = set(x * i for i in range(10**5))
>>> sys.getsizeof(s)
2097260
>>> l = list(x * i for i in range(10**5))
>>> sys.getsizeof(l)
439916
#

the set actually runs pretty quick on my computer

distant salmon
languid hare
#

same as yours, x = 2**61 - 1

distant salmon
#

Can you try printing hash(x)?

languid hare
#

mm i wonder if my python is using a different mod

#

yea ill check that

#

ah, yep

>>> hash(x)
1073741823
>>> hash(x * 2)
2147483646
>>> hash(x * 3)
1073741822
distant salmon
#

Are you using 32 bit CPython?

#

Maybe that one uses mod 2^31 - 1

languid hare
#
>>> x = 2 ** 124 - 1
>>> hash(x)
0
>>> hash(x * 2)
0

124 apparently

languid hare
distant salmon
#

So try 2^31 - 1

astral rover
#

fwiw ```py
In [1]: import sys

In [2]: sys.hash_info
Out[2]: sys.hash_info(width=64, modulus=2305843009213693951, inf=314159, nan=0, imag=1000003, algorithm='siphash24', hash_bits=64, seed_bits=128, cutoff=0)

In [3]: import math

In [4]: math.log2(sys.hash_info.modulus)
Out[4]: 61.0

languid hare
distant salmon
#

So my point still stands, hash tables in Python are very fragile

humble blade
#

wonder if there are any other data structure hashes that are easy enough to mess with

fleet bridge
#

tuple?

languid hare
#

the tuple/list hashes are pretty messy from what i remember

distant salmon
#

String hashes in Python are randomized, so you will be safe using them as keys in hash tables

fleet bridge
languid hare
#

the old one was just a multiplication and xor, but a simple collision was found so they changed it to make it more complex

#

iirc the issue was that (a, (a, b)) would have the same hash as b

distant salmon
#

Btw if someone is interested to know how dict works in Python, then here is the relevant source code. https://github.com/python/cpython/blob/bb86bf4c4eaa30b1f5192dab9f389ce0bb61114d/Objects/dictobject.c#L700-L720
From this, it is possible to figure out how to construct sequences of small numbers (say < 1e6) that can be used to attack dict

GitHub

The Python programming language. Contribute to python/cpython development by creating an account on GitHub.

fleet bridge
humble blade
#
static Py_hash_t
tuplehash(PyTupleObject *v)
{
    Py_ssize_t i, len = Py_SIZE(v);
    PyObject **item = v->ob_item;

    Py_uhash_t acc = _PyHASH_XXPRIME_5;
    for (i = 0; i < len; i++) {
        Py_uhash_t lane = PyObject_Hash(item[i]);
        if (lane == (Py_uhash_t)-1) {
            return -1;
        }
        acc += lane * _PyHASH_XXPRIME_2;
        acc = _PyHASH_XXROTATE(acc);
        acc *= _PyHASH_XXPRIME_1;
    }

    /* Add input length, mangled to keep the historical value of hash(()). */
    acc += len ^ (_PyHASH_XXPRIME_5 ^ 3527539UL);

    if (acc == (Py_uhash_t)-1) {
        return 1546275796;
    }
    return acc;
}
#

looks pain

languid hare
#

The len being mixed in at the end there makes it a little more annoying

#

mm actually it seems pretty doable 👀

#
acc = _PyHASH_XXROTATE(acc);
acc *= _PyHASH_XXPRIME_1;

the bit rotation is obviously invertible
the multiplication is invertible (even with bit overflow) because it's multiplying by a prime

#

then invert the acc += lane * _PyHASH_XXPRIME_2; to get lane, which is the hash of the element

#

and we can just set the element equal to lane, since ints hash to themselves

fleet bridge
#
x = hash(obj)
assert x == hash(x) # always true
#

(hash is an identity function if applied the second time)

languid hare
#

idempotent! i love that word

fleet bridge
#

I forgot that word (

languid hare
#

some progress

#

!e

print(hash( () ))
print(hash( (1778577755476246539,) ))
night quarryBOT
#

@languid hare :white_check_mark: Your 3.11 eval job has completed with return code 0.

001 | 5740354900026072187
002 | 5740354900026072187
languid hare
#

!e

assert hash(()) == hash((1778577755476246539,)) == hash((1778577755476246539, 654455456954384049)) == hash((1778577755476246539, 654455456954384049, -930367412484010356)) == hash((1778577755476246539, 654455456954384049, -930367412484010356, -2054489711005872846)) 
night quarryBOT
#

@languid hare :warning: Your 3.11 eval job has completed with return code 0.

[No output]
languid hare
#

trying to extend it once more fails though, interestingly

tough willow
#

What are those Numbers? Where do they come from

mortal grotto
#

Python Golfing :D hehe
I have a script, which turns any integer (no limit as long as the RAM is enough) into a worded number in German, following all the capitalization rules and everything. For fun I was golfing the script, so it it as short as possible (counting bytes, I don't like those exec(decode()) approaches).

And so I could make it as small as 1040 bytes (wc -c zahl.py)

Would anyone be ready to break their brain with me and make the code sub 1000?

*A,L,M,J,K,N,O,P,B,D,E,G,g,k="drei vier fünf sech sieb acht neun zehn elf zwölf sept quin ns ginta ing okt qua mn mx dr non tre en".split()
F,n,o,C,U,m,H,j="ego sanz"
I,S="",10;Q=S*S;T=Q*S
Y=["null","ein","zwei"]+A*T
Y[6]+=U;Y[7]+=k
def Z(q,r=I):
 a=abs(q);d,u=a//T,2;s=Y[b:=a%Q]*(a<S)or Z(d%T,"tausend ")+Z(a%T//Q,"hundert")+[Z(a%S,"und")+["zwan",*A][b//S-2]+"zß"[b//S==3]+"ig",Y[b]*(b>0)+A[7]*(b>12)][b<20]
 while d:
  V,v=u//2,I
  while V:c,e=V//S%S,V//Q%S;h,z,*_=[I,I,"un",I,"duo",I,g,U,P+"ttuor",I,M,I,U+F,"x",L+F,B,O+o,I,"nove",B][V%S*2:];f,y,*_=[i:=["nxs",j,H,"duz",J,g+j,J,P+E+N,J,M+n,H,"sesz",H,L+N,D,O+N,I,G+n,I][e*2-2:],[H,"dezi","ms","viginti",J,"tri"+K,J,P+E+m+K,J,M+P+K,H,"sexa"+K,H,L+"ua"+K,D,O+o+K,I,G+m+K][c*2-2:]][c>0];v=(*[H,*"mb","tr",P+E,M+"t","sext",L,O,G][V%T:],(h+I.join({*z}&{*f})+y+i[1]*(c>0)+"enti"*(e>0))[:-1])[0]+"illi"+v;V//=T
  d//=T;s=Z(p:=d%T,F*(p<2)+C+v.title()+[o+H,"arde"][u%2]+k[u%2:]*(p>1)+C)+s;u+=1
 return[(s:="minus "*(q<0)+s+U[(a==1)*r>I:b==1])[0].title()+s[1:].strip(),(s+r)*(a>0)][r>I]
zahl=Z
#

The rules are: the file must have a function "zahl" which can be imported from another file and the function should accept an integer as its' first argument anf return a string representing the number

#

The code above is producing the right output and is following the rules.

mortal grotto
#

Uh, better not show it, it's really bad. It was written to be golfed later on

languid hare
distant salmon
versed eagle
#

yep thats true

#

my brain forgot to use english for a bit lmao

versed eagle
#

or rather, can you specify what rules you're talking about

#

also, what python version does this run in

gleaming linden
#

seems to work in 3.11 for me

distant salmon
#

Here is another example

>>> print(Z(1234567123456712345671234567))
Eine Quadrilliarde zweihundertvierunddreißig Quadrillionen fünfhundertsiebenundsechzig Trilliarden einhundertdreiundzwanzig Trillionen vierhundertsechsundfünfzig Billiarden siebenhundertzwölf Billionen dreihundertfünfundvierzig Milliarden sechshunderteinundsiebzig Millionen zweihundertvierunddreißigtausend fünfhundertsiebenundsechzig
versed eagle
mortal grotto
#

Yeah, I am using 3.11 for this, so - no we can't, this will produce a Warning

mortal grotto
gleaming linden
#

technically SyntaxWarning is sent to stderr so it doesn't matter if you only care about stdout

mortal grotto
#

The original code was over 2600 bytes, btw

#

Can't even send here

versed eagle
#

i dont know german

versed eagle
#

yay

mortal grotto
versed eagle
#

i dont know german

mortal grotto
#

Although, I believe those rules won't help any further - just looking at the code should suffice for golfing

#

Wait a second, I will host the ungolfed version somewhere, so I can share it here

versed eagle
night quarryBOT
#
Pasting large amounts of code

If your code is too long to fit in a codeblock in Discord, you can paste your code here:
https://paste.pythondiscord.com/

After pasting your code, save it by clicking the Paste! button in the bottom left, or by pressing CTRL + S. After doing that, you will be navigated to the new paste's page. Copy the URL and post it here so others can see it.

distant salmon
mortal grotto
mortal grotto
#

Ofc I can paste it here formatted and made more readable, but that would cost me a lot of bytes

mortal grotto
#

Golfed code and readability are like two different universes

versed eagle
versed eagle
distant salmon
mortal grotto
#

Okey, I will go and re-write my current code, to make it more readable, I hope we can find some solutions then

versed eagle
#

you don't have to rewrite it, necessarily

mortal grotto
#

(And I will add explanatory comments)

mortal grotto
versed eagle
#

ah

versed eagle
#

well, send a ping whenever you do that ig

versed eagle
mortal grotto
#

Iterating is what is happening in the final code

#

Also final code does not have any functions excepts the main function "Z"

#

Commenting my code to make clear, what is happening just made it double the ungolfed size

regal merlin
#

Would customizing import behavior fall under this channel's topics, or is it not weird enough?

#

If it doesnt, which channel would be better?

languid hare
#

sounds pretty esoteric

#

elaborate?

quartz wave
# mortal grotto Python Golfing :D hehe I have a script, which turns any integer (no limit as lon...

-1b ```py
A,L,M,J,K,N,O,P,B,D,E,G,g,k="drei vier fünf sech sieb acht neun zehn elf zwölf sept quin ns ginta ing okt qua mn mx dr non tre en".split()
F,n,o,C,U,m,H,j="ego sanz"
I,S="",10;Q=S
S;T=QS
Y=["null","ein","zwei"]+A
T
Y[6]+=U;Y[7]+=k
def Z(q,r=I):
a=abs(q);d,u=a//T,2;s=Y[b:=a%Q](a<S)or Z(d%T,"tausend ")+Z(a%T//Q,"hundert")+[Z(a%S,"und")+["zwan",A][b//S-2]+"zß"[b//S==3]+"ig",Y[b](b>0)+A[7](b>12)][b<20]
while d:
V,v=u//2,I
while V:c,e=V//S%S,V//Q%S;h,z,_=[I,I,"un",I,"duo",I,g,U,P+"ttuor",I,M,I,U+F,"x",L+F,B,O+o,I,"nove",B][V%S2:];f,y,_=[i:=["nxs",j,H,"duz",J,g+j,J,P+E+N,J,M+n,H,"sesz",H,L+N,D,O+N,I,G+n,I][e2-2:],[H,"dezi","ms","viginti",J,"tri"+K,J,P+E+m+K,J,M+P+K,H,"sexa"+K,H,L+"ua"+K,D,O+o+K,I,G+m+K][c2-2:]][c>0];v=([H,"mb","tr",P+E,M+"t","sext",L,O,G][V%T:],(h+I.join({z}&{f})+y+i[1](c>0)+"enti"(e>0))[:-1])[0]+"illi"+v;V//=T
d//=T;s=Z(p:=d%T,F
(p<2)+C+v.title()+[o+H,"arde"][u%2]+k[u%2:](p>1)+C)+s;u+=1
return[(s:="minus "
(q<0)+s+U[a==1!=r>I:b==1])[0].title()+s[1:].strip(),(s+r)*(a>0)][r>I]
zahl=Z

versed eagle
regal merlin
# languid hare elaborate?

tl;dr i want to customize import behavior to detect and replace methods matching a certain behavior as part of pyglet's unit tests

#

this does not play nicely with a module proxy class they use:

@fixture(autouse=True)
def monkeypatch_all_shaders(monkeypatch, get_dummy_shader_program):
    original_import = __import__

    def import_and_patch_shader_getter_members(module_name, *args, **kwargs):
        imported = original_import(module_name, *args, **kwargs)

        for member_name, member in inspect.getmembers(imported, is_shader_getter):
            monkeypatch.setattr(f"{module_name}.{member_name}", get_dummy_shader_program)

        return imported

    monkeypatch.setattr(builtins, "__import__", import_and_patch_shader_getter_members)
mortal grotto
quartz wave
regal merlin
# versed eagle hook `__import__`

can you please be more specific? I think that's what I'm trying to do in the code abbove, but I think I am doing it wrong. Others have reported it working, but it may not work in the specific context.

#

source-level transformation is uncessary imo, just monkeypatching

quartz wave
mortal grotto
mortal grotto
quartz wave
# mortal grotto I was sitting on this for a while

-2b ```py
A,L,M,J,K,N,O,P,B,D,E,G,g,k="drei vier fünf sech sieb acht neun zehn elf zwölf sept quin ns ginta ing okt qua mn mx dr non tre en".split()
F,n,o,C,U,m,H,j="ego sanz"
I,S="",10;Q=S
S;T=QS
Y=["null","ein","zwei"]+A
T
Y[6]+=U;Y[7]+=k
def Z(q,r=I):
a=abs(q);d,u=a//T,2;s=Y[b:=a%Q](a<S)or Z(d%T,"tausend ")+Z(a%T//Q,"hundert")+[Z(a%S,"und")+["zwan",A][b//S-2]+"zß"[b//S==3]+"ig",Y[b](b>0)+A[7](b>12)][b<20]
while d:
V,v=u//2,I
while V:c,e=V//S%S,V//Q%S;h,z,_=[I,I,"un",I,"duo",I,g,U,P+"ttuor",I,M,I,U+F,"x",L+F,B,O+o,I,"nove",B][V%S2:];f,y,_=[i:=["nxs",j,H,"duz",J,g+j,J,P+E+N,J,M+n,H,"sesz",H,L+N,D,O+N,I,G+n,I][e2-2:],[H,"dezi","ms","viginti",J,"tri"+K,J,P+E+m+K,J,M+P+K,H,"sexa"+K,H,L+"ua"+K,D,O+o+K,I,G+m+K][c2-2:]][c>0];v=([H,"mb","tr",P+E,M+"t","sext",L,O,G][V%T:],(h+I.join({z}&{f})+y+i[1](c>0)+"enti"(e>0))[:-1])[0]+"illi"+v;V//=T
d//=T;s=Z(p:=d%T,F
(p<2)+C+v.title()+"aorndeenn"[~u&1:4*(p>1)+4:2]+C)+s;u+=1
return[(s:="minus "(q<0)+s+U[a==1!=r>I:b==1])[0].title()+s[1:].strip(),(s+r)(a>0)][r>I]
zahl=Z

mortal grotto
#

You really did golf that, amazing

#

Sadly, this fails

#

(p>1) and u%2==1 produces "arde" instead of "arden" and
(p<2) and u%2==1 produces just "ar"

fleet bridge
#

Challenge: get all possible SyntaxWarning kinds without looking into cpython repo.
I will start:```py

1) * object is not callable; perhaps you missed a comma?

()()
<stdin>:1: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma?

<stdin>:1: SyntaxWarning: 'list' object is not callable; perhaps you missed a comma?
''()
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?
...()
<stdin>:1: SyntaxWarning: 'ellipsis' object is not callable; perhaps you missed a comma?
{}()
<stdin>:1: SyntaxWarning: 'dict' object is not callable; perhaps you missed a comma?
{()}()
<stdin>:1: SyntaxWarning: 'set' object is not callable; perhaps you missed a comma?
1()
<stdin>:1: SyntaxWarning: 'int' object is not callable; perhaps you missed a comma?
1.()
<stdin>:1: SyntaxWarning: 'float' object is not callable; perhaps you missed a comma?
1j()
<stdin>:1: SyntaxWarning: 'complex' object is not callable; perhaps you missed a comma?
True()
<stdin>:1: SyntaxWarning: 'bool' object is not callable; perhaps you missed a comma?
b''()
<stdin>:1: SyntaxWarning: 'bytes' object is not callable; perhaps you missed a comma?

2) * object is not subscriptable; perhaps you missed a comma?

True[1]
<stdin>:1: SyntaxWarning: 'bool' object is not subscriptable; perhaps you missed a comma?
1[2]
<stdin>:1: SyntaxWarning: 'int' object is not subscriptable; perhaps you missed a comma?
...[1]
<stdin>:1: SyntaxWarning: 'ellipsis' object is not subscriptable; perhaps you missed a comma?
...[...]
<stdin>:1: SyntaxWarning: 'ellipsis' object is not subscriptable; perhaps you missed a comma?

3) * indices must be integers or slices, not *; perhaps you missed a comma?

[][[]]
<stdin>:1: SyntaxWarning: list indices must be integers or slices, not list; perhaps you missed a comma?
()[()]
<stdin>:1: SyntaxWarning: tuple indices must be integers or slices, not tuple; perhaps you missed a comma?

flint hollow
#

better challenge: get all the warnings in a single line

fleet bridge
#

💀 ```py

''(),''(),''(),''(),''(),''(),''(),''(),''(),''(),''(),''(),''(),
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?
<stdin>:1: SyntaxWarning: 'str' object is not callable; perhaps you missed a comma?

quartz wave
#

you could do this to anything tbh ```pycon

()[...]
<stdin>:1: SyntaxWarning: tuple indices must be integers or slices, not ellipsis; perhaps you missed a comma?
()[1.]
<stdin>:1: SyntaxWarning: tuple indices must be integers or slices, not float; perhaps you missed a comma?
()[{}]
<stdin>:1: SyntaxWarning: tuple indices must be integers or slices, not dict; perhaps you missed a comma?

languid hare
#

rather annoyingly the int hash modulus is slightly smaller than the true range of hashes (on a 64 bit width hash at least)

#

so on my IDLE python (32 bit width) my script is able to output this:

() 750394483
(-1099103383,) 750394483
(-1099103383, 1675715659) 750394483
(-1099103383, 1675715659, 1507789696) 750394483
(-1099103383, 1675715659, 1507789696, 1437192654) 750394483
(-1099103383, 1675715659, 1507789696, 1437192654, 1048715906) 750394483
(-1099103383, 1675715659, 1507789696, 1437192654, 1048715906, -1487580131) 750394483
(-1099103383, 1675715659, 1507789696, 1437192654, 1048715906, -1487580131, -639358311) 750394483
(-1099103383, 1675715659, 1507789696, 1437192654, 1048715906, -1487580131, -639358311, 518373792) 750394483
(-1099103383, 1675715659, 1507789696, 1437192654, 1048715906, -1487580131, -639358311, 518373792, 129897044) 750394483
(-1099103383, 1675715659, 1507789696, 1437192654, 1048715906, -1487580131, -639358311, 518373792, 129897044, 1888568303) 750394483

and so on

#

each of the tuples has the same hash as the empty tuple

#

but on a 64 bit width:

() 5740354900026072187
(1778577755476246539,) 5740354900026072187
(1778577755476246539, 654455456954384049) 5740354900026072187
(1778577755476246539, 654455456954384049, -930367412484010356) 5740354900026072187
(1778577755476246539, 654455456954384049, -930367412484010356, -2054489711005872846) 5740354900026072187
(1778577755476246539, 654455456954384049, -930367412484010356, -2054489711005872846, -3639312580444267251) 8877380592658120617
(1778577755476246539, 654455456954384049, -930367412484010356, -2054489711005872846, -3639312580444267251, 681202749096285504) 8877380592658120617
fleet bridge
# fleet bridge Challenge: get all possible SyntaxWarning kinds without looking into cpython rep...
# initial examples:
>>> ()()
<stdin>:1: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma?
>>> 0[0]
<stdin>:1: SyntaxWarning: 'int' object is not subscriptable; perhaps you missed a comma?
>>> [][[]]
<stdin>:1: SyntaxWarning: list indices must be integers or slices, not list; perhaps you missed a comma?
# @<class 'cereal'> (fast):
>>> 5or[]
<stdin>:1: SyntaxWarning: invalid decimal literal
fleet bridge
languid hare
languid hare
fleet bridge
#
>>> class H:
...  def __hash__(self): return 2**61
...
>>> H()
<H at 0x001FDFF56A1D0>
>>> hash(H())
2_305_843_009_213_693_952
>>> 2**61
2_305_843_009_213_693_952
>>> hash(2**61)
1
>>> x = 2**61
>>> hash(x)
1
>>> sys.hash_info.width
64
``` what is happening? i dont understand
#

is __hash__ wrapper cutting value to only 32 bits?

#

or something

#

im blind, its other way around
int.__hash__ for some reason cuts value to 32 bits?

languid hare
#

https://docs.python.org/3/library/stdtypes.html#hashing-of-numeric-types

Essentially, this function is given by reduction modulo P for a fixed prime P. The value of P is made available to Python as the modulus attribute of sys.hash_info.

CPython implementation detail: Currently, the prime used is P = 2**31 - 1 on machines with 32-bit C longs and P = 2**61 - 1 on machines with 64-bit C longs.

fleet bridge
#

ah, that is weird

#

so there is two limits:

  • 64 bits for all hashes
  • 61 bits for numeric hashes
languid hare
#

mhm

#

!e

x = (2,)
print(hash(x))
print(hash(hash(x)))
night quarryBOT
#

@languid hare :white_check_mark: Your 3.11 eval job has completed with return code 0.

001 | 6909455589863252355
002 | 2297769571435864453
fleet bridge
#

that implies that number's hashes can have 8 (2**3) times less different values, so hash collisions on numbers are 8 times more likely

#
>>> x = (2,); (x,hash(x),hash(hash(x)))
((2,), 6_909_455_589_863_252_355, 2_297_769_571_435_864_453)
>>> x = (1,); (x,hash(x),hash(hash(x)))
((1,), -6_644_214_454_873_602_895, -2_032_528_436_446_214_993)
>>> x = (0,); (x,hash(x),hash(hash(x)))
((0,), -8_753_497_827_991_233_192, -1_835_968_800_350_151_339)
>>> x = (3,); (x,hash(x),hash(hash(x)))
((3,), -5_029_647_727_744_300_836, -417_961_709_316_912_934)
>>> x = (4,); (x,hash(x),hash(hash(x)))
((4,), 8_524_022_316_992_554_414, 1_606_493_289_351_472_561)
>>> x = (5,); (x,hash(x),hash(hash(x)))
((5,), -7_813_438_383_599_366_905, -895_909_355_958_285_052)
>>> x = (6,); (x,hash(x),hash(hash(x)))
((6,), -1_305_797_627_497_368_480, -1_305_797_627_497_368_480)
``` only for 1/8 of tuples of kind `(n,)` this would be true: `hash(x) == hash(hash(x))`
#

!e ```py
n = 10**6
print(sum(hash((n,)) == hash(hash((n,))) for n in range(n))/n)

night quarryBOT
#

@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.

0.250033
fleet bridge
#

it is 1/4, not 1/8...

languid hare
#

hmm

#

id guess something about the sign bit

fleet bridge
#

yeah, there is some off-by-one error in my calculations

languid hare
#

For a complex number z, the hash values of the real and imaginary parts are combined by computing hash(z.real) + sys.hash_info.imag * hash(z.imag), reduced modulo 2**sys.hash_info.width so that it lies in range(-2**(sys.hash_info.width - 1), 2**(sys.hash_info.width - 1)). Again, if the result is -1, it’s replaced with -2.

#

hmm i might be able to bypass it with complex

#

the components would be subject to the 61 bit limit but the overall hash is 64

#

weird

#

!e

import sys
print(sys.hash_info.imag)
night quarryBOT
#

@languid hare :white_check_mark: Your 3.11 eval job has completed with return code 0.

1000003
languid hare
#

neat, another prime

fleet bridge
#

at some day cpython will use all primes for some calculations...

#

sys.hash_info.inf = 314159 is prime too

languid hare
#

in other news ive just learnt of a float method from the hash docs

#

!e

from math import pi
num, denom = pi.as_integer_ratio()
print(f"pi = {num}/{denom}")
night quarryBOT
#

@languid hare :white_check_mark: Your 3.11 eval job has completed with return code 0.

pi = 884279719003555/281474976710656
languid hare
#

pi is rational, who knew

night quarryBOT
#

@languid hare :white_check_mark: Your 3.11 eval job has completed with return code 0.

001 | 5
002 | 4
003 | 3
fleet bridge
#

makes sense

languid hare
#

!e

class H:
  def __init__(self, v):
    self.v = v
  def __hash__(self):
    return self.v

print(hash(H(2**63)))
print(hash(H(2**63-1)))
print(hash(H(2**63+1)))
night quarryBOT
#

@languid hare :white_check_mark: Your 3.11 eval job has completed with return code 0.

001 | 4
002 | 9223372036854775807
003 | 5
fleet bridge
languid hare
#

@maiden blaze send help

maiden blaze
#

what are you goons up to today

versed eagle
#

cpython hashes ints weirdly

languid hare
#

mm might be something about the internal representation

#

2^63-1 is the largest number that can be stored in 8 bytes, after that the python long object needs another 8 bytes
(hypothesis. ive no idea what the internal representation looks like :p)

maiden blaze
#

is there a similar discont near 2**31

#

huh
doesnt it use 2**30 as the base

languid hare
#

!e

class H:
  def __init__(self, v):
    self.v = v
  def __hash__(self):
    return self.v

print(hash(H(2**31-1)))
print(hash(H(2**31)))
print(hash(H(2**31+1)))
night quarryBOT
#

@languid hare :white_check_mark: Your 3.11 eval job has completed with return code 0.

001 | 2147483647
002 | 2147483648
003 | 2147483649
languid hare
versed eagle
#

its been a while since i read the source for longobject

night quarryBOT
#

Objects/longobject.c line 3297

long_hash(PyLongObject *v)```
languid hare
fleet bridge
#

time to unwrap my 32-bit python 3.10 🥳

#
Python 3.10.0 (tags/v3.10.0:b494f59, Oct  4 2021, 18:46:30) [MSC v.1929 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class H:
...  def __init__(self, v):
...   self.v = v
...  def __hash__(self):
...   return self.v
...
>>> print(hash(H(2**31-1)))
2147483647
>>> print(hash(H(2**31)))
1
>>> print(hash(H(2**31+1)))
2
>>> import sys
>>> sys.hash_info
sys.hash_info(width=32, modulus=2147483647, inf=314159, nan=0, imag=1000003, algorithm='siphash24', hash_bits=64, seed_bits=128, cutoff=0)
languid hare
#

!e

import sys
print(sys.hash_info)
night quarryBOT
#

@languid hare :white_check_mark: Your 3.11 eval job has completed with return code 0.

sys.hash_info(width=64, modulus=2305843009213693951, inf=314159, nan=0, imag=1000003, algorithm='siphash13', hash_bits=64, seed_bits=128, cutoff=0)
quartz wave
#

also python arbitrary length integers only either fit 4 or 2 bytes

versed eagle
quartz wave
languid hare
#

ugh i just wanted to make tuples that cant be put into a dict

#

now i gotta deal with this mess

quartz wave
night quarryBOT
#

Objects/typeobject.c lines 8758 to 8770

/* Transform the PyLong `​res`​ to a Py_hash_t `​h`​.  For an existing
   hashable Python object x, hash(x) will always lie within the range of
   Py_hash_t.  Therefore our transformation must preserve values that
   already lie within this range, to ensure that if x.__hash__() returns
   hash(y) then hash(x) == hash(y). */
h = PyLong_AsSsize_t(res);
if (h == -1 && PyErr_Occurred()) {
    /* res was not within the range of a Py_hash_t, so we're free to
       use any sufficiently bit-mixing transformation;
       long.__hash__ will do nicely. */
    PyErr_Clear();
    h = PyLong_Type.tp_hash(res);
}```
languid hare
#

mm

#

!e

tuples = [(4, -959703335196834730), (7, -1649852810609714918), (8, 403413395588177987), (11, 28542440325690448), (12, 2081808646523583353), (14, -661607035087189740), (15, 1391659171110703165), (18, 1016788215848215626), (42, -824914778392737540), (45, -1515064253805617728), (46, 538201952392275177)]

for t in tuples:
    print(t, "=>", hash(t))
night quarryBOT
#

@languid hare :white_check_mark: Your 3.11 eval job has completed with return code 0.

001 | (4, -959703335196834730) => 123456789
002 | (7, -1649852810609714918) => 123456789
003 | (8, 403413395588177987) => 123456789
004 | (11, 28542440325690448) => 123456789
005 | (12, 2081808646523583353) => 123456789
006 | (14, -661607035087189740) => 123456789
007 | (15, 1391659171110703165) => 123456789
008 | (18, 1016788215848215626) => 123456789
009 | (42, -824914778392737540) => 123456789
010 | (45, -1515064253805617728) => 123456789
011 | (46, 538201952392275177) => 123456789
... (truncated - too many lines)

Full output: https://paste.pythondiscord.com/IQ47TGCNC5QO4HVN72Z7MWGZBM

languid hare
#

partially working

versed eagle
#

8 bytes fits into 2 32-bit integers no?

#

unless its preallocating to have more space than it needs, which i dont think it does

quartz wave
#

there's always an extra 2 bytes not used in the digits (1 byte for 16-bit digits) and i have no idea why

versed eagle
#

python uses uint32_t for 64 bit systems

fleet bridge
languid hare
#

mhm

quartz wave
#

since python 3.11 or 3.12

versed eagle
#

oh

languid hare
#

my last step is finding an element with a given hash, which at the moment i assume to be the hash itself.
however that only works 1/4 of the time as we've seen

quartz wave
versed eagle
#

last i checked it was a uint16_t for 32 bit systems

quartz wave
#

but they made that architecture-independent and defaulted to uint32_t for both 32-bit and 64-bit systems

versed eagle
#

ig i need to go read the newest version then

quartz wave
#

!e ```py
from ctypes import c_uint
n=2**63-1;print([(c_uint3).from_address(id(n)+int.basicsize)])

night quarryBOT
#

@quartz wave :white_check_mark: Your 3.11 eval job has completed with return code 0.

[1073741823, 1073741823, 7]
fleet bridge
#
>>> hex(1073741823)
'0x3fffffff'
quartz wave
#

it's 2**30-1

#

the maximum number that fits in range(2**30)

versed eagle
#

does that not just waste 2 bits

#

or do they use those for something else?

quartz wave
#

maybe try to avoid overflow with signed integers

versed eagle
#

so basically a carry register?

quartz wave
#

specifically

long_hash() requires that PyLong_SHIFT is strictly less than the number of bits in an unsigned long, as do the PyLong <-> long (or unsigned long) conversion functions

#

and

the marshal code currently expects that PyLong_SHIFT is a multiple of 15

plush halo
#

here's something interesting to run on xonsh

#
espeak @(' '.join(random.choices([l + 'oink' for l in alpha], k=100)))
languid hare
sonic birch
#

Just thinking.. can it be somehow useful?

from functools import partial as part

@part(part, b=5)
def foo(a, b):
  print(a, b)
fleet bridge
#

My brain is not smart enough to understand this

astral rover
#
from functools import partial as part

def foo(a, b):
  print(a, b)
foo = part(foo)(part(b=5))```
#

yeah that doesnt even help, i can guess the meaning but lol

fleet bridge
#

foo=print does the same

#

So:
foo = part(print)(part(b=5))

#

Oh, wait, no. Print doesn't have b kwarg

#

Nvm

astral rover
#

is that not the correct deco order?

quartz wave
#
from functools import partial as part

@part(part, b=5)
def foo(a, b):
  print(a, b)

foo = part(part, b=5)(foo) # = part(foo, b=5)
astral rover
#

oh yep

#

that makes more sense

languid hare
#

lol

#

on average itll need 4 nested tuples to achieve a target hash

#

since its only within range 1/4 of the time

sonic birch
# sonic birch Just thinking.. can it be somehow useful? ```py from functools import partial as...

The only use case I can see so far is - expensive computation, like:

from functools import partial as part

def long_compute():
  # some expensive work 

@part(part, b=long_compute())
def foo(a, b):
  # do something with a and b

If you want b to be initialized before the function call, but you don't want somebody outside to be able to change b after initialized

UDP:
Examples:
1.

b=...#bad, b can be changed from outside
def foo(a):
  # use a, b
def foo(a, b=...): # bad, b can be changed by caller
  # use a, b
def foo(a):
  # b = ... # bad, b will be re-init each time function is called. Not good for long init
languid hare
#

that's a nice use

quartz wave
night quarryBOT
#

@quartz wave :white_check_mark: Your 3.11 eval job has completed with return code 0.

9
quartz wave
#

it's like using a default value

#

now if partial() was just ```py
def partial(*args, **kwargs):
f, *args = args
return lambda *a, **k: f(*args, *a, **kwargs, **k)

languid hare
#

playing with more hashes, here's a "nice" hash that works on 32 and 64 bit

#

these are all just an application of the chinese remainder theorem

#

still fun

distant salmon
#

Speaking about hash hacks. Here is how to create a ddos attack for dict

#

!e

def dict_ddos(n):
    pow2 = 1
    while pow2 < 2 * n: pow2 *= 2

    # Fill up all spots that 0 wants to use
    A = [pow2]
    i = 1
    for _ in range(n // 2):
        A.append(i)
        i = (i * 5 + 1) % pow2

    # Spam 0s
    A += [0] * (n - len(A))
    return A

B = {}
for a in dict_ddos(10**5):
    B[a] = 1
night quarryBOT
#

@distant salmon :warning: Your 3.11 eval job timed out or ran out of memory.

[No output]
distant salmon
#

This doesn't make use of hash collisions. Instead what I've done is that I've filled up all the spots that 0 "wants" in the dict. After doing that, checking if 0 is a key in the dict takes O(n) time.

#

The numbers used here are fairly small, around 2 * n. This is a lot smaller than what you get using multiples of 2^61 - 1.

mortal grotto
# quartz wave -2b ```py *A,L,M,J,K,N,O,P,B,D,E,G,g,k="drei vier fünf sech sieb acht neun zehn ...

Btw, in case you are interested, I reduced the code to 1018 bytes now: ```py
A,L,M,J,N,O,P,B,D,E,G,g,k="drei vier fünf sech sieb acht neun zehn elf zwölf sept quin ns ing okt qua mn mx dr non tre en".split()
F,n,o,C,U,m,H,j="ego sanz"
I,S="",10;Q=S
S;T,l=QS,J,J,J,H,H,D,I,I
Y=["null","ein","zwei"]+AT
Y[6]+=U;Y[7]+=k
def Z(q,r=I):
a=abs(q);d,u=a//T,2;s=Y[b:=a%Q]
(a<S)or Z(d%T,"tausend ")+Z(a%T//Q,"hundert")+[Z(a%S,"und")+["zwan",A][b//S-2]+"zß"[b//S==3]+"ig",Y[b](b>0)+A[7](b>12)][b<20]
while d:
V,v=u//2,I
while V:c,e=V//S%S,V//Q%S;h,z=[I,"un","duo",g,P+"ttuor",M,U+F,L+F,O+o,"nove",I,I,I,U,I,I,"x",B,I,B][V%S::S];f,y=[[I,H,"ms",l,"dezi","viginti","tri",P+E+m,M+P,"sexa",L+"ua",O+o,G+m],i:=[I,"nxs",H,l,j,"duz",g+j,P+E+N,M+n,"sesz",L+N,O+N,G+n][e:]][c<1][c::S];v=([H,"mb","tr",P+E,M+"t","sext",L,O,G][V%T:],(h+I.join({z}&{f})+y+"ginta"(c>2)+i[S](c>0)+"enti"
(e>0))[:-1])[0]+"illi"+v;V//=T
d//=T;s=Z(p:=d%T,F*(p<2)+C+v.title()+[o+H,"arde"][u%2]+k[u%2:](p>1)+C)+s;u+=1
return[(s:="minus "
(q<0)+s+U[a==1!=r>I:b==1])[0].title()+s[1:].strip(),(s+r)*(a>0)][r>I]
zahl=Z

#

aiming for sub 1k

modern haven
#

Thats python code!?

mortal grotto
#

Yes, golfed

#

To be as short as possible

finite blaze
modern haven
#

Very

finite blaze
#

ah alright

modern haven
#

New to programming too

finite blaze
#

👍

mortal grotto
#

Have function "zahl" which accepts any positive/negative integer and returns the worded version of the number in German following all the grammar

finite blaze
#

ah i see

mortal grotto
#

So

zahl(1) == "Eins"
zahl(-10) == "Minus zehn"
zahl(859785271795) == "Achthundertneunundfünfzig Milliarden siebenhundertfünfundachtzig Millionen zweihunderteinundsiebzigtausend siebenhundertfünfundneunzig"

:D

finite blaze
#

is the strip() even needed?

mortal grotto
#

Yes, I still haven't figured out how to remove the spaces at the end

#

the "tausend " has a space, unit naming puts a space between each unit, so thinking about special cases actually makes up more bytes than just using str.strip()

#

Nvm

#

Welcome to Code Golf!

stark granite
#

i did some cursed stuff

#

but not on such scale

#

like worst thing i did was this:

#

pls hold

finite blaze
#
*A,L,M,J,N,O,P,B,D,E,G,g,k=[*"drei vier fünf sech sieb acht neun zehn elf zwölf sept quin ns ing okt qua mn mx dr non tre en"]
F,n,o,C,U,m,H,j="ego sanz"
I,S="",10;Q=S*S;T,*l=Q*S,J,J,J,H,H,D,I,I
Y=["null","ein","zwei"]+A*T
Y[6]+=U;Y[7]+=k
def Z(q,r=I):
 a=abs(q);d,u=a//T,2;s=Y[b:=a%Q]*(a<S)or Z(d%T,"tausend ")+Z(a%T//Q,"hundert")+[Z(a%S,"und")+["zwan",*A][b//S-2]+"zß"[b//S==3]+"ig",Y[b]*(b>0)+A[7]*(b>12)][b<20]
 while d:
  V,v=u//2,I
  while V:c,e=V//S%S,V//Q%S;h,z=[I,"un","duo",g,P+"ttuor",M,U+F,L+F,O+o,"nove",I,I,I,U,I,I,"x",B,I,B][V%S::S];f,y=[[I,H,"ms",*l,"dezi","viginti","tri",P+E+m,M+P,"sexa",L+"ua",O+o,G+m],i:=[I,"nxs",H,*l,j,"duz",g+j,P+E+N,M+n,"sesz",L+N,O+N,G+n][e:]][c<1][c::S];v=(*[H,*"mb","tr",P+E,M+"t","sext",L,O,G][V%T:],(h+I.join({*z}&{*f})+y+"ginta"*(c>2)+i[S]*(c>0)+"enti"*(e>0))[:-1])[0]+"illi"+v;V//=T
  d//=T;s=Z(p:=d%T,F*(p<2)+C+v.title()+[o+H,"arde"][u%2]+k[u%2:]*(p>1)+C)+s;u+=1
 return[(s:="minus "*(q<0)+s+U[a==1!=r>I:b==1])[0].title()+s[1:].strip(),(s+r)*(a>0)][r>I]
zahl=Z
#

does this work?

#

@mortal grotto

mortal grotto
#

Lemme check

stark granite
#
print('\n'*int(o:=(b:=int(input("Pyramid base size: ")))%2==1)+'\n'.join((s:=' '*(b//2-i))+'#'*int(o)+'#'*i*2+s for i in range(b//2+1)))
#

tho i know how to improve it

#

and yes, i wanted it to be a single statement

mortal grotto
mortal grotto
stark granite
mortal grotto
finite blaze
#

@mortal grotto can u give me some test cases?

#

numbers with expected responses

#

nvm ;p

keen thicket
keen thicket
#

somehow lost a c at the end

#

should work now

#

i'd be curious about how fast dicts fill up compared to lists

mortal grotto
finite blaze
#

yeah just did that

mortal grotto
#

👍

distant salmon
#

I was talking about a series of integers which if used as keys for a dict will run super slow

keen thicket
#

yeah, it's running slow because you allocated a ton of extra data structures due to hash collisions

distant salmon
#

This is only a slow down in time due to dict being fragile

keen thicket
#

and why is dict fragile? because when the keys collide it requires extra data structures being used

#

turning something that should be O(1) to O(number of collisions)

#

not like python data structures, but the underlying dict implementation is allocating extra data structures for every collision

distant salmon
keen thicket
#

I didn't say data, I said data structures

distant salmon
#

you said allocating, there is 0 allocation going on

keen thicket
#

there absolutely is allocation happening it is just hidden from you

#

this obviously depends on the exact implementation of the dictionary but hash collisions always cause a degradation in performance because it means you have to figure out which of the collided keys has the value you're looking for

#

in most implementations this is done by allocating a linked list for that entry in the hash table, and then searching that linked list

distant salmon
#

Here is a slightly simplified explanation of how dicts in Python work:
Dicts internally store everything in a power of 2 sized list (at least twice the size of the numbers of elements stored in the dict). If you use key = x then it first checks at index x. If that is occupied by something else than x then it checks index 5 * x + 1, and if that is occupied it checks index 5 * (5 * x + 1) + 1...

keen thicket
#

yeah and if they're all occupied it has to allocate new lists

distant salmon
#

They are never all occupied

keen thicket
#

yeah because python allocates new data structures to hold them

distant salmon
#

The thing that can happen is that it takes ages to find the spot where x is stored

keen thicket
#

yes that is because of hash collisions

#

which is what I'm saying

distant salmon
#

You are talking about "python allocates new data structures". I dont get what you mean by that.

keen thicket
#

either you turn each index into a linked list, or you allocate a new list to hold the overflow, either way you have to grow the memory size of the dict

#

The Python interpreter has to allocate new C data structures to hold this stuff

distant salmon
keen thicket
#

because it's the expected behavior for dictionaries that they will overflow at some point

#

there are Python lists (which are I think what you're referring to), but I was referring to the underlying data structures that are implemented in C

#

the reason you don't see these allocations is because Python's garbage collector etc handle this for you

distant salmon
keen thicket
#

it will always find an empty space because Python automatically allocates new space for it once you exhaust the existing space

distant salmon
#

!e

def dict_ddos_0(n):
    pow2 = 1
    while pow2 < 2 * n: pow2 *= 2

    # Fill up all spots that 0 wants to use
    A = [pow2]
    i = 1
    for _ in range(n - 1):
        A.append(i)
        i = (i * 5 + 1) % pow2
    return A

# This part runs fast
B = {}
for a in dict_ddos_0(10**5):
    B[a] = 1

# Make Python check for 0 in the dict which will take ages since all spots 0 
# since the first 10^5 spaces where 0 could be at is occupied
for _ in range(10**5):
  0 in B
night quarryBOT
#

@distant salmon :warning: Your 3.11 eval job timed out or ran out of memory.

[No output]
distant salmon
#

See here, absolutely no allocation is going on at all

#

The expensive part is just checking if 0 is in the dict

#

This is not a memory ddos, it is purely a time ddos

keen thicket
#

oh then you should write some code that actually times it

#

because right now it looks like you're just confirming the fact that, yes, when you have hash collisions it does take longer

#

that is part of the implementation notes though

#

"But catering to unusual cases should not slow the usual ones, so we just take
the last i bits anyway. It's up to collision resolution to do the rest. If
we usually find the key we're looking for on the first try (and, it turns
out, we usually do -- the table load factor is kept under 2/3, so the odds
are solidly in our favor), then it makes best sense to keep the initial index
computation dirt cheap."

#

This is in the comments on the C file I sent earlier

distant salmon
#

I'm sure that the people that made dict knows about this "attack"

#

But I'm not so sure most Python users know about it

keen thicket
#

Well, this is the esoteric python channel which generally involves deep knowledge of CPython's implementation

#

But the asymptotically bad performance once hash collisions are induced is one of the main drawbacks of most dictionary implementation

distant salmon
#

For example I think that using strings as keys for a dictionary is safe cause their hash is randomized

keen thicket
#

"Major subtleties ahead: Most hash schemes depend on having a "good" hash
function, in the sense of simulating randomness. Python doesn't: its most
important hash functions (for strings and ints) are very regular in common cases"

#

Python's hashes are not randomized

#

From the same C file I sent above

distant salmon
#

and I really wish ints hashes were randomized too

keen thicket
#

....

#

did you read the whole quote

#

because it specifically mentions strings by name

#

and says they are not random

distant salmon
#

I'm fairly certain that each time you start up Python it rerandomized the hashes of strings.

#

!e

print(hash('banana'))
night quarryBOT
#

@distant salmon :white_check_mark: Your 3.11 eval job has completed with return code 0.

-7126866263746545998
distant salmon
#

!e

print(hash('banana'))
night quarryBOT
#

@distant salmon :white_check_mark: Your 3.11 eval job has completed with return code 0.

-2654407998515714908
keen thicket
#

yeah when you restart the interpreter it obviously changes a lot of stuff

stark granite
distant salmon
#

and then people had issues getting with ddosed with string keys

#

So in Python3 they changed it

#

So now each time you start Python it rerandomizes it

stark granite
distant salmon
stark granite
#

even worse

distant salmon
#

This is the source code for dict

#

When you try to look up if some key x is in a dict

stark granite
#

oh wait

#

that is all?

distant salmon
#

yes

stark granite
#

i thought it would be a bit more complex

distant salmon
#

I thought so too once, but no, this is it

stark granite
keen thicket
#

The Python3 change appears to just be making the hash inconsistent across interpreter restarts, but in that case you would also lose the entire hash table

#

As long as the hashes are consistent during the running of the interpreter then the hash table works fine

#

if you want it to persist you would have to use a different hash implementation

#

like md5

#

the existence of a hash seed that changes hash values across program executions does not mean in any way that the hash is now somehow internally random

distant salmon
stark granite
distant salmon
#

So you likely have to walk around for a bit until you either find the spot where x is, or an empty spot (meaning x is not in the dict)

stark granite
#

gotcha

stark granite
distant salmon
#

and then I repeatedly asked if 0 is in the dict

stark granite
#

it sounds way less in a non-exponential form lol

#

100 000 is not that big actually

#

(for modern PCs)

distant salmon
#

That is fairly slow

stark granite
keen thicket
#

can you add timing code so we can actually see how much slower

distant salmon
stark granite
#

10 000 000 000

#

10 billion

#

ok that is quite some number

distant salmon
keen thicket
mortal grotto
#
def dict_ddos_0(n):
    pow2 = 1
    while pow2 < 2 * n: pow2 *= 2

    # Fill up all spots that 0 wants to use
    A = [pow2]
    i = 1
    for _ in range(n - 1):
        yield i
        i = (i * 5 + 1) % pow2

# This part runs fast
B = {}
for a in dict_ddos_0(10**5):
    B[a] = 1

# Make Python check for 0 in the dict which will take ages since all spots 0 
# since the first 10^5 spaces where 0 could be at is occupied
for _ in range(10**5):
  0 in B
stark granite
keen thicket
stark granite
#

(10⁵)³ is stupidly big

#

like

#

1 000 000 000 000 000

mortal grotto
#

10¹⁵

keen thicket
#

e15

stark granite
#

and (10⁵)⁴ is even more

#

100 000 000 000 000 000 000

mortal grotto
#

10²⁰

distant salmon
#

The pow2 takes the 0 index spot, so it is very important that it is yielded

stark granite
mortal grotto
mortal grotto
#

Math enthusiast

#

Idk, wdym

stark granite
#

i just use compose key (linux thingy)

distant salmon
mortal grotto
#

Phone

stark granite
#

so ³ is COMPOSE + ^ + 3

stark granite
#

that works too lol

mortal grotto
#

Google keyboard

keen thicket
stark granite
#

(android is based on linux, afterall)

mortal grotto
#

Yes, but also actually a linux user

#

Manjaro on my PC

keen thicket
#

it's linux all the way down....

stark granite
#

sad arch user

stark granite
mortal grotto
keen thicket
distant salmon
keen thicket
#

"Turtles all the way down" is an expression of the problem of infinite regress. The saying alludes to the mythological idea of a World Turtle that supports a flat Earth on its back. It suggests that this turtle rests on the back of an even larger turtle, which itself is part of a column of increasingly larger turtles that continues indefinitely....

distant salmon
#

But if you really wanna know. On my computer 10^5 case takes 20 s, and 10^6 case takes 2000s

keen thicket
mortal grotto
keen thicket
stark granite
keen thicket
#

you need to make a graph

distant salmon
keen thicket
#

there are like easily 10 different ways the setup of the code and what is cached etc could influence this

mortal grotto
#

He speaks about it theoretically

keen thicket
keen thicket
distant salmon
keen thicket
stark granite
#

as you can see it grows BIG and FAST

#

not factorial level

keen thicket
#

yeah I'm aware of what it looks like

stark granite
#

but really still bad

keen thicket
#

I'm saying that for this code, I haven't seen a graph that looks like that

stark granite
versed eagle
distant salmon
keen thicket
#

I took way too many data structures classes in undergrad to assume that you can estimate time complexity just by reading real world code

stark granite
versed eagle
stark granite
#

PLS PING ME IN REPLES

#

:(

distant salmon
#

I said instant cause the all of the insertions take O(n) time, while all of the lookups take O(n^2) time

versed eagle
keen thicket
distant salmon
#

I also know from past experience that creating hashtables of size 10^5 takes almost no time at all (significantly less time than 1 s)

stark granite
#

tho nothing beats O(n!)

mortal grotto
#

There is always something that beats something else

keen thicket
#

hahaha

stark granite
#

i remember 3↑↑↑3 is EXTERMELY large

#

so it is like

versed eagle
stark granite
#

3↑3 is (((3³)³)³

#

iirc

versed eagle
#

love it

distant salmon
keen thicket
stark granite
keen thicket
#

If you can't make the graph, that's fine I can do it for you

distant salmon
keen thicket
stark granite
keen thicket
#

Isn't it your job to justify your own work?

distant salmon
versed eagle
stark granite
keen thicket
keen thicket
#

but you're right, give me like 15 minutes and I'll show you a graph of your code

stark granite
#

i thoguht it was like higher order of power

keen thicket
#

and then we can talk about what that graph looks like

stark granite
#

like power is the higher order of multiplication

versed eagle
#

the amount of arrows is the amount of iterations of the previous amount of operations

stark granite
#

like multiplication is higher order of addition

versed eagle
stark granite
#

imagine actually creating an algo with such big o

versed eagle
#

thats only with 2 arrows also

stark granite
#

i kinda want to write my custom biginteger and bigfloat implementations (as well as bigfixpoint)

versed eagle
#

for what language?

stark granite
#

rust :)

versed eagle
#

ah

stark granite
#

like, to be able to see

#

is it even possible to store such large number

#

actually

#

if the number is larger than this

#

it shouldnt be possible

#

as, it literally doesnt fit

versed eagle
# stark granite yeah ._.

In mathematics, Knuth's up-arrow notation is a method of notation for very large integers, introduced by Donald Knuth in 1976.In his 1947 paper, R. L. Goodstein introduced the specific sequence of operations that are now called hyperoperations. Goodstein also suggested the Greek names tetration, pentation, etc., for the extended operations beyon...

stark granite
#

(at least for 64-bit machines)

stark granite
versed eagle
#

yeah

stark granite
#

like, 6D or 7D stuff

#

a cude inside of a cude inside of a cude inside of a cude inside of a cude inside of a cude inside of a cude inside of a cube.

mortal grotto
#

Stumbled upon Graham's number, when reading that Wiki

stark granite
#

is it it 3↑↑↑3?

mortal grotto
#

G_64, where G_1 = 3^^^3 and G_n = 3^(^G_(n-1)) 3

keen thicket
#

Ok, I'm back with a graph @distant salmon

mortal grotto
#

Embed fail

#

Why tho?

keen thicket
#

I'm not sure, give me one second

#

timing code: ```python
def dict_ddos_0(n):
pow2 = 1
while pow2 < 2 * n: pow2 *= 2

# Fill up all spots that 0 wants to use
A = [pow2]
i = 1
for _ in range(n - 1):
    yield i
    i = (i * 5 + 1) % pow2

def insert(size):
d = dict_ddos_0(size)
# This part runs fast
B = {}
for a in d:
B[a] = 1
return d

Make Python check for 0 in the dict which will take ages since all spots 0

since the first 10^5 spaces where 0 could be at is occupied

def check(d):
for _ in range(10**5):
0 in d

from timeit import timeit
import matplotlib.pyplot as plt
times = []
sizes = [i for i in range(0, 105, 102)]

bisect_left

num_trials = 5
for size in sizes:
d = insert(size)
times.append(timeit(lambda:check(d), number=num_trials))
plt.plot(sizes, times, label="time spent checking")

plt.xlabel('Input Size')
plt.ylabel('Execution Time (s)')
plt.title('Performance vs Input Size')
plt.legend()

plt.show()

mortal grotto
#

You used my version with the bug, lol

keen thicket
versed eagle
mortal grotto
keen thicket
#

ok, running it again with the older code

mortal grotto
#

You should A=[pow2] -> yield pow2

keen thicket
#

OH

#

Ok, I tweaked the timing code and fixed another bug.

#

idk about y'all, but that does not look like an exponential curve.

mortal grotto
#

You should use the same size for checking 0 for when inserting

keen thicket
#

Yeah, that was the extra bug I fixed

#
def dict_ddos_0(n):
    pow2 = 1
    while pow2 < 2 * n: pow2 *= 2

    # Fill up all spots that 0 wants to use
    yield pow2
    i = 1
    for _ in range(n - 1):
        yield i
        i = (i * 5 + 1) % pow2

def insert(size):
    d = dict_ddos_0(size)
    # This part runs fast
    B = {}
    for a in d:
        B[a] = 1
    return d

# Make Python check for 0 in the dict which will take ages since all spots 0
# since the first 10^5 spaces where 0 could be at is occupied
def check(d, size):
    for _ in range(size):
      0 in d


from timeit import timeit
import matplotlib.pyplot as plt
times = []
sizes = [i for i in range(0, 10**10, 10**10//50)]
# bisect_left
num_trials = 3
for size in sizes:
    d = insert(size)
    times.append(timeit(lambda:check(d, size), number=num_trials))
plt.plot(sizes, times, label="time spent checking")

plt.xlabel('Input Size')
plt.ylabel('Execution Time (s)')
plt.title('Performance vs Input Size')
plt.legend()

plt.show()
mortal grotto
#

Wtf

#

Still wrong tho

#

You checking the list

#

Lemme fix that

keen thicket
#

Oh, wait yeah because it's a generator it isn't passing in d correctly to the check function

mortal grotto
#
def dict_ddos_0(n):
    pow2 = 1
    while pow2 < 2 * n: pow2 *= 2

    # Fill up all spots that 0 wants to use
    yield pow2
    i = 1
    for _ in range(n - 1):
        yield i
        i = (i * 5 + 1) % pow2

def insert(size):
    # This part runs fast
    d = {}
    for a in dict_ddos_0(size):
        d[a] = 1
    return d

# Make Python check for 0 in the dict which will take ages since all spots 0
# since the first 10^5 spaces where 0 could be at is occupied
def check(d, size):
    for _ in range(size):
      0 in d


from timeit import timeit
import matplotlib.pyplot as plt
times = []
sizes = [i for i in range(0, 10**10, 10**10//50)]
# bisect_left
num_trials = 3
for size in sizes:
    d = insert(size)
    times.append(timeit(lambda:check(d, size), number=num_trials))
plt.plot(sizes, times, label="time spent checking")

plt.xlabel('Input Size')
plt.ylabel('Execution Time (s)')
plt.title('Performance vs Input Size')
plt.legend()

plt.show()
#

Looks like exp to me

#

I only tried to 10**5

#

4*

keen thicket
#

Yeah I can't try it over 10e5 because it consumes way too much memory

#

But 10e5 is relatively low for estimating asymptotic behavior

#

At least now we have actual graphs to compare, makes it a whole lot easier

#

The fastest algorithm is one which hasn't been profiled yet lol

mortal grotto
#

You can print(size) to see for yourself, that it takes ages

keen thicket
#

that's the question

mortal grotto
#

Looks like that tho

keen thicket
#

the size is increasing exponentially as well

mortal grotto
#

That is what you would expect

mortal grotto
keen thicket
#

You should be able to do that with walrus operators

mortal grotto
#

Would I be able tho? There are multiple expressions in there

keen thicket
#

You can combine all the expressions into a single tuple, and then index it to get the values you want to be the conditions

#

I'm getting a syntax error trying to run your base code though

keen thicket
#

oops, it was indentation because I copy pasted

#

lol

mortal grotto
#

It's py 3.11 btw, but should run in 3.6+ probably

#

doesn't use any super new features

keen thicket
#

walrus operator requires 3.8+ I believe, but yeah

mortal grotto
#

Yes, 3.8 then

keen thicket
#

Actually the syntax error I was getting was related to your usage of the walrus operator inside an indexing expression

#

which isn't allowed IIRC

mortal grotto
#

Idk wym

#

I use 3.11.4 and this code runs perfectly

keen thicket
#

Did you make any changes since you last posted it? I'm on Python 3.9

#

!e

Y = [1, 2, 3, 4, 5]
a = 0
Q = 2
Y[b:=a%Q]
night quarryBOT
#

@keen thicket :warning: Your 3.11 eval job has completed with return code 0.

[No output]
keen thicket
#

oh weird....

#

this is what I get locally with 3.9: File "/Users/juliuspark/one-offs/test.py", line 4 Y[b:=a%Q] ^ SyntaxError: invalid syntax

mortal grotto
#

lemme try on my raspi

mortal grotto
keen thicket
#

found it!

keen thicket
#

looks like it was a feature added in 3.11

mortal grotto
#

Oh, wow

keen thicket
#

yeah locally it works fine with 3.11

#

that's cool though I didn't know that was possible

mortal grotto
#

New to me, because I got into golfing, when 3.11 was already out

keen thicket
#

that will help a lot for my obfuscated stuff

#

ahh I feel that

sick hound
#

I'm coding a 1v1 playground for who solves a python exercise the fastest. Who's up for the challenge ??

keen thicket
#

I am actually running a contest for obfuscated Python code that this would be perfect for

keen thicket
#

I made like one post in this channel a while ago with the mods approval but I haven't been doing a good job of promoting it

sick hound
keen thicket
sick hound
#

I'm coding it on vue js

sick hound
#

I have the exercise generator

#

using leetcode API

mortal grotto
#

ah

sick hound
keen thicket
sick hound
#

Using socket is ideal

#

for the 1v1 functionality

#

I need help though

mortal grotto
#

No time for that sadly

#

There are mesa drivers for Termux 💀

fleet bridge
#

Idea for some cursed stuff: self.__dict__ = globals()

mortal grotto
#

Doing globals().clear() in console somehow unpacks the __builtins__ module, lol

fleet bridge
#

Wdym?

mortal grotto
#
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}
>>> globals().clear()
>>> globals()
{'__builtins__': {'__name__': 'builtins', '__doc__':
...
#

Oh. I did not know, you can actually remove global things. ran __builtins__.clear() and now print() is not accessible

fleet bridge
#

Because __builtins__ can contain two things: module itself or its dict
When interpreter finds global dict with no ref to builtins, it replaces it with builtins dict

fleet bridge
mortal grotto
#

Sounds like fun

#

And it can easily be reset by just quitting the console

#

command line

#

I forgot, how do you call the "command line interpreter"?

fleet bridge
#

Repl

mortal grotto
#

Ah, yes

fleet bridge
#

read-eval-print loop

mortal grotto
#

Yep, just forgot the name

#

Goodbye, I gtg

fleet bridge
night quarryBOT
#

@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.

c
versed eagle
#

that's quite nice

distant salmon
#

Btw here is a fun thing that you can do in Python

#

!e

A = [0,0,0]
i = A[i] = 2
print(A)
night quarryBOT
#

@distant salmon :white_check_mark: Your 3.11 eval job has completed with return code 0.

[0, 0, 2]
distant salmon
#

I have used this for codegolf in the past

fleet bridge
night quarryBOT
#

@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.

[[...]]
distant salmon
#

Here is another weird thing many people probably dont know about

#

Most people know that you can do

#

!e

A = [1,2,3]
B = [4,5,6]

A += B
night quarryBOT
#

@distant salmon :warning: Your 3.11 eval job has completed with return code 0.

[No output]
distant salmon
#

But did you know that this doesn't work

#

!e

A = [1,2,3]
B = [4,5,6]

def f():
  A += B

f()
night quarryBOT
#

@distant salmon :x: Your 3.11 eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "/home/main.py", line 7, in <module>
003 |     f()
004 |   File "/home/main.py", line 5, in f
005 |     A += B
006 |     ^
007 | UnboundLocalError: cannot access local variable 'A' where it is not associated with a value
distant salmon
#

This is the reason that I prefer to use .extend over +=