#esoteric-python
1 messages · Page 53 of 1
it's a lot shorter with a direct golf from the wiki though
def slashes(s):
while s:
m=["",""]
for t in 0,1,2:
while"/"!=s[:1]>"":m[t-1]+=s[z:="\\"==s[0]]*-~-(t<1!=print(end=s[z]));s=s[z+1:]
s=s[1:]
while m[0]in s>"":s=s.replace(*m,1)
wow, kinda like self-modifying Markov algorithms
very cool language
list(s)
[*s]
while(cond):
while cond:
while(s:=...)and m in s:
while(s:=...)*(m in s):
oh, y'all already golfed the hell out of it :-)
m=["",""]->m=[""]*2
true..
oh god it errors
my golf, not including a glob import from build123d:```py
(v:=(a:=Sphere(26)).volume,print((v-18*(v-(a-(l:=lambda m,p:extrude(Pos(Z=m)Circle(4.5),amount=8.5,taper=p))((16,0))-l((24.5,-45))).volume)).00102))
i see golfery but with a bit of spaghettiery
print(((v:=(a:=Sphere(26)).volume)-18*(v-(a-(l:=lambda m,p:extrude(Pos(Z=m)*Circle(4.5),amount=8.5,taper=p))(*(16,0))-l(*(24.5,-45))).volume))*.00102)```-2 chars
Nice, I suspected there was something silly I was doing with the print statement.
!e py import ast print(ast.unparse(ast.parse("f'{a:{{x}}}'")))
:white_check_mark: Your 3.13 eval job has completed with return code 0.
f'{a:{ {x}}}'
a random space appeared, literally unusable 🤐
read the ast.unparse documentation
Warning: The produced code string will not necessarily be equal to the original code that generated the
ast.ASTobject
I think the reason they post it is not because they are not the same but specifically the extra space is annoying to watch for them
i think that space should be there
people might go around thinking f"{a:{{x}}}" has a format string == r"{x}"
why isn't it like that anyways..
WHST
okay now i did too.
god i hate these correlations =へ=
my brain was like
||oh darn thats loss
i got tricked into thinking about it
whats another thing that people get tricked into thinking about?
aha! and then i lost||
because ||loss and losing the game contain the same root work||
meow
meow
sorry
class __Mutex1: ...
class __Mutex2: ...
class IsTemplate(__Mutex2, __Mutex1): ...
class IsUI(__Mutex1, __Mutex2): ...
class Valid1(IsUI): ...
class Valid2(IsTemplate): ...
try:
class Invalid1(IsUI, IsTemplate): ...
raise AssertionError
except TypeError:
...
try:
class Invalid2(IsTemplate, IsUI): ...
raise AssertionError
except TypeError:
...
Does anyone have usecase of this
yeah obviously
but why exactly like that f'{a:{ {x}}}
did someone really write a sentence in pep 8 saying there must be a space in front of nested formats
maybe for obfuscation purposes, by reading the code one would not probably expect a type error raised there
Well, you would know by basic mro
The question is other than obfu
Does anyone know dark magic that edit the subclass of a class
class A:...
class B(A):...
parent = A
child = None
for i in globals().values():
if issubclass(i, parent):
child = i
break
if child:
child.editied_attr = lambda:1```?
assuming your child class exist in globals
No, it might not be in globals, you are only given the class object and some need to somehow manipulate such
Currently looking at rn on editing the class of the object to have the same behaviour by init and init_subclass
oh wait
there is .__subclasses__()
@grave grail
!epy print(int.__subclasses__())
:white_check_mark: Your 3.13 eval job has completed with return code 0.
[<class 'bool'>]
Oh oops I described it wrong
I meant
B(A)
How can I edit B so now it also inherit C, D (or whatever)
And unfortunately B.__mro__ is not an editable attribute
You can assign to .__bases__ (with some restrictions)
Let me check
Hmm, but it unfortunately doesn't work when you have multiple class C(B, A)
...Why?
Wtf
!e
class A:
def __init_subclass__(*args, **kwargs):
print(args, kwargs)
print(A.__init_subclass__)
class B(A):...
def __init_subclass__(*args, **kwargs):
print(args, kwargs)
A.__init_subclass__ = __init_subclass__
class C(A):...
class Asub:
def __init_subclass__(*args, **kwargs):
print(args, kwargs)
A.__init_subclass__ = Asub.__init_subclass__
class E(A):...
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | <bound method A.__init_subclass__ of <class '__main__.A'>>
002 | (<class '__main__.B'>,) {}
003 | () {}
004 | (<class '__main__.Asub'>,) {}
Because (Objects/typeobject.c \approx L3733)
/* Special-case __init_subclass__ and __class_getitem__:
if they are plain functions, make them classmethods */
Make that A.__init_subclass__ = classmethod(__init_subclass__) and it behaves the same.
Oh ok, thx
Done it but haven't test does it impact how you use the class
i was told to post this here, one-line hangman
(_a_ := "train") and (_b_ := "_" * len(_a_)) and not (_c_ := 0) and ((f := lambda _: print(0) if globals()["_b_"] == globals()["_a_"] else f(str(globals().__setitem__("_b_", (g := input()) * 0 + "".join([v if g == v else globals()["_b_"][i] for i, v in enumerate(globals()["_a_"])]))) * 0 + str(globals().__setitem__("_c_", globals()["_c_"] + 1 * (not g in _a_))) * 0 + str(print(globals()["_b_"], _c_)) * 0) if globals()["_c_"] < 6 else print(1))(""))
"""
DESCRIPTION:
_a_ := solution word (here: "train")
_b_ := what's shown (like: "tr__n")
_c_ := error counter
(word:="train") and (display:="_"*len(word)) and not (errors:=0) and ( # define prerequisites
(f := lambda _: # main recursive function
print("WINNER!!!") if globals()["display"] == globals()["word"] else f( # exit - once you've won, else:
str(globals().__setitem__("display", (g:=input())*0+ # generate and \
"".join([v if g==v else globals()["display"][i] for i,v in enumerate(globals()["word"])]) # update display
))*0 + # easter egg # nothing much
str(globals().__setitem__("errors",globals()["errors"] + (not g in word)))*0+ # count errors
str(print(globals()["display"],errors))*0 # print display (and errors)
) if globals()["errors"] < 6 else print("YOU LOST!!!!!") # exit - once you've lost
)(""))
"""
Nice
...Still broke on multi mutex on same class
compressable
Ok I think it actually work now
Golfed
[print(B,C)or(C>5>exit(1))or(B==A>exit(0))for A in["train"]for B in["_"*5]for C in[0]for()in iter(set,1)for E in[input()]for B in["".join([y,x][E==x]for(x,y)in zip(A,B))]for C in[C+(E not in A)]]
"""
DESCRIPTION:
a := solution word (here: "train")
b := what's shown (like: tr__n)
c := attempts left
(
word := "train", # \
display := "_" * len(word), # |- define prerequisites
left := 6, # /
[
print(display, left := left + (g in word)-1) # print display (and count and print attempts left) (executes last)
for _ in iter(lambda: left * (display != word), 0) # main loop, exit if either:
# - no attempts left (left == 0)
# - display is equal to word [(display != word) == False == 0]
# else:
if ( # nothing much
g := input(), # generate and \
display := "".join(t[g == t[1] for t in zip(display, word)), # update display
) # easter egg # then do the printing written above
],
print("WINNER!!!" if c else "YOU LOST!!!!!") # show if you've won or lost
) # fin
"""
(a:="train",b:="_"*len(a),c:=6,[print(b,c:=c+(g in a)-1)for _ in iter(lambda:c*(b!=a),0)if(g:=input(),b:="".join(t[g==t[1]]for t in zip(b,a)))],exit(c<1))
``` semi-golfed
nice
now to find a good way of generating five letter words...
my first idea:
__import__('random').choice([*{*__import__('re').findall(r'\b[a-z]{5}\b', open(__import__('difflib').__file__).read())}])
difflib gives nearly 200 valid words but obviously not the shortest
what library ever needs this much documentation??
Also the code should be modified to print the word at the end
just ```py
[{import('re').findall(r'\b[a-z]{5}\b', open(import('difflib').file).read())}][0]
Hangman with the man: py [w:=[*'smile'],G:={7},(r:=lambda s:(g:=8-len(G-{*w}),print(*s),s==w>exit(),H:='\n| \\ / \n| \\│/ \n| O \n| ┃ \n+--+ ',[H:=H.replace(c,' ',1)for c in r'\/\│/O┃'[:g]],print(H[::-1]),g==0>exit(),G>{c:=input()}>r(s),G.add(c),s:=[[b,a][c==a]for a,b in zip(w,s)],r(s)))(['_']*5)] (improved version)py [w:='maeli',G:={7},(r:=lambda s:(g:=len(G-{*w}),print(*s),G>{*w}>exit(),H:=r''' +--+ | | O | /|\ | / \ |''',[H:=H[:c]+' '+H[c+1:]for c in b'? '[g:]],print(H),g>7>exit(),G>{c:=input()}>r(s),G.add(c),s:=[[b,a][c==a]for a,b in zip(w,s)],r(s)))('_'*5)]
Can this be used in production
you shouldn't be using esoteric code in production
if you really need to.
What is esoteric-python?
Writing code that looks cursed but functions as required
Everyone always asks what esoteric python is, no one ever asks how esoteric python is
because that question doesn't make sense? its just cpython nothing more about it
It was a meme nerd
esoteric python is suffering from lack of enthusiasm, thank you
meow
catkin
meow
guess esoteric python is no more
This has become the server's pet channel
Anyone want to golf this thing
Requirement, as_mutex API must be usable as it is now and it function in same way
what do yall think of my oneliners?
_1liner1 = (word := "k") and (display := "_" * len(word)) and not (errors := 0) and ((f := lambda _: print("WINNER!!!") if globals()["display"] == globals()["word"] else f(str(globals().__setitem__("display", (g := input()) * 0 + "".join([v if g == v else globals()["display"][i] for i, v in enumerate(globals()["word"])]))) * 0 + str(globals().__setitem__("errors", globals()["errors"] + 1 * (not g in word))) * 0 + str(print(globals()["display"], errors)) * 0) if globals()["errors"] < 6 else print("YOU LOST!!!!!"))(""))
_1liner2=[w:="face",d:="_"*len(w),v:=globals().__setitem__,p:=print,hangman:=(" 2222222222222222222222222222222222\n 1 3\n 1 3\n 1 3\n 1 44444\n 1 44 44\n 1 4 9 9 4\n 1 4 4\n 1 44 888 44\n 1 44444\n 1 5\n 1 5\n 1 5\n 1 5\n 1 5\n 1 6 7\n 000000000 6 7\n 00000000000000000 6 7\n 000000000000000000000 6 7")+"\n"*5,glyphs:="#|_|o|/\\~x",e:=0,enum:=enumerate,h:=lambda x:p("".join(glyphs[int(j)]if j.isdigit()and int(j)<x else j if not j.isdigit()else" "for i,j in enum(hangman))),(f:=lambda _:(p("WINNER!!!")if w==d else p("LOSER!!!")if e>=10 else(v("d","".join(i if i==g_ else d[j]for j,i in enum(w)))or p("correct guess")or p(d)or f(0))if(g_:=input(">"))in w else(v("e",e+1)or p("incorrect guess")or h(e)or f(0))))(0)]
guess what they do :)
hangman
you ran it >:(
i can't. i'm on mobile and i don't have space for an interpreter
there's a huge hangman ASCII art in the middle, y'know.
oh :/
also i did the deobfuscating + regolfing of your other code
and kind of figured it out along the way
ohh
yeah i forgor- 💀
i made a second one
oneliner2 = [
v:=globals().__setitem__,
p:=print,
hangman:= (" 2222222222222222222222222222222222\n 1 3\n 1 3\n 1 3\n 1 44444\n 1 44 44\n 1 4 9 9 4\n 1 4 4\n 1 44 888 44\n 1 44444\n 1 5\n 1 5\n 1 5\n 1 5\n 1 5\n 1 6 7\n 000000000 6 7\n 00000000000000000 6 7\n 000000000000000000000 6 7") + "\n" * 5,
glyphs:="#|_|o|/\\~x",
e:=0,
w:="face",
d:="_"*len(w),
g:=input,
enum:=enumerate,
h:=lambda x:p("".join(glyphs[int(j)] if j.isdigit() and int(j)<x else j if not j.isdigit() else " " for i,j in enum(hangman))),
# print hangman
(f:=lambda _: (v("d","".join(i if i==g_ else d[j] for j,i in enum(w))) or p("correct guess") or p(d) or f(0)) if (g_:=g(">")) in w else (v("e", e+1) or p("incorrect guess") or h(e) or f(0) if e<10 and not w==d else p("WINNER!!!") if w==d else p("LOSER!!!")))(0)
# update progress (display var) and print guess and progress if guess is right else increase err count and print hangman -!- recursion exits -!- [win] | [loss]
]
description
i need eep now, bye
gn
what if i want to?
Nothing stopping you, but you shouldn't
You will get like:
Why does it not work?
The reason is it was not on the test case and therefore the code don't have to obey such
!e print(type(3//3.0) is float)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
True
:white_check_mark: Your 3.13 eval job has completed with return code 0.
2.0
wow, just wow. rounds to an integer but returns it as a float
!e print("abcde"[4//1.5])
:x: Your 3.13 eval job has completed with return code 1.
001 | /home/main.py:1: SyntaxWarning: str indices must be integers or slices, not float; perhaps you missed a comma?
002 | print("abcde"[4//1.5])
003 | Traceback (most recent call last):
004 | File [35m"/home/main.py"[0m, line [35m1[0m, in [35m<module>[0m
005 | print([31m"abcde"[0m[1;31m[4//1.5][0m)
006 | [31m~~~~~~~[0m[1;31m^^^^^^^^[0m
007 | [1;35mTypeError[0m: [35mstring indices must be integers, not 'float'[0m
// is floor division
it floors the result
.__setitem__,p:=print,hangman:=
oopsie-
But changes it to int only if both a and b are ints.
!e
print(1e200 // 2e198)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
49.0
hate it when teachers/tutorials call it "integer division"
yes
its called integer division as a carryover from C
wow computers are so dumb, cant even do 1e200 // 2e198 correctly
that's actually a really cool demonstration though
!e ```py
from decimal import Decimal
print(Decimal(1e200) / Decimal(2e198))
:white_check_mark: Your 3.13 eval job has completed with return code 0.
49.99999999999999760987903232
classic
!e
from decimal import Decimal
print(Decimal("1e200") / Decimal("2e198"))
:white_check_mark: Your 3.13 eval job has completed with return code 0.
5E+1
!e ```py
from decimal import Decimal
print(1e200 / 2e198 == 50)
print(Decimal(1e200 // 2e198))
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | True
002 | 49
computers can
ieee754 double precision floating point numbers cant
that makes no sense lmao 😭
but get this
!e
print(1e200/2e198, 1e200//2e198, 8e100/2.0e100==8e100//2.0e100)
!e py print(int(1e200)//2e198) print(1e200//int(2e198))
:white_check_mark: Your 3.13 free threaded eval job has completed with return code 0.
001 | 49.0
002 | 49.0
:white_check_mark: Your 3.14 pre-release eval job has completed with return code 0.
50.0 49.0 True
what doesnt make sense
she put the entire calculation into Decimal(...), that kinda defeats the purpose of the module
or he, whatever
was that not on purpose
I don't think so
that's why you do Decimal("1e200")
or Decimal(int(10**200))/Decimal(int(2*10**198))
when you do, you get the inaccurate float approximation, to more digits than the float APIs would give you
for example, ```py
decimal.Decimal(0.3)
Decimal('0.299999999999999988897769753748434595763683319091796875')

yeah i meant to do float division but messed it up from my phone
yeah but it's fun to see the exact representation when playing around with weird rounding behaviour
(i just didn't get it right ;D)
initial, length unknown
https://paste.pythondiscord.com/J3PA
Nice
floor division returns a float, if either side of the operation is a float.
flipping this; only when both are integers, does it return an integer.
https://docs.python.org/3/library/stdtypes.html
- Also referred to as integer division. For operands of type int, the result has type int. For operands of type float, the result has type float. In general, the result is a whole integer, though the result’s type is not necessarily int. The result is always rounded towards minus infinity ...
- ... for complex numbers ... convert to floats using abs() if appropriate.
Rust enum in python (?
https://gist.github.com/i-am-unknown-81514525/447cc247ff824ec9cde6edb9256dce0f
!e
as someone who never spoke rust this is beyond esoteric
Honestly, there are large part of the code that hack the python globals so I can have undefined variable to be valid
Which come from help from previous message which come from help from other members
omg nice! i love this
that's a fun way of doing it! i remember using a different method to hack undefined globals when i implemented c++ style input/output syntax (i.e. cin/cout) in python. so it's really interesting to see a similar idea done differently
+1 for rust
actually, i just saw lines 76-81 in your gist. that's funny
Oh ye I literally search and copy that code to put it in
#esoteric-python message
From here after being told how to replace globals
Let a radiation safe expression be one such that it and any deletion of a single character evaluates to the same integer in python. For example, 00 is a radiation safe expression that evaluates to 0. Is there a radiation safe expression for every number 1-100? What is the shortest program that prints a radiation safe expression for each n 1-100?
The deletion of it:
How much it is deleting, a character or a token?
character
just one?
yep
I mean, if it can be more than one(non restrictive), then there are no radiation safe expressions that can evaluate to integer lol
edited for clarity
first challenge is finding one that evaluates to 1 :)
for example ||00**00|| is close
Apparently you cannot use leading 0 except 0
00**00|00**00|00**00
nice
The reason why cannot just use 2 is apparently 0**0**0 is 0
yep 0**(0**0)
does 11<122<11123 count, being a boolean?
for any sufficiently tight binding result for 1 you can always ++ it to itself for larger numbers
(assuming it also works with 0 removals)
Wdym
if you can do <expr for 1>++<expr for 1> without needing parentheses around the expressions you have an expression for 2
unary + is kinda goated actually
Oh
has anyone figured out how to edit a live generator's entry point, or code body? or even a non-live function's code body in-place?
sure it's virtually guaranteed to be a disaster, but is it possible?
!e I don't know about generators but you can certainly change a function's code body ```py
def f(a, b, c): print(a + b + c)
def g(): print('Hello, world!')
g()
g.code = f.code
g(1, 2, 3)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | Hello, world!
002 | 6
wow
hmmm
!e
def foo(a):
print(f"foo {a=}")
b = yield a
print(f"foo {b=}")
c = yield b
print(f"foo {c=}")
def bar(a):
print(f"bar {a=}")
b = yield a
print(f"bar {b=}")
c = yield b
print(f"bar {c=}")
x = foo(3)
a = next(x)
b = x.send(99)
x.gi_code = bar.__code__
c = x.send(40)
:x: Your 3.13 eval job has completed with return code 1.
001 | foo a=3
002 | foo b=99
003 | Traceback (most recent call last):
004 | File [35m"/home/main.py"[0m, line [35m18[0m, in [35m<module>[0m
005 | [1;31mx.gi_code[0m = bar.__code__
006 | [1;31m^^^^^^^^^[0m
007 | [1;35mAttributeError[0m: [35mattribute 'gi_code' of 'generator' objects is not writable[0m
even using object.__setattr__(x, "gi_code", bar.__code__) doesn't work
what kind of behaviour are you trying to get here?
to assert dominance over the interpreter
it's my computer and i decide what the bytes are
but yeah tbh i am disappointed to not be able to control every aspect of python objects that aren't like... Ctypes
i can understand a Ctype or something, but generator is a fundamental object
I’m not familiar enough with C/Ctypes to figure it out, but it looks like the code uses &gen->gi_frame so if you got the offset of the struct field couldn’t you write to it to change the frame it’s pointing to?
ooooooo interresting
https://github.com/python/cpython/blob/main/Include/internal/pycore_interpframe_structs.h#L59-L74
mfw using a macro to add a prefix to all field names
!e This sort of works, based on a ton of assumptions and will probably break everything. It only works when the generated item is a constant item, and doesn't overwrite the length, so I guess those are stored somewhere else I didn't overwrite. This also gets a bit silly, since when you are turning to using ctypes like this you are basically using a memory editor and could do anything. ```py
def swap_generator(old, new):
# based on https://stackoverflow.com/a/45698304
import ctypes
# Assumes 64-bit operation system, size is 8, 10th element for 89 offset
(ctypes.c_longlong).from_address(id(old) + 89).value = id(new.gi_code)
# Manually increase refcount to pretend this is a good idea
(ctypes.c_longlong).from_address(id(new.gi_code)).value += 1
print("works :)")
gen = (1 for _ in [1, 2, 3])
print(next(gen))
swap_generator(gen, (2 for _ in [1, 2, 3, 4]))
print(*gen)
print("doesn't :(")
gen = (x for x in [1, 2, 3])
print(next(gen))
swap_generator(gen, (x for x in [9, 8, 7, 6]))
print(*gen)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | works :)
002 | 1
003 | 2 2
004 | doesn't :(
005 | 1
006 | 2 3
assuming an understanding of python bytecode, i can imagine a generator object should be able to swap out its own code mid-execution by carefully manipulating python's data stack, this way. This means it should, ultimately, be possible to create a kind of "in-flight repair" protocol where the program modifies itself
Also, you could make a C extension to avoid all of this ctypes memory editing nonsense
perhaps you could...
def falsey():
self = yield
while (x != y):
... same as plane
def plane():
self = yield
while (x == y):
(ctypes.c_longlong).from_address(id(self) + 8*...).value = id(new.__code__)
(ctypes.c_longlong).from_address(id(falsey.__code__)).value += 1
...
def engine() -> plane:
x = plane()
next(x)
x.send(x)
return x
so you could have the loop conditionally invert itself (and arbitrarily many other simple 1-1 operator changes) at runtime
all without having to resort to that ugly old python trick of just "suffix booleans with == a; and change a"
this is all incredible, really
i wonder if you could, through careful manipulation... use the python EXPR datastack as a stack
you would need to alter the value in the middle of an operation, perhaps with :=
I’m confused what you’re trying to do or why
depends on the interpreter
for the JIT-type interpreter, the offset of the executing code is probably entirely internal-only
I don't understand why you would need cursed things for this, why not define a custom iterator with that behavior? ```pycon
class FlipFlopGen:
... def init(self, state):
... self.state = state
... def iter(self):
... return self
... def next(self):
... return self.state
... def flip(self):
... self.state = not self.state
... x = FlipFlopGen(True)
... print(next(x))
... print(next(x))
... x.flip()
... print(next(x))
... print(next(x))
...
True
True
False
False
it's about what's possible
also what is the offset based on...?
and esp. with generators i mean this kind of alternation is trivial enough without even needing a custom object, just have a variable, but my example is just that
!e The c code, I just found it using ```py
import ctypes
gen = (1 for x in [1])
print(id(gen.gi_code))
for i in range(20):
print(i, (ctypes.c_longlong).from_address(id(gen) + 8*i))
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | 139751458934096
002 | 0 c_long(1)
003 | 1 c_long(139751469414496)
004 | 2 c_long(0)
005 | 3 c_long(139751469465616)
006 | 4 c_long(139751469465616)
007 | 5 c_long(0)
008 | 6 c_long(0)
009 | 7 c_long(139751459108272)
010 | 8 c_long(139753891832256)
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/ANKMWZDKS6M5DTF2ADC56BMVQQ
And you can see 9 has the same value as the id, so it's the correct offset
smart
i see
Actually stupid, if I knew how to read C code like lambda I could have found the offset by just counting using this link https://github.com/python/cpython/blob/main/Include/internal/pycore_interpframe_structs.h#L59-L74
_frame_state is the 10th item
it's not really that simple
you're counting PyObject_HEAD as 1 pointer and the chars as 1 pointer
IDK it seems to line up and work, I really have no clue what I'm doing
it's a coincidence :p
That's funny
you're most likely getting the first field pointed to by the _iframe struct pointer
which is the code object of the frame of the generator
oh. i get it now
an internal interpreter frame is technically stored as an "array" inside the generator object
since C arrays are just glorified pointers
Don't all c-based python objects use slots? Or do you mean something different?
and if the array were to be dereferenced like a normal pointer, the first element (a.k.a. the first field of the interpreter frame) would be the value
so by changing that, the first field of the iframe (a.k.a. the code object of the generator frame) is modified
slots?
like the getters and setters referencing fields?
__slots__
oh
i don't really know, but aren't internal object struct fields basically like that anyway
as in they're stored after the object [header]
I wonder, what actually is in that code object, since overwriting it only works for a constant return value, not dynamics ones/iteration length
it doesn't override the module-scope iterator passed to it
(y for x in a for y in x)
is basically the same as ```py
def _gen(_0):
for x in _0:
for y in x:
yield y
_gen(iter(a))
so in order to change the iterator, the running stack must be changed
dont forget alignment
guess the size of this struct
struct {
int *x0;
char x1;
int *x2;
};
||24|| yeah?
because ||x2 is aligned|| to ||an 8 byte boundary||
usually yeah
and the funny part is if you put another char after x1, the size wont change
3 bytes?
i meant like they count the chars as 1 pointer each regardless of the adjacency
An pointer should be 4 byte tho
if you are on a 32 bit system. we are all on 64 bit, i hope
not 3 bytes
icy
struct packing is such a weird thing in C
Tbf, why you say char is a pointer tho
"__a__s", as in "Apple", not "is" as in "Internet"
i was referring to how they counted the fields as 1 pointer each, including the ones with the type of char
yeah
unless you put 9 chars there :3
i don't know what i'm doing ```pycon
gen = (x for x in [1, 2, 3])
print(next(gen), next(gen))
1 2
gen_sub(gen, (x for x in [9, 8, 7, 6]))
print(*gen)
7 6
What is gen_sub?
Wow
fun. fact. this: py r = [x for _ in _ for x in [1]] is the same as this: ```py
r = []
for _ in _:
for x in [1]:
r.append(x)
BUT THIS: ```py
r = [x for _ in _ for x in [nonconst]]
``` IS THE SAME AS THIS. ```py
r = []
for _ in _:
x = nonconst
r.append(x)
did they seriously add a peephole optimization for this kind of weird assignment in comprehensions
i mean that doesn't really trouble me, it's just the fact that it's inconsistent \( T^T )/
well its consistent by behavior isnt it
for x in [1] is basically x = 1
it somehow doesn't do it when it's a constant sequence?? why??
because it can be stored as a constant tuple in the bytecode?
-# actually it does kinda trouble me, i'm trying to do a thing where i replace the iterators in a generator
i'm just saying why not apply that assignment opt. first before the constant sequence iteration opt.
anyways updated so that you can replace individual iterators
girl
what you're doing is really cool
im kind of too tired to phrase things well but uh yeah
you're awesome and stuff
tyy ^_^
!e
def test_list():
"V" in ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
def test_tuple():
"V" in ('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z')
def test_set():
"V" in {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}
import dis
dis.dis(test_list)
dis.dis(test_tuple)
dis.dis(test_set)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | 1 RESUME 0
002 |
003 | 2 LOAD_CONST 1 ('V')
004 | LOAD_CONST 2 (('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'))
005 | CONTAINS_OP 0
006 | POP_TOP
007 | RETURN_CONST 0 (None)
008 | 4 RESUME 0
009 |
010 | 5 LOAD_CONST 1 ('V')
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/SEAWRGMKLW5P4RDLKMAIIOUIBY
TIL I learned that Python doesn't build sets and lists if they are just needed for CONTAINS_OP
(if constant elements)
yes
it's cool that it's reusing a tuple / frozenset saved from co_consts
I thought Python always does just what it's told to do, without making this kind of optimizations
what's the optimization in this case?
!e
import dis
def test_str():
"V" in "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
dis.dis(test_str)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | 2 RESUME 0
002 |
003 | 3 LOAD_CONST 1 ('V')
004 | LOAD_CONST 2 ('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
005 | CONTAINS_OP 0
006 | POP_TOP
007 | RETURN_CONST 0 (None)
none, that's why it's unremarkable
)
!e
import dis
def test_list():
a = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
"V" in a
dis.dis(test_list)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | 3 RESUME 0
002 |
003 | 4 BUILD_LIST 0
004 | LOAD_CONST 1 (('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'))
005 | LIST_EXTEND 1
006 | STORE_FAST 0 (a)
007 |
008 | 5 LOAD_CONST 2 ('V')
009 | LOAD_FAST 0 (a)
010 | CONTAINS_OP 0
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/FY6SYNPIADWUUCMZIQX3QVRFJE
I would be amazed if it would cover that 😄
though no idea if CONTAINS_OP const + local name is any less efficient than CONTAINS_OP const + const
Kind of annoying that there is no non-esoteric way to access frozenset from co_consts without creating a new set. And something like frozenset({1, 2, 3}) would end up creating 3 set objects...
243
import random
from string import*
b=lambda s:"ny".index(input(s+'? '))
print("".join(random.choices(ascii_letters[:26*-~b('Use capital letters')]+digits*b('Use numbers')+"!@#$%^&*()-_=+[]{}|;:,.<>?/"*b('Use symbols '),k=int(input("Length")))))
Are there things that annoy you when you see them in python code, because you know some internal details (maybe even something on the opcode level), though they don't really matter and working around them might not bring any real benefits?
E.g. I have it every time I see if hasattr(a, x): y = a.x when __getattr__ is not just default method and it has some other stuff in it - it's annoying because I know that hasattr is basically getattr with AttributeError exception catch, so it's basically calling getattr twice for no reason.
maybe, but i kind of do the double getattr myself in non-esoteric code
code golf: given two lines of input A and B, print A with all instances of the substring B replaced by a space.
print(input().replace(input(),' '))
does that count newlines as characters?
31 ||
exit(str.replace(*open(0),' '))
||
short a )
oop
31||I=input;I(I().replace(I(),' '))|| not sure this counts.
||print(*input().split(input()))|| 30?
that's so cute
this is clever!
27? ||print(*str.split(*open(0)))||
newlines shouldn't usually cause a problem for this format
!tvmute 880102329335046246 2w This is not how you get voice-verified. Posting "hi" across many channels definitely counts as spamming.
:incoming_envelope: :ok_hand: applied voice mute to @torn cave until <t:1751452045:f> (14 days).
you two's answers could just be combined into 26 ||py I=input;I(*I().split(I()))||
nvm idk how drunk I was that day
Have you tried it?
i mean it does "print" but it also starts taking input
But input only takes one argument, it doesn't space-join the prompt like print does
ah, yeah, thats true, i suppose we tested only with the case where it splits into 1 element
!rule 6
What's everyone's favorite bit of esoteric python?
"Subclassing" non types
Oh?
!e ```py
class Foo(map(0,"")):pass
print(Foo)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
<map object at 0x7f8b8452fbb0>
everything ^_^
^^
https://gist.github.com/i-am-unknown-81514525/d3e2a8e57e4fcbd487f47922155950a1
Who doesn't like abusing mro to make class mutually exclusive
!e ```py
try:
for {}[()] in [()]*(()==()):
x = a, *v = a[0], *_ = [0], 7, 2
x[0] += sum(v),
except TypeError:
print(x)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
([[...], 9], 7, 2)
XD I used Cython to build a class which was it's own type once
Was a fun exercise
You can even replace the standard object base type if you want
I was trying to build a truly immutable object/type. Got pretty close too
Well, I don't cross the boundary outside python usually since I don't know much outside
code
:white_check_mark: Your 3.13 eval job has completed with return code 0.
Mondziuu: esoteric python
what in the world
sorry, was not reacting to u specifically but tihs channel in general
seeing the obfuscated code
i love ```py
chr(sum(range(ord(min(str(not()))))))
translated to runic
globals().update({k.translate(range(5695,5880)):eval(k)for k in vars(__builtins__)})
ᚯᚱᚨᚭᚳ(ᚢᚧᚱ(ᚲᚴᚬ(ᚱᚠᚭᚦᚤ(ᚮᚱᚣ(ᚬᚨᚭ(ᚲᚳᚱ(ᚠᚫᚫ(()))))))))
:white_check_mark: Your 3.13 eval job has completed with return code 0.
Deleted file: /home/main.py
!e
五, *試験 = [5, 33554431, 18157905, 15255086, 10813998, 8548352, 667904, 151936, 268672, 133568]
レアシンボル, さらに珍しい, はは= "1#", "0.", "025b"
印刷する, 範囲, 地図, 交換する = eval(bytes('牰湩ⱴ爠湡敧慭Ɒ猠牴爮灥慬散','u16')[2:])
def 解く(ね):
印刷する(ね)
for い in 範囲(五):
印刷する(交換する(交換する(f"{ね:{はは}}"[い*五:-~い*五],*レアシンボル),*さらに珍しい))
印刷する()
*ψ, = 地図(解く,試験)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | 33554431
002 | #####
003 | #####
004 | #####
005 | #####
006 | #####
007 |
008 | 18157905
009 | #...#
010 | .#.#.
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/MNXLAJDY7GJ4JBRM7CPCO7FQ5E
rare symbols, even rarer, haha
lol
the bytes part is "pitónes"
||jk||
yet another silly code golf: print the multiples of 8 between 16 and 104, inclusive, in order, each on a single line
par is ||27||
Stein's Gate was great
!e|| print(*(i*8for i in range(2,14)))|| 33
||for _ in range(2,14):print(_*8)|| ||31||
Didn't noticed 🥴
contenders ||```py
*map(print,range(16,105,8)),
x=8;while x<97:print(x:=x+8)
*map(print,b' (08@HPX`h'),
solution since nobody seems to have gotten it: ||*map(print,range(*b'i')),||
oh my god i got close.
i tried to make it so that there were a lot of solutions close in byte count :P
while after ; is not valid syntax
!epy 1;while 1:1
:x: Your 3.13 eval job has completed with return code 1.
001 | File [35m"/home/main.py"[0m, line [35m1[0m
002 | 1;[1;31mwhile[0m 1:1
003 | [1;31m^^^^^[0m
004 | [1;35mSyntaxError[0m: [35minvalid syntax[0m
just use \n it will also count as single char
metaphorical ;
in here it's basically an \n for demonstration purposes only
Esoteric Python should be illegal
You hear me illegal.
is your name samuel seabury, perchance?
the third.
!e fun alternate way I just found to make a slice: ```py
from typing import Union
print(Union[1:2:3])
:white_check_mark: Your 3.13 eval job has completed with return code 0.
slice(1, 2, 3)
Oh very good to know for esopy purposes that Union is an identity []function for 1 argument
!e that doesn't seem to do what you think it does...
*map(print,range(*b'i')),
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | 0
002 | 1
003 | 2
004 | 3
005 | 4
006 | 5
007 | 6
008 | 7
009 | 8
010 | 9
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/7ZFX6RFXLVC7ECROAYW7MD3LVU
it does exactly what he thinks it does
there's just a few control characters missing from what you wrote
Which ones? I copied what was posted as the solution.
if written normally those would be \x10 and \x08 respectively
!e ```py
*map(print,range(*b'\x10i\x08')),
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | 16
002 | 24
003 | 32
004 | 40
005 | 48
006 | 56
007 | 64
008 | 72
009 | 80
010 | 88
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/PLUDQ3T6U6V4WY6BMPQ73R3ZNI
!e ```py
print('characters displayed: \x10i\x08')
:white_check_mark: Your 3.13 eval job has completed with return code 0.
characters displayed: i
!e
*map(print,range(*b'i')),`
!e
*map(print,range(*b'i')),
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | 16
002 | 24
003 | 32
004 | 40
005 | 48
006 | 56
007 | 64
008 | 72
009 | 80
010 | 88
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/YCHNKVITIRPPGKI5RBWTCTK7A4
there.
The joys of invisible characters.
with some small edits to the source code, fixed a thing which was bothering me for a while
Also, you know what python lacks? The opposite of id() function
it's a fresh git checkout, aka python from the future
I didn't know they already started 3.15, nice
3.14 is already beta, so whatever you get from git is marked as 3.15 (although in practice it won't be much different from 3.14)
Try make it 3.14.15a9
noted
but how will you deal with garbage ids?
try deid(2 ** 61)
wait
no
deid(id(2 ** 61))```
i can almost guarantee you it wont be 2 ** 61
yeah, tsoding tag
that's also a segfault (why wouldn't it be unless 2**61 happened to be readable and looking like a pyobject)
>>> a = 2 ** 61
>>> deid(id(a))
2305843009213693952
Can you do tryid(int) -> tuple[Literal[True], Any] | tuple[Literal[False], None]
Which Any would be the pyobject if it exist there
I don't think there's a practical way of distinguishing a real pyobject from a random assembly of bytes which happened to look sufficiently like a pyobject
in theory you can deid() in the middle of a bytearray and get a pyobject back and then have funny things happen
The implementation is literally:
static PyObject *
builtin_deid(PyObject *self, PyObject *args)
{
long int n;
if (!PyArg_ParseTuple(args, "l", &n)) {
return NULL;
}
PyObject *ret = (PyObject*) n;
Py_INCREF(ret);
return ret;
}
Then I should rephrase
Just make sure it doesn't segfault
If it would segfault if I do deid on the given id, it gives (False, None)
Otherwise give (True, object)
Whether it would segfault by the usage of such corrupted object can be ignored
The only thing deid() cares about is being able to incref, which means being able to read and write this specific location... Not really a strong indication that segfault won't happen right after, e.g. when repr is called
Oh the segfault was repr? I thought it was when incref
the gc tracks all of the proper ones
if you enable gc debugging
that fits some definition of "practical" probably
it's not like there's any sane usecase for a function like that 🙂
Gc would only track objects that can contain other references to objects afaik
iirc there was the gc debug build that just has a linked list of every object?
i might also be misremembering, its been a couple years since ive looked at the gc lol
Pretty sure the GC is only used for container objects, but there's also a reference count debug mode that might do what you are referring to
you could use the internal argument clinic on this
yeah thats what im talking about
You should checkout _ctypes.PyObj_FromPtr
ah, yes, easter egg features
learning how to clinic is on my "eventual todo" list
this is how i'd write it i think
/*[clinic input]
deid as builtin_deid
addr: object
/
Return the object at address addr; may segfault if no object exists.
[clinic start generated code]*/
{
PyObject *obj = (PyObject *)PyLong_AsVoidPtr(addr);
if (obj == NULL && PyErr_Occurred()) {
return NULL;
}
return Py_XNewRef(obj);
}
...
BUILTIN_CHR_METHODDEF
BUILTIN_COMPILE_METHODDEF
+ BUILTIN_DEID_METHODDEF
BUILTIN_DELATTR_METHODDEF
...
then run argument clinic
hello! can someone rate my quine program?
line_2 = " file.write('line_1 = %r\\n' % line_1 + 'line_2 = %r\\n' % line_2 + 'line_3 = %r\\n' % line_3)\n"
line_3 = ' file.write(line_1 + line_2 + line_3)'
with open('quine.txt', 'w') as file:
file.write('line_1 = %r\n' % line_1 + 'line_2 = %r\n' % line_2 + 'line_3 = %r\n' % line_3)
file.write(line_1 + line_2 + line_3)```
!e ```py
print(open(file).read())
:white_check_mark: Your 3.13 eval job has completed with return code 0.
print(open(__file__).read())
Pretty sure the definition of a quine doesn't allow you to read file
most of the time yea, but since theirs used open, i figured i could to
But the difference is their quine is to create a file that have the same code
ah i misread
*Wraps into bash self executing script*
Assuming the quine is functional
!e ```py
exit((:='exit((:=%r)%%)')%)
:x: Your 3.13 eval job has completed with return code 1.
exit((_:='exit((_:=%r)%%_)')%_)
It cannot take any form of input, such as a file
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | s = 's = {!r}\nprint(s.format(s))'
002 | print(s.format(s))
!e ```py
='=%r;exit(%%)';exit(%)
:x: Your 3.13 eval job has completed with return code 1.
_='_=%r;exit(_%%_)';exit(_%_)
that's the quine I know for python
code golfing challenge: output any 200 valid wordle words
A judge for this might look like ```py
with open('./words.txt', 'r') as f:
words = f.read().splitlines()
given_input = open(0).read().splitlines()
assert len(given_input) == len(set(given_input) & set(words)) == 200
I honestly have no clue what a good solution is, my best is ||642||
I have ||625|| with a very basic solution
this might be a fun collaborative challenge
530
||```py
D=[
'aeaiasatbsckepgsgyicitkelelnmampndnengnknnnyodokoloporpepsptrerkrmrysststtunupur',
'apatceckcododsfeffftinirislklsmpmsnangnkntospepsptrardrerkrmrrrsrtrysesmtsvavevs',
'aoasbabscachckcocsdeefelkoksldlelillmbmemompnanengnknonspsrkrlrmrorprrrtrutitsva',
'ceckcydedodsederesgshiilinitkeldlellltmsnengnknsrdrerkrsrtsmtetsulwlwnwsydyszazz',
'ckdedsdyftgshskakekoktkylelllmltlymamemsndnknspepsrdrerkrnrprtshulvewlwmwnwsyays',
]
for A, B in zip('sto cha chi spa sha'.split(), D):print(A+('\n'+A).join(map(''.join,zip(*[iter(B)]*2))))
clever
http://golf.horse/ results indicate that an optimal solution might be <200 bytes
how short do we get if we just compress a list of 200 words
the words can be chosen for optimal compressing
🫢 I had ||('cha', 'sto', 'sha', 'spa', 'cho')||
like with gzip? thats boring :P
not really
picking which words to use is an interesting puzzle
checking every combination is bad because thats bad
That's what I did for 625 bytes
how carefully did you pick the words
I just took the first 200 words starting with "pa" and compressed them without it. Lots of potential there still.
Also I used base85 to represent the result of that in the code, surely there's better ways.
im thinking it could be possible to store each of the two-letter suffixes in my solution above into one byte
Probably even three or four. We don't need uppercase, numbers, punctuation, ...
I am thinking if there exist >200 word that have the same substring
How big of a substring are you talking about? For 2-char ones that's the case. 3 is doubtful, 4 impossible.
Oh wait I forgot to type
I meant 3
one funny thing i was thinking about you could get longer repeated substrings if you store all of the words concatenated back to back, allowing the last few characters of one word and the next few of another to become some common substring
And hopefully exist considerably more than 200 so that it can be filtered
But unless it's always the same offset now you have to store those, too
I have the compression method down to 551 bytes
Here's my current solution at 398 ||
D="aahederrorallinacherestopeevenallayincellamasassedumboskytesladedalleechedileacharamenemasedgesteadsummahalalamoreechessayontalarmedictalmaserickerneskipsyopposcallanodesextolanchocotestaigapoopsitherondeshireedemangoniflemedinarmethosensewannasalephasteraineembarsoncericingleantardoraddinervenomasananashivespacedargalearedanionicerses";[print(D[(j:=int((5*i-3)/3)):j+5])for i in range(1,201)]
||
Explanation:
||
The strategy is basically "make one giant portmanteau". So far the best compression I've been able to find by brute force is
search_len = ((current_count % 3) == 0) + 3
if current[-search_len:] == word[:search_len]:
stack.append((current_count + 1, current + word[search_len:], (*current_trace, word)))
This turns out to make https://oeis.org/A047212 , or gaps of 2 2 1 2 2 1 2 2 1 between word starts. There is probably a more concise way to generate the i but I've literally spent hours on this one part so I just gave up and used a definition from OEIS.
Trying to do a pure length 4 search_len fails. I'm unsure if % 2 works yet, my code is too slow.
||
🤯 I like the idea
you can bring it down to 386 with some simple golfs. It's a creative idea!
||```py
for i in range(200):j=(5*i+2)//3;print("aahederrorallinacherestopeevenallayincellamasassedumboskytesladedalleechedileacharamenemasedgesteadsummahalalamoreechessayontalarmedictalmaserickerneskipsyopposcallanodesextolanchocotestaigapoopsitherondeshireedemangoniflemedinarmethosensewannasalephasteraineembarsoncericingleantardoraddinervenomasananashivespacedargalearedanionicerses"[j:j+5])
is there a list of all the wordle words somewhere
we may as well check
Scroll up, bulmenisaurus linked it in the original message.
brother this chat has war crime level code and thats in python 😭
I’ve been thinking about this, and I suspect there’s one key difference: because the amount of data is so much larger there, it will almost always be worth it to trade processing complexity for compression space. With how much less data there is here, a lot of the fancy tricks probably won’t work because they have too much overhead. The actual data compression limit might be around 200 bytes, but my guess is that would make the decompression algorithm way too complex to fit into the saved space.
that makes sense
Are there any chance we could find combinations of data and rely built-in libraries to decompress
Using external (i.e. stdlib) is way better than what we could possibly do with less overhead
!e ```py
___: int = 1--+------+-++-++----+---++-+--+--1-+--1
_: str =1--+------++1+-+-+--+-+-++-++--++---1-+1
____: float = 1-----+-++++---+---1---++--+---+1
__:int=1--+------+-++-++--1---+---++-+--+--1-+--1
this is 1+2+3
_____ = +-+++--+--++--++--+-+-+--++-++_+-+++--+--++--++--+-+-+--++-+_+____
print(_____)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
6
:white_check_mark: Your 3.13 eval job has completed with return code 0.
2
!e
import operator as op
class Op:
from operator import *
assert op.add is Op.add
print(dir(Op))
!e```py
import operator as op
import functools as ft
import itertools as it
import random
inc = lambda n: -~n
dec = lambda n: ~-n
odd = lambda n: bool(n&1)
even= lambda n: odd(dec(n))
mul4= ft.partial(op.mul, 4)
def N(n, r):
if r in {0, n}:
return 1
return N(n-1, r-1) + N(n-1, r)
n = op.itemgetter(1)(divmod(1001, 35))
f = filter(odd, range(5, 100, 3))
m = map(op.itemgetter(-2), map(list, map(range, f)))
r = random.choice(list(m))
print(N(n, r))
:x: Your 3.13 eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File [35m"/home/main.py"[0m, line [35m22[0m, in [35m<module>[0m
003 | print([31mN[0m[1;31m(n, r)[0m)
004 | [31m~[0m[1;31m^^^^^^[0m
005 | File [35m"/home/main.py"[0m, line [35m15[0m, in [35mN[0m
006 | return [31mN[0m[1;31m(n-1, r-1)[0m + N(n-1, r)
007 | [31m~[0m[1;31m^^^^^^^^^^[0m
008 | File [35m"/home/main.py"[0m, line [35m15[0m, in [35mN[0m
009 | return [31mN[0m[1;31m(n-1, r-1)[0m + N(n-1, r)
010 | [31m~[0m[1;31m^^^^^^^^^^[0m
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/YBUNGD2T3LGCA7MQ56MCHC5CT4
!e
import operator as op
import functools as ft
import itertools as it
import random
inc = lambda n: -~n
dec = lambda n: ~-n
odd = lambda n: bool(n&1)
even= lambda n: odd(dec(n))
mul4= ft.partial(op.mul, 4)
def N(n, r):
if r in {0, n}:
return 1
return N(n-1, r-1) + N(n-1, r)
def __main__():
n = random.choice( divmod(999, inc(35)) )
f = filter(odd, range(5, 100, 3))
m = map(op.itemgetter(-2), map(list, map(range, f)))
r = random.choice(list(m)) % n
print(N(n, r))
locals()[__name__] is __main__ and __main__()
:white_check_mark: Your 3.13 eval job has completed with return code 0.
4686825
!e```py
import functools as ft
import operator as op
mul2 = ft.partial(op.mul, 2)
mul2(11) == 22 and print(ft.partial.name, name[3:-2].replace(*'ay'))
class R:
def _endless(start, step):
curr = start
while True:
yield curr
curr += step
def _forwards(start, step, end):
curr = start
while curr <= end:
yield curr
curr += step
def _backwards(start, step, end):
curr = start
while curr >= end:
yield curr
curr += step
def better_range(start, step, end=None):
if end is None:
return R._endless(start, step)
elif step > 0:
return R._forwards(start, step, end)
else:
return R._backwards(start, step, end)
def __class_getitem__(cls, args):
start = args[0]
if args[1] is ...:
# Default stepsize
try:
end = args[2]
except IndexError:
end = None
step = 1 if end is None or start <= end else -1
elif args[1] is not ...:
# Stepsize provided
assert(args[2] is ...)
try:
end = args[3]
except IndexError:
end = None
step = args[1] - start
return R.better_range(start, step, end)
for x in R[0, ..., 10]:
print(x)
for x in R[0, 2, ..., 10]:
print(x)
for x in R[10, 8, ...]:
print(x)
Any ideas for the syntax?
I'd love to be able to include inclusive/exclusive ranges somehow that's close to math, like R[0, ..., 4)
but obviously this is probably not really possible
R[0, ..., 4, ")"] :P
ewww
maybe a wrapper class that wraps numeric types
R[0, ..., exclusive(4)]
obviously I can easily define a completely exclusive interval
like
R(0, ..., 4)
the half open ones are the problems

maybe it's time for a pep
to allow for a mutated __getitem__ and __call__ amalgamation
def _make_exclusive(generator):
generator.__next__() # throw away the first value
prev_val = generator.__next__()
# this throws away the last value
for val in generator:
yield prev_val
prev_val = val
def __new__(cls, *args):
return R._make_exclusive(R[args])
for x in R(10, 8, ..., -2):
print(x)
it's taking shape
what about for x in R[0 < _ <= 10] with R and _ predefined
repl users won't like that
inaccessibility wins
Could you make for I in (0 < R <= 10)
Hmmmm this is not bad at all
Lol doesn't _ get overwritten constantly
No you don't have control over the output of boolean operators
Need to run a background process to make sure it always points to my object
because __gt__ and __le__ don't have to return a boolean you can sort of do it
!e ```py
class _R:
def init(self): self.l = self.u = None
def ge(self, o):
self.l = o
return self
def gt(self, o): return o + 1 <= self
def lt(self, o):
self.u = o
return self
def le(self, o): return self < o + 1
def iter(self):
if self.l is None or self.u is None: raise ValueError('provide upper and lower bounds')
it = iter(range(self.l, self.u))
self.l = self.u = None
return it
def repr(self): return f'{self.l} <= R < {self.u}'
R = _R()
for n in 0 < R <= 3:
print(n)
print(list(1 <= R < 11))
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | 1
002 | 2
003 | 3
004 | [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
oh wait you're right! I was thinking of __bool__ and how comparison chaining implicitly calls and, but the short circuiting cancels that out
that does work!
Challenge: make multi-bound possible
Like (1 < R <= 20 and 0 < R <= 10) or (1 < R <= 20 or 29 < R <= 37)
ambiguous without stack frame inspection
not really? Unless I remember wrong and you cannot manipulate the output of A or B given A/B is controlled by the developer
oops, there are actually isn't
*Like ((1 < R <= 20) & (0 < R <= 10)) or ((1 < R <= 20) | (29 < R <= 37))
I am sure bitwise and/or would actually be overrideable, instead of syntax one
yeah if you want or not to short circuit in a<=R<b or c<=R<d the first < has to return a falsy object but with and it has to be truthy
This could be implemented for free by returning a set
hmm, then it cannot be calculated if I do like 1 < R <= 10000000000000000000
with some conditioning, forwards and backwards could probably be combined
breaks endless ranges, i think
((1 <= R) & (2 <= R))
cant be a set without some sort of further trickery going on
it mean, if you do (R < 1), it would break anyway
unless it doesn't have to retain a specific order
I have come up with a way to do this, but I don't have the ability to do it (where "this" is the output 200 wordle words challenge #esoteric-python message using builtin things):
Theoretically this should make a valid solution (not golfed for clarity): ```py
import random, itertools
random.seed(<seed>)
[print(word) for word in random.sample(itertools.permutations(['a', 'e', 'i', 'l', 'p', 'r', 's', 't'], 5), 200)]
The idea of this is that the length 5 permutations of the characters `['a', 'e', 'i', 'l', 'p', 'r', 's', 't']` make 245 valid wordle words. I found this character set using a different brute force program.
Since you can set the seed `random` uses, you should be able to find a seed where the first 200 samples of `random.sample` produce only the wordle words. This is very unlikely, since there are 6720 permutations, but it should be possible. Brute force won't work (I tried, you'd have to check 10^96 seeds), but given that the [Seed esolang](https://esolangs.org/wiki/Seed) exists which is also based on a Mersenne twister (like the `random` module), it should be possible to reverse the desired output into a seed, making for an extremely short solution.
The main issue is that I have completely failed to understand any of the reversing algorithms, or how they would be applied to this case. Hopefully someone else here has that required knowledge to complete the golf.
would 10^96 possibilites mean the hash should be around log_2(10^96) = 320 bits of information, or around 40 bytes long?
Maybe? I’m not 100% sure how hashes translate to the twister state, but you can set it directly so I guess it could also depend on that? The 10^96 comes from getting up to 24 words brute forcing from seed 0, then doing an exponential regression
in theory the total proportion of random samples of letter permutations that form 200 unique wordle words is given by
P(245, 200) / P(P(8, 5), 200) ~~ 10^-340
but with mersenne twister i think most of those sequences simply do not occur and you saturate the random state
But doesn’t the twister have a period of 2^19973-1, or about 10^6001?
I managed to find a sequence of 200 state inputs such that if you set the state to that + index 0, it does generate the 200 words. All the numbers are also relatively low (<10 million), so there are definitely a ton of working states. Still no clue how you could reverse that into a valid seed, since when using random.seed index is set to 646 so it instantly does a twist, and currently setting the 200 states is way longer than the portmanteau solution.
Hmm, maybe so
i thought this was fun #python-discussion message
!e also this ```py
fs = [lambda: i for j in range(3) if (i := j,)]
i = 7
print(fs1)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
7
!e also works with the expression part itself ```py
fs = [i := (j, lambda: i) for j in range(3)]
i = 7
print(fs[1]1)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
7
i actually don't know how the walrus is being used here :p
i haven't really ever used the walrus in python
Bro, why does the interpreter interpret like this..
I didn’t even get it until i asked an AI
It’s basically a dumb hack to make i exist from what i understand
interestingg
someone give me a program that prints the string "hi"
Easy, we just create a list of integers with the length of two, increment by one until they’re equal to the ASCII values of h and i, then print a string joined by the rune representation of the characters of that list
print("hi")
I expected more from esoteric python
Soynds good. How exactly do you do this?
specifications
walrus in a comprehension puts a name into the global scope
this is actually more for #esoteric-python, bcoz normal things are rarer
i golfed it
...or you can interpret it that way
!e ```py
z=[0]*2
while'a'[:z[0]==ord('h')<ord('i')==z[1]]<'0':z[0]+=b'h'[0]^z[0]>0;z[1]+=b'i'[0]^z[1]>0
print("".join(chr(0x16a0+b"fvufyfvuafvuyafvurcfkfvgfwhfvunfvifjfvuypzfsfvutfvbfvuemfvlfvudofvuyarckgqx".index(z|b' '[0]))for z in z))
:white_check_mark: Your 3.13 eval job has completed with return code 0.
ᚺᛁ
no POC 👎
!e
import random
random.seed(0x37abe)
print("%c%c" % (random.randrange(256), random.randrange(256)))
:white_check_mark: Your 3.13 eval job has completed with return code 0.
hi
!e ```py
print(
print
.self
.dir()
.getitem(121)
.getitem(slice(1,3))
)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
hi
wait what is this channel about
read the channel description
Something like this
okay... Black magic
Or this
My PB for https://github.com/python-discord/code-jam-12-qualifier is ||468 bytes|| (qualifable solution)
(Note that sharing solutions before the deadline is frown-upon)
ahh 👍
looks like in general it is for assignment within an expression
not sure why that needs to exist tbh
I've been thinking quite a while about making a script that instead of using another file as storage, it uses itself
shitcode but it works lol
with open(__file__) as f:
lines = f.read().strip().split("\n")
start = lines.index('"""')
names = lines[start+1:-1]
print(names)
while True:
name = input(":")
if not name:
lines = lines[:start]
lines.append('"""')
lines.extend(names)
lines.append('"""')
with open(__file__, "w") as f:
f.write("\n".join(lines))
exit()
names.append(name)
"""
"""
could even store an sqlite db in here
maybe save the file on the script, when the script is ran create it again, save and delete
idk if it might be possible to create a sqlite database from bytes
!e you could store in the bytecode then marshal this into a .pyc ```py
c = compile('a = 3', '', 'exec')
new_c = c.replace(co_code=c.co_code+b'CUSTOM DATA GOES HEREE')
print(new_c)
import dis
dis.dis(new_c)```
:x: Your 3.13 eval job has completed with return code 1.
001 | <code object <module> at 0x7f7395c3cd50, file "", line 1>
002 | 0 RESUME 0
003 |
004 | 1 LOAD_CONST 0 (3)
005 | STORE_NAME 0 (a)
006 | RETURN_CONST 1 (None)
007 | Traceback (most recent call last):
008 | File [35m"/home/main.py"[0m, line [35m6[0m, in [35m<module>[0m
009 | [31mdis.dis[0m[1;31m(new_c)[0m
010 | [31m~~~~~~~[0m[1;31m^^^^^^^[0m
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/67PNRPBVIWPTI75EBEVCHIZNWA
Objects/codeobject.c lines 472 to 482
if (PyBytes_GET_SIZE(con->code) > INT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"code: co_code larger than INT_MAX");
return -1;
}
if (PyBytes_GET_SIZE(con->code) % sizeof(_Py_CODEUNIT) != 0 ||
!_Py_IS_ALIGNED(PyBytes_AS_STRING(con->code), sizeof(_Py_CODEUNIT))
) {
PyErr_SetString(PyExc_ValueError, "code: co_code is malformed");
return -1;
}```
الرقم_الأول = float(input("أدخل الرقم الأول: "))
الرقم_الثاني = float(input("أدخل الرقم الثاني: "))
المجموع = الرقم_الأول + الرقم_الثاني
print("المجموع هو:", المجموع)```
المجموع هو: 16.0
What is this
Python in Arabic
it works
Based on your input
Yeah lol someone shared Python in Chinese xD
i'm very tempted to use this in the next program i send to someone
How, it's got a parenthesis in the variable
i don't think it does
Look xD
one of my bosses is chinese
i should send them a program like this
lol
Looks Japanese but not 100% sure
Doesn't matter lol
yeah it's japanese
x = [0,0,[]]
0 and [] means False?
they're falsy, not False
Wdym?
!e ```py
print(f"{0 == False = }")
print(f"{[] == False = }")
if 0:
print("zero is truthy")
else:
print("zero is falsy")
if []:
print("[] is truthy")
else:
print("[] is falsy")
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | 0 == False = True
002 | [] == False = False
003 | zero is falsy
004 | [] is falsy
i guess not
well i mean 0 == False actually
but [] is not
i think is is the more fair comparison, but this is also strange
0 is not False and [] is not False
0 == False but [] == False
but 0 and [] are both falsy, i.e. when you turn them into a boolean, they return False
I mean there're somethings like not() is false and [] is false
Do you know them?
0 is false bro
not isn't a class
0 == False but 0 is not False
Yeah not a def *
Oh I didn't mean a value like 0 = False
I mean in logic
!e not simply inverts the result of the boolean ```py
print(not False)
print(not True)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | True
002 | False
this depends on the language, but in python it is
!e print(not())
:white_check_mark: Your 3.13 eval job has completed with return code 0.
True
Huh?
that's equivalent to not tuple()
💀 ?
() is an empty tuple
Yeah
Yeah not * anything is the opposite
empty tuple
vv
not()
^^^
operator
!e if():
pass
else:
print("this is weird")
:white_check_mark: Your 3.13 eval job has completed with return code 0.
this is weird
an empty tuple is falsy
empty tuple is false
!e ```py
print(chr(sum(range(ord(min(str(not())))))))
:white_check_mark: Your 3.13 eval job has completed with return code 0.
ඞ
Bro False != Falsy? just to understand
yup
What's it then?
just because it's falsy doesn't mean it's False
What's the mean Falsy?
its boolean value is False
oh
so when you call bool() on it, it returns False
!e
print(0 is False)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | /home/main.py:1: SyntaxWarning: "is" with 'int' literal. Did you mean "=="?
002 | print(0 is False)
003 | False
xd
if and while internally call bool() on things too
Opposite of falsy is truely?
truthy
truthy
no
??
the boolean value is false, the original value is not
the original value of [] is the list itself, and its boolean value is False
oh
I understood this one
the boolean value is not the origin
This no
those statements are the same i think
it means [] has a boolean value of False, but the original value of [] is not False
😭 Someone said empty tuple is false
they probably meant it's falsy
empty python things are usually falsy
!e print( bool( () ) )
Look
So, it's false
:white_check_mark: Your 3.13 eval job has completed with return code 0.
False
ugh is () even "falsy"?
!e ```py
if () == False:
print("() is False")
else:
print("() is a falsy object")
:white_check_mark: Your 3.13 eval job has completed with return code 0.
() is a falsy object
is "falsy" defined via == or via bool()?
via bool()
ah
See this guys
this wording is strange to me, though. 0 == False but 0 is not False
but it's confusing to just print the result bool()
yea
False is an instance of bool, 0 is an instance of int
so the first two lines here don't seem to test if () is False to me
python considers them equal along with 0.0 and -0.0 (from float), but they're not the same object
they also test if () is a different type of falsy
!e ```py
if () is False:
print("() is False")
else:
print("() is a falsy object")
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | /home/main.py:1: SyntaxWarning: "is" with 'tuple' literal. Did you mean "=="?
002 | if () is False:
003 | () is a falsy object
is, ==, and bool() can all be different
print(not(False),not(True),not(None),not(tuple()),not())
True false true true true
not will always make it the opposite
😭 When it becomes true or false??
True and False are not numbers
But 0 in bool is false
0 is neither True or False
Huh
is for identity equality (i.e. memory address is equal), == for comparative equality (i.e. using __eq__), bool() for getting the boolean value (i.e. truthy or falsy)
0 "converted" to bool - via a function that takes 0 as input, and spits out False
0 itself is never False
0 itself is not False
but python considers them equal using ==
True == 1 and False == 0, but that doesn't mean 1 is True and 0 is False
0/1 are ints
False/True are bools
!e ```py
print(0 == False)
print(f"{type(0) = }")
print(f"{type(False) = }")
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | True
002 | type(0) = <class 'int'>
003 | type(False) = <class 'bool'>
no, that means it's equal to False
it's not False
.-.
it's equal to False
i believe there's only one "False" value in python. (if you have a list of many Falses, the list just holds many copies of the same reference to the same place in memory - hope i worded that right)
similarly, there's only a single 0 value in python. and it's a different value than False
then, you can just decide the output of comparing them using == or applying bool()
they are different values, but doing 0 == False can still output True
In Binary and C++ and most of the languages 0 is treated in boolean as false
yes
so python inherits the fact that 0 is equal to False
but 0's type is int, and False's type is bool
I mean in the output
When it's false it outputs 0
in C++
and BIN
and some other langs
### Helps with help command ###
مساعدة="help"
help("".join((lambda x=ch: x)() for ch in مساعدة))
😭 Bilingual code wild
And in python every object (including those that you'd treat as fundamental) is a struct.
Treat True and False as special singletons that python distinguishes for conditional operations. Additionally python knows how boolean values are implemented in eg.: C, so it pretends that booleans are similar to integers: issubclass(bool, int) -> True; True + True == 2, ....
But if booleans / integers were fundamental objects in python, something like this wouldn't be possible:
!e ```py
A hack for circumventing class protiection implemented by python interpreter
class A:eq=lambda s,o:o
(bool.dict==A())["fictional_attr"] = "Hello World!"
print(True.fictional_attr)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
Hello World!
!e
### Helps with help command ###
مساعدة="help"
help("".join((lambda x=ch: x)() for ch in مساعدة))
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | Help on _Helper in module _sitebuiltins object:
002 |
003 | help = class _Helper(builtins.object)
004 | | Define the builtin 'help'.
005 | |
006 | | This is a wrapper around pydoc.help that provides a helpful message
007 | | when 'help' is typed at the Python interactive prompt.
008 | |
009 | | Calling help() at the Python prompt starts an interactive help session.
010 | | Calling help(thing) prints help for the python object 'thing'.
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/PKPZKUO3E2ZTF6YBSTNCXWCDJA
Hmm wtf
.bm
!e
print([None] * 1000])
:x: Your 3.13 eval job has completed with return code 1.
001 | File [35m"/home/main.py"[0m, line [35m1[0m
002 | print([None] * 1000[1;31m][0m)
003 | [1;31m^[0m
004 | [1;35mSyntaxError[0m: [35mclosing parenthesis ']' does not match opening parenthesis '('[0m
!e
print([None] * 1000)
:white_check_mark: Your 3.14 pre-release eval job has completed with return code 0.
[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, Non
... (truncated - too long)
Full output: https://paste.pythondiscord.com/PBMP7RUII6AKHWQPLWAOQXAKUE
print(''.join(map(chr, [72,101,108,108,111,44,32,119,111,114,108,100,33])))
!e print(''.join(map(chr, [72,101,108,108,111,44,32,119,111,114,108,100,33])))
:white_check_mark: Your 3.13 eval job has completed with return code 0.
Hello, world!
_ = lambda __ : __()
__ = lambda : chr(72)+chr(101)+chr(108)*2+chr(111)+chr(44)+chr(32)+chr(119)+chr(111)+chr(114)+chr(108)+chr(100)+chr(33)
_(__)```
!e _ = lambda __ : ()
__ = lambda : chr(72)+chr(101)+chr(108)*2+chr(111)+chr(44)+chr(32)+chr(119)+chr(111)+chr(114)+chr(108)+chr(100)+chr(33)
_()
:warning: Your 3.13 eval job has completed with return code 0.
[No output]
this is how boolean algebra works
in factor, true is -1
which is cute
signed 1-byte value
!e ```py
print(~False) # True?
:white_check_mark: Your 3.13 eval job has completed with return code 0.
-1
(abusing two's complement)
!e
print(~True)
:white_check_mark: Your 3.13 eval job has completed with return code 0.
-2
What
its bitwise NOT
True is 1 or 0b0000_0001(assume 8 bit signed integer for example) in binary, bitwise not turns it into 0b1111_1110 which is -2
same for False, which is 0 or 0b0000_0000 and bitwise not turns it into 0b1111_1111 which is -1
search up "bitwise operations"
i do already know them
they're just like the ones from boolean algebra
not, or, and, xor
bitwise mean the operation apply on each bit
Yeah
And do you know two's complement?
i almost remember it from a redstone video from minecraft, i think its like an algorithm with bytes?
mainly used for addition and subtraction i think
@cerulean wadi 
Tyy
I swear I didn't understand
uh man this channel is for mad people finding crazy things
So part one of the weirdness is: True is equal to 1, and False is equal to 0.
Then you look at the binary representation of 1 and 0, and look at what happens (w.r.t. two's complement) when you flip each bit.
print(not True) = False
Isn't ~ means not?
💀 My whole life was a lie
!e
x = 7
print(bin(x))
print(bin(~x))
:white_check_mark: Your 3.13 eval job has completed with return code 0.
001 | 0b111
002 | -0b1000
well, that's not very helpful
It's how the number would be represented in two's complement, which is what Python's ints are based on. Sort of.
ohh I got it so the number system of Python made with Binary System?
Yes. ints with a different binary encoding than floats, but yes, in the end every value must be encoded in binary, because that's how computers work.
Yeah that's why I won't join AI field even if I die
Btw what's ur field in Python?
I'll tell you in #ot0-psvm’s-eternal-disapproval :)
ok
hi everyone
context: #python-discussion message
Asked claude and it suggested using type, so I did this to test, which works, but there's still something wrong, the keybind works as expected, but it doesn't show up in the footer, it ought to, so I think there's still something I'm missing when using type, probably in the dict?
from collections.abc import Callable
from textual.app import App, ComposeResult
from textual.binding import Binding
from textual.screen import Screen
from textual.widgets import Footer
def include_bindings[T: Screen | App](field: str) -> Callable[[type[T]], type[T]]:
# build a bindings list from settings, hardcoded it for testing
bindings = [Binding("w", "quit", show=True)]
def wrapper(cls: type[T]) -> type[T]:
NewClass = type(
cls.__name__,
(cls,),
{
"BINDINGS": bindings,
"__module__": cls.__module__,
"__qualname__": cls.__qualname__,
},
)
return NewClass
return wrapper
@include_bindings("")
class Test(App):
def compose(self) -> ComposeResult:
yield Footer()
def on_mount(self):
self.notify(str(self.active_bindings.keys()))
if __name__ == "__main__":
Test().run()
sir this is #esoteric-python
run before your code get turned into a golf ball
and I figured you guys probably would know what witchery to do to make this work 🤷♂️
fair
replace py bindings = [Binding("w", "quit", show=True)]
with```py
bindings = [("w", "quit", "Quit")]
or just pass "Quit" as third positional argument to Binding
and show default value is True
oh yeah I'm dumb
I knew it, but I just forgot 💀
well, that was anticlimactic
into the void of useless info it goes
toyed with your snippet, and got more than i hoped for
Python 3.13.5 (main, Jun 21 2025, 09:35:00) [GCC 15.1.1 20250425] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class A:__eq__=lambda s,o:(s,o)
...
>>> (bool.__dict__==A())[1]['__doc__'] = "A natural number"
>>>
>>> help(True)
Segmentation fault (core dumped) python
yup, mappingproxy.__req__ strikes again
(there's no __req__())
yea, so the comparefunc falls back on using the second arg (A())'s __eq__ with the mapping proxy's wrapped dict as the argument
because mappingproxy richcompare just calls richcompare on its wrapped dict
Objects/descrobject.c lines 1232 to 1240
static PyObject *
mappingproxy_richcompare(PyObject *self, PyObject *w, int op)
{
mappingproxyobject *v = (mappingproxyobject *)self;
if (op == Py_EQ || op == Py_NE) {
return PyObject_RichCompare(v->mapping, w, op);
}
Py_RETURN_NOTIMPLEMENTED;
}```
RichCompare tries to compare ->mapping (dict) with w (A()) and fails with dict.__eq__, so it falls back on using A().__eq__
and yea whoops, there is no __req__ dunder, i need to go to bed
and that.. segfaults-?
it gives the user a reference to the wrapped class dict
directly mutating it violates rules with the attribute cache
so it can cause weird errors when the attribute cache is in one state for the class, and the actual backing storage is in another state
fishhook/fishhook.py lines 141 to 143
getdict(type)['__base__'] = __base__
# call PyType_Modified to reload cache
pythonapi.PyType_Modified(py_object(type))```
to make the attribute cache sane again, you need to call PyType_Modified (which actually just invalidates the cache entirely)
also, just for reference, you can actually fully implement PyType_Modified in python if you have rw to a classes backing memory: https://github.com/chilaxan/pysnippets/blob/d70b4e642dedeb358094b3d249f9ec9af9c55156/small_hook.py#L37-L45
small_hook.py lines 37 to 45
def PyType_Modified(cls):
cls_mem = getmem(id(cls), sizeof(cls), 'P')
flags = cls.__flags__
flag_offset = [*cls_mem].index(flags)
if not cls.__flags__ & Py_TPFLAGS_VALID_VERSION_TAG:
return
for subcls in type(cls).__subclasses__(cls):
PyType_Modified(subcls)
cls_mem[flag_offset] &= ~Py_TPFLAGS_VALID_VERSION_TAG```
is it known that messing with mappingproxied types could cause segfaults ?
or it's that req taps directly into cpython structs and i managed to assign something wrong into an object field
ah I didn't see the discussion above. reading now
Interesting, but it works for me...
Python 3.13.1 (tags/v3.13.1:0671451, Dec 3 2024, 19:06:28) [MSC v.1942 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class A:__eq__=lambda s,o:(s,o)
...
>>> (bool.__dict__==A())[1]['__doc__'] = "A natural number"
>>> help(True)
Help on bool:
True
A natural number
>>>
funny, different os and build though
works on ubuntu 24.04 for me```py
Python 3.12.3 (main, Jun 18 2025, 17:59:45) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
class A:eq=lambda s,o:(s,o)
...
(bool.dict==A())[1]['doc'] = "A natural number"
help(True)
(it makes interactive ui that i can scroll up and down)
it also crashes for me
Python 3.13.2 (tags/v3.13.2:4f8bb39, Feb 4 2025, 15:23:48) [MSC v.1942 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class A:__eq__=lambda s,o:(s,o)
...
>>> (bool.__dict__==A())[1]['__doc__'] = "A natural number"
>>> help(True)
E:\co> ```
exit code is -1073741819
and it doesn't crash on 3.12.9```py
E:\co> py -3.12
Python 3.12.9 (tags/v3.12.9:fdb8142, Feb 4 2025, 15:27:58) [MSC v.1942 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
class A:eq=lambda s,o:(s,o)
...
(bool.dict==A())[1]['doc'] = "A natural number"
help(True)
Help on bool:
True
A natural number
considering that it does crash on 3.13.2 and 3.13.5, and doesn't crash on 3.12.9, 3.12.3, 3.13.1
its bug since 3.13.2
interesting
wow, in all this foolery we're maybe uncovering a real bug
foolery?
you do realize that 90% of bugs in "interpreters" comes from esoteric code?
sorry i didn't mean it as an insult, i like trying to poke around language construct in all possible ways
wait
E:\co> py
Python 3.13.2 (tags/v3.13.2:4f8bb39, Feb 4 2025, 15:23:48) [MSC v.1942 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class A:__eq__=lambda s,o:(s,o)
...
>>> (bool.__dict__==A())[1]['__doc__'] = "A natural number"
>>>
>>> help(True)
Help on bool:
True
A natural number
>>> ```somehow it didn't crash this time
but it's the first time i witness a potential bug being discovered like htat
it might be dependent on memory allocation state
>>> (bool.__dict__==A())[1]['__doc__'] = "A natural numberfweifewifjweiofjweifjfjewiofwe"
>>> help(True)
Help on bool:
True
<python-input-11>
>>> ```intresting
that's out of my league but maybe when the assigned string can exist in the right spot / page sometimes and forbidden some other times
and now somehow crashed on 3.12.9
heisenbug
I saw something similar yesterday
at one point I think the docstring from another type got used instead
maybe there's some hashing creating cache collisions
ok
so here it is
I got it
kinda
so
it breaks on running help after second time you reassign it but only if you run help before the 2nd reassign
which is weird
¯_(ツ)_/¯
the bug itself is kinda weird
I hate to break it to you, but this bug has been known about for a while
whats the actual bug and where is the report?
And yes, it's gonna be behave different on different system, because the allocations might be in different orders or laid out differently
It was reported on github a while back. I'll see if I can find it.
it does seems like a memory bug
This would be a logic bug tbh I think
Although the attribute cache inconsistency could be seen as a memory bug
attribute cache?
i've been searching through Objects/typeobject.c to know where but i just can't figure it out..
PyType_Modified sets a flag (how does that reset?), getting/setting .__doc__ has descriptors but i don't see how modifying the dictionary can make it segfault-
Honestly, I've haven't dug into the attribute cashes inner workings in a while, but I can take a look at tracing it later today
but.. my claim to fame e_e !
interesting comments too, TIL
Trust me, there are plenty of other bugs to still to find, just gotta dig for them
fuzzes cpython manically
(like the occasional bugposter segfault-finder in #internals-and-peps)
I'd say the actual bug is that overriding __eq__ gives you back an "unstable" object
what the hell is a mapping proxy anyway
Mappingproxy is a type that's used to provide a read only dictionary that is not meant to be accessed directly
not too far from Proxy uses in other languages (js, java,. ..)
I am French and on Visual Code Studio I cannot install Selenium in my terminal. Could someone translate everything into French in a private message please?
wtf
hello, this is#esoteric-python
exec is the most important and next is globals. from there everything else is simple
i'd like to add getattr to the list