#esoteric-python
1 messages ยท Page 65 of 1
it is
Any idea how to rework it into my lib?
oh haha i just ran into the issue pastebean had py_object((((((((((((<NULL>, <class 'ctypes._endian.BigEndianStructure'>), ...
Traceback (most recent call last):
File "testing3.py", line 39, in <module>
[1] 3928 segmentation fault (core dumped) python3 testing3.py```
well at least it gave me the traceback first
okay so i've tried doing this but it still doesn't work, despite doing exactly what @sick hound did (that is, assignment of frame.f_lineno). the only difference is that i didn't do it from within a trace function. instead, i modified the memory a bit to trick it into thinking it's in a trace function, but it's actually not. still, it doesn't work and i'm adamant to know why :D
darn
@brisk zenith gonna do more phone dev, what specifically should I look into for fixing this?
hmm.. i honestly have no idea
it's a very low-level thing though, beyond bytecode. this is modifying the content of C structs for frames in memory :D i recommend that you have a good play around with ctypes though
Ctypes is amazing
Oh Juanita wanna work with me on adding the stuff recommended by pastebean?
Or wait
What random suggested*
what's that?
Basically messing with name/fast/const access
And uh
Changing scope of a frame/function
Stuff like that
>>> import numpy as np
>>> def f1(x):
... np.array([float(x)])
...
>>> def f2():
... return np.empty((), dtype=np.float).tolist()
...
>>> f1(1964.5)
>>> f2()
1964.5
>>> @CFUNCTYPE(py_object, py_object)
... def new_boolrepr(self):
... return "lol no"
...
>>> bool_struct = PyTypeObject.from_object(bool)
>>> bool_struct.tp_str = new_boolrepr
>>> print(True)
lol no
>>>
i'm going to attempt to map out as many C struct into ctypes.Structure classes as i can
got enough working that builtin types can be modified very easily
>>> x = 99999999999999999
>>> int_struct = PyLongObject.from_object(x)
>>> int_struct.ob_digit[0] += 1
>>> x
100000000000000000
>>>
ints are now mutable
>>> x = 5
>>> int_struct = PyLongObject.from_object(x)
>>> int_struct.ob_digit[0] = 4
>>> 2 + 2 == 5
True
>>>
now we've got a reasonably clean way of doing this lmao
i mean, we've done this sort of thing here many times before. i'm just writing a helper so that it makes more sense. the alternative is to have a bunch of magic numbers in the code ```py
digit = c_uint.from_address(id(5) + 24) # 24 what?
digit.value = 4
2 + 2 == 5
True
Ah ok
the 24 is there because the actual content of an int is stored 24 bytes after the beginning of the int itself, but you can't really tell that from the code
That's really cool tho
ty ๐
i mean, i could throw it in a hastebin for now. really it's just a bunch of dirty ctypes.Structure subclasses. so far i've only done basic stuff (namely, object, int, and all the structs that they need to function)
it's difficult to do it cleanly, but i tried my hardest to make it look okay lmao
code: https://paste.pydis.com/abumotoyec.py
i'm mostly just copying the definitions from these:
https://github.com/python/cpython/blob/master/Include/object.h
https://github.com/python/cpython/blob/master/Include/cpython/object.h
i think i'll do lists now
?
true is an int anyways, technically
well, bool is a subclass of int, technically, and True has the numerical value 1
Sorry
Actually, we turned bool into int, oops ```py
bool
<class 'int'>```
that's quite easily done using my code i believe
Don't set random pointers, you might turn bool into int :P
haha nice
>>> False
0``` Which means False is also 0 now
i mean technically they're not even defined as bools or whatever internally, they're PyLongObjects ```c
struct _longobject _Py_FalseStruct = {
PyVarObject_HEAD_INIT(&PyBool_Type, 0)
{ 0 }
};
struct _longobject _Py_TrueStruct = {
PyVarObject_HEAD_INIT(&PyBool_Type, 1)
{ 1 }
};
we overwrote &PyBool_Type with int apparently
>>> type(0) is type(1)
1
>>> type(0) is type(True)
0```
this is confusing
firstly, it's returning 1 and 0 instead of True and False
Oh, i see now
and also if you do type(True) it says it's an int? ```py
type(True)
<class 'int'>```
True gets printed as 1 ```py
True
1```
and does type 0 also return class 'int'
yes
>>> bool_struct = PyTypeObject.from_object(bool)
>>> int_struct = PyTypeObject.from_object(int)
>>> bool_struct.tp_repr = int_struct.tp_repr
>>> bool_struct.tp_name = int_struct.tp_name
>>> True
1
>>> False
0
>>> bool
<class 'int'>
>>>
using my helper code above
id(type(True)) vs id(type(1))
>>> PyObject.from_object(True).ob_type[0] = PyTypeObject.from_object(int)
>>> type(True)
<class 'int'> : # colon to make the syntax highlighting happy
>>> type(1)
<class 'int'> : # ignore these colons
>>> id(type(True))
1783558432
>>> id(type(1))
1783601632
>>> True
1```
It's not usable in prduction sadly.
of course, but it's fun to play with
esoteric python stuff is not meant to be used in production, it's meant to be fun and really weird
And it teaches you a lot aswell.
hacking the python internals is a fun way to find out about them :P
as someone who would like to eventually make contributions to cpython, i think this is the best way to learn about the internals
if you can break something then fix it you've probably understood enough about it to expand on it
>>> a = object()
>>> struct = PyObject.from_object(a)
>>> b = struct.get_object()
>>> b is a
True
>>> struct.ob_refcount
2
>>> del b
>>> struct.ob_refcount
1
>>>
implemented a get_object method
simple enough, just ```py
def get_object(self):
ptr = c_void_p(addressof(self))
return cast(ptr, py_object).value
works at any depth of the struct ```py
obj_type = struct.ob_type.contents.get_object()
obj_type is object
True
>>> my_list = [1, [2, "hello"], 3]
>>> struct = PyListObject.from_object(my_list)
>>> inner_list = struct.ob_item.contents[1].contents.value
>>> inner_list
[2, 'hello']
>>>
accessing list items has never been so easy
oh boy
back when the comparison operators returned actual ints, True and False didn't exist
re. True being 1
Didn't python 2 just have True = 1 and False = 0 instead of being reserved keywords?
Yeah pretty much
You could (still can in 2.7.16) reassign them to completely different values
The bool type still existed though
Oh huh
# Python 2
>>> True == 1
True
>>> isinstance(True, bool)
True
>>> isinstance(True, int)
True
# Python 3
>>> True == 1
True
>>> isinstance(True, bool)
True
>>> isinstance(True, int)
True
Guess I was wrong
Yeah the only difference is that it's reserved in Python 3
i remember when i was fascinated by the idea that True is an int. 
Oh that's a bit odd that it's both and int and a bool still in python 3
looks like bool was added in Python 2.3
Does bool just inherit int?
5.9 Comparisons
I believe so
>>> issubclass(bool, int)
True
Time to pyenv install 2.1.3
yep
Python 2.1.3 (#1, Apr 8 2019, 19:35:49)
[GCC 8.2.1 20181127] on linux5
Type "copyright", "credits" or "license" for more information.
>>> True
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'True' is not defined
>>> 1 == 1
1
huh
what's it do
๐
>>> type(69L)
<type 'long int'>
Yeah just suffixing numbers with L gives you a long int
Yeah python2 used to make you manage your int lengths a lot more than python3 does
It's always funny when python3 ints have arbitrary precision so a // gets the exact value for a massive number, but because floats don't, if you just use int(... / ...) you can sometimes get a wildly different number
well i'd hope that any int arithmetic is accurate in any language, because integers never get recurring decimals like floats do (which is more or less why they can be imprecise)
I wish more languages used rational representations instead of floating point.
e.g. 1 / 3 = 1/3
from fractions import Fraction
If you want it like that
I know it's possible, it's just a bit more complicated than it could be.
Floats are way faster than fractions iirc
For which operations?
Trigonometry of course, and logarithms, but they are inexact anyway.
Multiplication seems like it would go a lot quicker with fractions than with floats.
Same with division.
Actually, I guess the hard part would be factorising the numbers
The fractions module is written in pure python
(sorry if this is the wrong place to ask)
can this factorial function be made any shorter? it only needs to work for n>0 py f=lambda n:n**(n>0)*(n==0*1or f(n-1))
f=lambda n:n==0 or n*f(n-1)```
I got this
This looks like the standard regular function approach I think.
you can save 2 characters like this btw py f=lambda n:n<1or n*f(n-1)
and if you memoize it, then the running times aren't horrible either, as far as I understand!
@gentle pagoda what happens with f(-1)
i dont want to deal with n<0 because it makes the code longer xd
if you find a clean way of doing it im really interested tho
reminds me of my n>0 fibonacci implementation
ooh nice, how tf does that work?
It's a formula for calculating the nth element of the sequence. Without calculating the rest of it
ooh thats really cool ๐
in case you wanna try it
the 1000th fibonacci number according to this is
26863810024486259428057328890462071226932128417886493703576991815165644098340129752887649389042242022037970113428562978866498563272624804026557522173602820491641993157883791984718503223913747590579636943192064
wow i need to look at that formula later. looks really useful
I think I found a decent way to do gotos but it's gonna be a pain to do properly line-number wise
Nvm we have dis.findlinestarts(code)
@brisk zenith I did it ๐
Ignore the 3044 that's left from debug prints
The trick: I simply replace the goto call with a JUMP_ABSOLUTE
Higher res
yeah i considered doing that but it would be neat to do it like a normal function without a decorator or something :D
yea
i guess the only difference in that case is that or short-circuits whereas | doesn't. as soon as or reaches a True, it stops and doesn't evaluate the rest of the conditions. to be fair though, the use of parentheses there is a sign that the person who wrote that code came from another language and hasn't adapted to python's syntax properly.
def is_triangle(a, b, c):
if(a <= 0 | b <= 0 | c <= 0):
return False
elif( a + b <= c or a + c <= b or b + c <= a):
return False
else:
return True
yeah, just looks poorly-formatted
you could change that to ```py
def is_triangle(a, b, c):
if a <= 0 or b <= 0 or c <= 0:
return False
elif a + b <= c or a + c <= b or b + c <= a:
return False
else:
return True
and it would work just the same
i am determined to at least figure out why my goto code didn't work. there's probably a better way to debug this, but i don't really care :D i have modified the interpreter slightly to show me exactly what's going on: ```py
import ctypes
import sys
def goto(line):
print("beep!")
def test():
print("first")
goto(13)
print("second")
print("third")
test()
gives me an output of ```py
DEBUG: entering frame 'test' (0x55fcc5f779b0)
first
DEBUG: entering frame 'goto' (0x55fcc5f77c10)
beep!
DEBUG: returning from frame 'goto' (0x55fcc5f77c10) to line 9 of 'test' (0x55fcc5f779b0)
second
third
DEBUG: returning from frame 'test' (0x55fcc5f779b0) to line 1 of '<module>' (0x55fcc5f6e370)
isnt this jmp
@brisk zenith have you got a goto func working?
class WrongType(Exception):
def __init__(s,func,right,inp={"OBJNONEFOREXCEPTION"}):
s.msg = "{} needs {}".format(func,right) if inp is {"OBJNONEFOREXCEPTION"} else "{} needs {}, not {}".format(func,right,NKfunc.typeName(inp))
__str__ = (lambda s: s.msg)```
lambda is fun
:)
any([i <= 0 for i in [a,b,c]]) works as a <= 0 or b <= 0 or c <= 0
nope, at least in the way you have it, it's a bit different
any(i <= 0 for i in [a,b,c]) would be kinda same
because in your case it will evaluate all the conditions
and then would pick first truely if there is first truely
Python 3.8.0a3+ (heads/master-dirty:2fb2bc81c3, Apr 11 2019, 12:28:57)
[GCC 8.2.1 20181127] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> Maybe
True
>>> Maybe
False
>>>
i have successfully modified the python interpreter for no good reason
Maybe i have successfully modified the python interpreter for what may be a good reason
>>> Maybe = 1
File "<stdin>", line 1
SyntaxError: cannot assign to True
>>>
``` this is rather queer
@brisk zenith i assume you used the helper thing you made?
actually, no. i'm modifying cpython here.
although we did have a challenge recently of implementing Maybe in pure-python. on that topic, i need to merge those submissions
wow spicy
here's my cpython modification for Maybe: https://github.com/kingdom5500/cpython/tree/shenanigans/maybe-keyword
i'm gonna continue making changes so that Maybe = "hi" gives a proper error
Someone in another chat wanted a way to get all different capitalizations of a word.
So I made this.
f=lambda w:w==""and[""]or[c+s for s in f(w[1:])for c in[w[0].upper(),w[0].lower()]]```
f=lambda w:w and[c()+s for s in f(w[1:])for c in[w[0].upper,w[0].lower]]or[""]```
nice
Is there a way to make JUMP_ABSOLUTE set the bytecode pointer at module scope not at local scope without cpython modification?
@brisk zenith hacking the cpython it self is funny thing
i tried to implement new grammars like goto challange you made here in the past. It is really easy to modify it
also James Powell has great talks about it
This is the patch for adding a new conversion char to paths
I'm trying to see how far I can get with just internal bytecode stuffs
So glad that python has useful error messages
i think this is the equlivent of segfault on posix
yes it is
Yee
using ctypes?
That was from ```py
LOAD_GLOBAL 0
LOAD_CONST 0
CALL_FUNCTION 1
RETURN_VALUE
Where the consts tuple was just (print,)
The stack's set to 99 just to be safe, but I can't work out what's up with it
Oh nvm lol
I should have just LOAD_CONST'd the first and not tried to load print as a global
print isn't a const
It is if you define it as one ๐
oh dear
print is a name
: (
I did a good and stopped passing it as a const
Shame there's no JUMP_ABSOLUTE that'll break out of the current section of bytecode
what do you mean?
In something like this the jump just goes to the start of the code being executed
Instead of, say, a jump to the very first bytecode instruction
ah, yeah. you'd have to modify the bytecode of other frames which, although very possible, is probably very difficult to get right without fucking up a ton of stuff
Would it not be almost impossible because of CALL_FUNCTION encapsulating things?
So you'd need some way to cleanup some things while transferring other things into the new scope
i've tried doing this by modifying the attributes of the previous frame object. do you know what frame objects are?
Roughly. The frame for the current block of code is the object that contains info about the current execution state, the namespace, etc.?
yeah, pretty much. it also contains the index of the last instruction executed. i thought that changing this value would change where the interpreter resumes execution in that frame, but that doesn't work because frame.f_lasti is set by the interpreter, not checked by it. the only way i can think of doing it without using a trace function is by somehow modifying the value of next_instr in this function as it's simply a pointer to the currently executing intruction bytes. https://github.com/python/cpython/blob/master/Python/ceval.c#L1104
however, i don't think this is possible at all :D
that's just for my idea of a solution, though. if you can think of a way to do it differently, go ahead.
maybe @sick hound can figure out how to do what i'm thinking. is it possible to change the value of a variable in a running C function? i think this is getting even beyond #esoteric-python though haha.
to be fair that's probably a big XY problem right there
i don't know how C works on that level :D
is it possible? probably just about
probably incredibly difficult though
assuming you know exactly where the function called another function that eventually ran your code,
you could disassemble the function, find that CALL instruction, and figure out the difference between the esp/rsp value at that time and the place the variable you want to change is
(which would probably be easier in a debugger actually)
haha sounds 100% doable with python, sure :D
well you'd do that before writing the python code
the actual python code would get the address of the function, add the number of bytes between the CALL and the beginning of the function, and then look backwards through the stack to find that value
then it would subtract the other offset you found from the address it finds that CALL
that is an address that can be written to
...maybe
we only know a bit about assembly and that might be completely wrong ._.
but this is more #esoteric-c than #esoteric-python now
that is ok ๐ ty for your knowledge, i'll poke around a bit
also actually, a debugger would probably help
yeah for sure
>>> x = lambda a=None,b=[None]:[b.pop(),b.append(a),None][2] if a != None else b[0]
>>> x()
>>> x(1)
>>> x()
1
>>> x(None,[0])
0
>>> x()
1
>>>
``` anyone know why this happens?
@rugged sparrow without working through the whole thing by hand, I assume it's because the default b is the same list object every time.
Ah cool
Im writing a shoddy version of solitaire in one line and was having an issue due to thar
*that
Thought it was weird
Cause afaik wouldn't expected behavior be for default b to be a new list object every time?
nope
you can even use .__defaults__ and .__kwdefaults__ to get the default values
>>> f = lambda x=[], *, y=[]: (x, y)
>>> f()
([], [])
>>> f()[0].append(0)
>>> f()
([0], [])
>>> f.__defaults__
([0],)
>>> f.__defaults__[0].append(1)
>>> f()
([0, 1], [])
>>> f()[1].append(0)
>>> f()
([0, 1], [0])
>>> f.__kwdefaults__
{'y': [0]}
>>> f.__kwdefaults__['y'].append(1)
>>> f()
([0, 1], [0, 1])```
Thats cool
Much hackery later, and this now works
It will skip over print('a') and output b
And this works too
Just realized @ was a thing, so now there's a nicer syntax
Solution for the Maybe problem using a simple metaclass ^_^
i like that one. it's not perfect to the test cases but certainly a nice submission for it's simplicity. i'll merge it when i get on my computer next :)
I guess I can add a __str__ and __format__ for the metaclass for case of print(Maybe)
I think assignment can also be prevented somehow, I forget which method that invokes.
I tried doing Maybe and dang it's pretty satisfying when it throws up the error
neat!
How do you stop assignment?
And if you do - can you do it with a metaclass and add stuff like static typing?
I would assume not, at least not for a variable. Variables are references to objects; it makes sense that the objects themselves wouldn't get a say in assignment.
yup
the assignment part is probably the trickiest but there's been some really cool submissions which make a damn good effort :D
Yeah
...we have an evil idea...
Evil ideas belong here!
I used settrace and then just had it sys.stderr a fake "error" if it noticed a mutation to Maybe in the bytecode
It doesn't work if you try and put a debugger or something on it though, which is a pain
...we did something ```py
a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "wtf.py", line 7, in getitem
return super().getitem(item)
File "wtf.py", line 7, in getitem
return super().getitem(item)
File "wtf.py", line 7, in getitem
return super().getitem(item)
[Previous line repeated 329 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object```
>>> x = 4
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined```
wtf.py indeed
Well now everything is _getframe ```py
x
<built-in function _getframe>
what
<built-in function _getframe>
lol
<built-in function _getframe>```
we were not expecting that ```py
x = 5
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "wtf.py", line 14, in setitem
super().setitem(item, value)
AttributeError: 'frame' object has no attribute 'setitem'```
but i guess it makes sense ```py
super
<built-in function _getframe>```
this is amazing
Now it kind of actually does something ```py
x
'x'```
changing the type of locals()

>>> x
False
>>> y
False
>>> Maybe
True```
now Maybe is True and everything else is False
now everything is just False ```py
x
False
y
False
Maybe
False```
changed the type to bool?
nope
we're messing with locals()
we overwrote the type with our own class and we're changing the __getitem__ on that class
but since that gets called every time a variable is accessed we have to write it without using any variables
so we're writing it in bytecode
all of the functions we need to use like _getframe are constants
to get the arguments we use _getframe().f_locals
all variables are now randomly either 0 or 1 ```py
x
0
x
1
x
1
x
0
x
1
x
0
x
1```
we've turned everything into Maybe now ```py
x
True
x
False
x
False
x
False
x
True
x
False
x
False
x
False```
now everything's super ```py
x
<class 'super'> :
y
<class 'super'> :```
(ignore the extra :)
uh... hmm... ```py
x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "wtf.py", line 7, in getitem
# there is no source code for this function
RuntimeError: super(): class cell not found```
Now everything is an empty dictionary, oops... ```py
x
{}```
What's more interesting, the result you get when everything works or the weird errors you get when things don't work? :P ```py
x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "wtf.py", line 7, in getitem
# there is no source code for this function
TypeError: 'cell' object is not subscriptable```
i love the weird errors
i got a bus error yesterday
>>> 0x7ffd867b2bd8
[1] 30916 bus error (core dumped) ./python Test/goto_test.py
...from typing in a number?
did you mess with numbers or did the previous result have one reference and a weird/broken __del__
also we set up a function in a way that means its "source code" points to # there is no source code for this function
WE DID IT ```py
x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined```
@brisk zenith this is another Maybe implementation ```py
from ctypes import *
from sys import *
from sys import _getframe
from types import *
from random import *
there is no source code for this function
class PatchedLocals(dict):
getitem = FunctionType(CodeType(
2, 0, 2, 10, 0, b'd\0\x83\0j\0d\1\x19\0d\2k\2r\x1cd\5d\3d\4\x83\1\x83\1S\0d\6j\1d\0\x83\0j\0d\7\x19\0d\0\x83\0j\0d\1\x19\0\x83\2S\0', (_getframe, 'item', 'Maybe', getrandbits, 1, bool, dict, 'self'),
('f_locals', 'getitem'), ('self', 'item'), file, 'getitem', 7, b'', (), ('class',)
), {})
def setitem(self, item, value):
if item == 'Maybe':
raise SyntaxError("can't assign to keyword")
super().setitem(item, value)
def delitem(self, item):
if item == 'Maybe':
raise SyntaxError("can't delete keyword")
super().delitem(item)
py_object.from_address(id(locals()) + sizeof(c_ssize_t)).value = PatchedLocals```
oh neat :D
This is the most Python bytecode we have ever written.
by the way, the way that works is by changing locals()'s type to our own subclass of dict
the reason there's loads of bytecode in there is because to prevent recursion we had to implement __getitem__ without using any instruction that gets a local variable
so sys._getframe, random.getrandbits, bool and dict are all constants
also the reason we used random.getrandbits is because it's a builtin method, random.choice or anything like that is in Python and uses variables
huh nice
I have a funny idea
Is anyone here familiar with pysimplegui?
We could make a GUI scratch-like bytecode editor, with arrows for e.g. jumps and references
haha sounds interesting actually
My plan for this weekend is getting a nice inline ```py
bytec(
LOAD_GLOBAL(5),
CALL_FUNCTION,
)
Gonna be a pain though because I'll have to offset the JUMP_ABSOLUTEs following it
Or have a wall of NOPs
i've tried doing something similar to that but couldn't really be bothered to follow through with it. here was my decided syntax:
with __bytecode__:
LOAD_NAME ("print")
LOAD_CONST ("hello")
LOAD_FAST [0] # load local value at index 0
CALL_FUNCTION (2)
RETURN_VALUE
It should be pretty easy to do because the number of instructions that it'll be compiled to will be less than number it takes up to define
Constants like "print" and "hello" might be a bit of a pain because there's the possibility of a block of bytecode containing more than one with __bytecode__
yeah
it's easy to use a with block for that because the SETUP_WITH block also provides the bytecode location of the end of the block as its oparg
Oh really? That's actually pretty neat
so im nowhere near as talented as y'all are, but im working on a oneline card game and thought of this ```python
newCard = lambda card,suite:lambda self={
'card':card,
'suite':suite, #0:heart,1:diamond,2:clubs,3:spades
'visible':False
}:[
[
self.update({
'flip':lambda:self.update({'visible':not self['visible']})
}),
self.update({
'getCard':lambda:'โฅโฆโฃโ '[self['suite']]+self['card']
}),
self.update({
'printCard':lambda:print('โฅโฆโฃโ '[self['suite']]+self['card'] if self['visible'] else '[]',end='')
})
],
self
][1]
Ace = newCard('A',3)
Ace()'printCard'
Ace()'flip'
Ace()'printCard'```
I just realized earlier today that my goto implementation will crash python
"just realized earlier today"
It's 16:23 here
nice pleonasmic oxymoron :P
Because it jumps out of things like while without going over the bytecode instruction that tells the interpreter that it left those blocks, so after ages and ages it'll hit the block limit and error
oh
@rugged sparrow that reminds me very much of my early submissions for the esoteric challenges (before i became an event handler for them). my first attempt at one-lining something like that is the first pin of this channel, feel free to take a look. :D
@brisk zenith cool I'll check it out
(lambda a:setattr(a,'d',((lambda b:b(b))(lambda b:lambda f,x:(lambda c,d:lambda:c(*d))(b(b),(f,f(x)))))(lambda n:print(n)or n+1,0))or list(setattr(a,'d',a.d())for _ in iter(int,1)))(type('',(),{})())```
@sick hound does that count infinitely?
cool
@brisk zenith this is the first oneline/code golf i did
print(eval(f"(LB=Lc='X',b=L:int(input(a)),d=[*range(9)],e=Lp=print:[a,p('_'*7),[p('[4m',*a[x:x+3],'[0m',sep='|')for x in[0,3,6]]][0]:(Lb:[b]*9if 1in[all([b==a[int(x)]for x in str(list(map(ord,'รลสฆษถฦกฤอรถ'))[y])])for y in range(8)]else a)((Lb,c,d:[b.pop(c),b.insert(c,d),b][2])([e(d),e(a)],a,d.index(b(c)),c)if['X']*9!=a!=['O']*9else a,c):(L:'X'*(a==['X']*9)+'O'*(a==['O']*9)or'C')({'B('*9}[' ']*9){',a))'*4}))('O')".replace('L','lambda a,')))```
its tictactoe
oh interesting, i remember when there was a golfed tic-tac-toe round here that we got pretty damn short
don't think Someone is here anymore though, lemme see if i can find it.
tbh, with what ive learned since then, i could prob shorten it more
i=input;p=print
C=lambda a:max(a[b//6]&a[b//6+b%6]&a[b//6+b%6*2]for b in[1,3,4,9,14,15,19,37])
P=lambda b:p(*(['-xo'[i]for i in a]for a in[b[i:i+3]for i in(0,3,6)]),sep='\n')
def I(k):
if 1^k.isdigit():p('INTEGERS MORON');return
j=int(k)%9-1
if x[j]:p('Taken')
else:x[j]=I.g%2+1;I.g+=1
I.g=0
while 1:
if i('S or Q: ')=='Q':exit()
x=[0]*9
while 1^C(x)in(1,2):
P(x);I(i('Move: '))
if 0 not in x and not C(x):p('Tie');break
else:P(x);p('Winner is','x'if C(x)>0else'o')```
strings aren't shortened but you get the point
yea
to be fair, we often consider eval to be some form of cheating because we could just eval(compile(<bytecode>)) to make it ridiculously short
i think it checks if there's a win
ah nice
[all([b==a[int(x)]for x in str(list(map(ord,'รลสฆษถฦกฤอรถ'))[y])])for y in range(8)]``` this is how i check my win
it gives me all the valid win states for the board
[210, 345, 678, 630, 417, 258, 840, 246]
that's pretty smart
1597463007 :P
thanks
whats that number? @sick hound
@brisk zenith did you see my minesweeper? https://discordapp.com/channels/267624335836053506/303934982764625920/560951038820089876
it's a magic number
how so?
yeah i did see your minesweeper, it's pretty neat
thanks
google 0x5F3759DF
@brisk zenith
neat!
I had to rewrite all my bytecode parsing code because I realized extended args were a thing
ah yeah haha
we did another weird thing ```py
type(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x90 in position 0: invalid start byte```
this is extremely worrying, what have we done ```py
type(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb2 in position 1: invalid start byte
type(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x90 in position 0: invalid start byte
type(42)
<class ''> :
type(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe3 in position 4: invalid continuation byte
type(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe3 in position 4: invalid continuation byte
type(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb2 in position 1: invalid start byte
type(42)
<class ''> :
type(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe3 in position 4: invalid continuation byte```
@brisk zenith it looks like we set the name of int to a deallocated piece of memory... oops...
>>> int
<class '๐ณธx'>
>>> int
<class ''>
>>> int
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x88 in position 0: invalid start byte
>>> int
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x88 in position 0: invalid start byte
>>> int
<class '๐ณธx'>
>>> int
<class ''>
>>> int
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd8 in position 0: invalid continuation byte
>>> int
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd8 in position 0: invalid continuation byte```
...This isn't quite what we wanted but at least it's not "BOX x BOX" ```py
int
<class 'mol'>```
oh wait, we're stupid ._.
>>> type(0)
<class 'lol'>```
that's quite easy to achieve using my structs code from a few days ago :D
we renamed int to lol
we're going to make it possible to assign anything
the way we did that was by doing athing.__name__ = 'lol'
hm okay neat
with nearly the same code, we can also change the class of things
False is now this thing ```py
False
':\x00\x00\x00์ฐๆฉ\x00\x00\x00\x00\x00\x00ใงธๆจป\x00\x00อ \x00\x00\x00(\x00\x00\x00์ซฐๆจก\x00\x00\x00\x00\x00\x00'```
that's interesting ```py
x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
MemoryError```
object is now an empty string. that's not good. ```py
int.base
''```
the shit you get up to is hilarious at times. i'm just waiting for the day i see "oh yeah by the way bool is now a particle accelerator"
@brisk zenith oh yeah by the way bool is now a particle accelerator
>>> bool
<__main__.ParticleAccelerator object at 0x000000006A4EF120>```
lol
i'm sorry but what the actual fuck is that memory address
Lmao
0x6A4EF120
for fucks sake lmao
it's 1783558432
which is what the id of bool was before we made it a particle accelerator
that's not a sentence you hear every day
How do you even
i literally have no idea
i thought i changed the memory of ellipsis.__repr__ to point to ellipsis itself but apparently not.
How did you overwrite __repr__? ctypes?
yeah but using my helper program that makes it slightly higher-level than modifying data at memory addresses
have you seen it?
>>> bool_struct = PyTypeObject.from_object(bool)
>>> int_struct = PyTypeObject.from_object(int)
>>> bool_struct.tp_repr = int_struct.tp_repr
>>> bool_struct.tp_name = int_struct.tp_name
>>> True
1
>>> False
0
>>> bool
<class 'int'> :
>>>
>>> @CFUNCTYPE(py_object, py_object)
... def new_boolrepr(self):
... return "lol no"
...
>>> bool_struct = PyTypeObject.from_object(bool)
>>> bool_struct.tp_str = new_boolrepr
>>> print(True)
lol no
>>>
i want to implement more structs. i've got it private on github at the moment but there is a link with the main parts somewhere in this channel
I have a patch decorator I wrote so I can py @patch(str) def reverse(self): return self[::-1] and it'll overwrite str.reverse
Or more usefully, ```py
@patch(str)
def spongebob(self):
return ''.join(
i.upper() if n % 2 == 0 else i.lower() for n, i in enumerate(self)
)
Turns out it doesn't play nice with things like booleans
Did I cross a line I shouldn't have crossed?
OH NO
@fallen heath Your eval job has completed.
001 | File "<string>", line 5
002 | SyntaxError: from __future__ imports must occur at the beginning of the file

@desert garden nice try, that wouldn't even run because python would give a SyntaxError before it reached your import. ;)
That's what you think
that is what i think
But what you don't see is me calling it from another import
That wraps importlib
And replaces __import__ with something that modifies the file before importlib sees it
print('what')
sys.excepthook is missing
1 + 1
sys.excepthook is missing
HELP
sys.excepthook is missing
exit()
sys.excepthook is missing
^Z```
apparently sys.excepthook was missing
>>> what
b"\xe4\x00lass '\x00\x00\x00\x00\x00\x00\x00\x00"
>>> what
'\r\n'
>>> what
b"\xe4\x00lass '\x00\x00\x00\x00\x00\x00\x00\x00"
>>> what
'\r\n'```
huh??? ```py
what, what
('(hat\x00\x00', '(hat\x00\x00')```
this is very interesting ```py
[what]
[''\']
[what]
[''\']```
oh, mi segfaulted it :(
this object has way too many references ```py
obj.ob_refcount
2179898566729```
:D
mi now has a cparam, whatever that is ```py
param
<cparam 'P' (000001978EBB4340)>```
but now it's turned into this again ```py
param
b'\xe4\xa0\xbb\x8e\x97\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
param
'\r\n'
param
b'\xe4\xa0\xbb\x8e\x97\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
param
'\r\n'```
it seems like this stuff is deterministic but unpredictable
if you do this, you will always get a <cparam 'P'
>>> obj = PyObject.from_object('hello')
>>> cast(pointer(obj), py_object).value
<cparam 'P' (000002EC46904340)>
>>> param = _```
(on min computer, at least)
but if you do it even slightly differently, that doesn't happen
...this is weird
mi's confused, what on earth is going on ._.
>>> cast(paramO._obj, py_object).value
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
# <it crashes>```
i mean, PyObject is just a subclass of ctypes.Structure
which is defined in _ctypes as _Structure in C code
so it might be related
but what on earth is <cparam 'P'
fuck knows
and what is b'\xe4\xa0F\xc9\xb1\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
search for "cparam" in the cpython github and see if you find any related strings
that's literally all i do
ah that makes sense actually
callproc.c is what makes CFuncPtr (and PyCFuncPtrType and stuff) work, right?
mi has no idea, but here's the struct c struct tagPyCArgObject { PyObject_HEAD ffi_type *pffi_type; char tag; union { char c; char b; short h; int i; long l; long long q; long double D; double d; float f; void *p; } value; PyObject *obj; Py_ssize_t size; /* for the 'V' tag */ };
interesting
also pastebean, should i add you to my github repo for those helper structs? it's private for now but you can contribute if you want. i want to add structs for code object, frame objects, etc. but haven't gotten round to it yet.
you could
mi doesn't really have anything better to do so mi'll probably contribute if you do
sounds good. i think this should work https://github.com/kingdom5500/cpystructs/invitations
it worked
neat
for struct fields that begin with _ like for PyBytesObject._ob_sval, it should be given a placeholder (probably c_void_p) and you should make a property called ob_sval which handles the field manually. this is because some fields are dynamically-sized and that can't be configured automatically.
sometimes I come here to take a look at a foreign language
Experimentation of one way to handle ob_sval @brisk zenith
import ctypes
class PyBytesObject(ctypes.Structure):
_fields_ = [
('ob_refcnt', ctypes.c_ssize_t),
('ob_type', ctypes.py_object),
('ob_size', ctypes.c_ssize_t),
('ob_shash', ctypes.c_ssize_t),
('ob_sval', ctypes.c_char),
]
obj = b'foobar'
ptr = ctypes.cast(id(obj), ctypes.POINTER(PyBytesObject))
vp = ctypes.cast(ptr, ctypes.c_void_p)
vpv = ctypes.c_void_p(vp.value + PyBytesObject.ob_sval.offset)
``` ```py
>>> ptr.contents.ob_refcnt
1
>>> repr(ptr.contents.ob_type)
"<class 'bytes'>"
>>> ptr.contents.ob_size
6
>>> ptr.contents.ob_shash
-1415199440176704306
>>> hash(obj)
-1415199440176704306
>>> ptr.contents.ob_sval
b'f'
>>> ctypes.cast(vpv, ctypes.c_char_p).value
b'foobar' # only works if it is null-terminated
>>> ctypes.cast(vpv, ctypes.POINTER(ctypes.c_char))[:ptr.contents.ob_size]
b'foobar' # works for any type```
oh huh, interesting.
that would work for bytes objects, sure, but i suppose the issue is when you get to lists or ints.
you can substitute any type for c_char in class definition and the last one
>>> test = [1, 2, 3, 4, 5]
>>> test.sort()
>>> test
[3, 4, 5, 1, 2]
>>>
code (using my cpystructs module): ```py
import cpystructs
import random@cpystructs.PyCFunction
... def evil_sort(self, _):
... random.shuffle(self)
...
list_struct = cpystructs.PyTypeObject.from_object(list)
list_struct.tp_methods[13].ml_name
b'sort'
list_struct.tp_methods[13].ml_meth = evil_sorttest = [1, 2, 3, 4, 5]
test.sort()
test
[3, 4, 5, 1, 2]
so simple yet so evil
haha that name's in the C struct, i'm being as consistent to the C structs as i can: ```c
struct PyMethodDef {
const char *ml_name;
PyCFunction ml_meth;
int ml_flags;
const char *ml_doc;
};
oh, lemme check sorted
oh hot, segfault
>>> list(sorted(test))
[1] 11340 segmentation fault (core dumped) python3
i wonder why (like, actually)
Doesn't it just need < or > implemented
or is it basically
def sorted(iterable):
l = list(iterable)
l.sort()
return l
i am very confused right now, hold on.
Chrome mobile crashes when trying to load source :(
so this is the C code for the sorted builtin. ```c
static PyObject *
builtin_sorted(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *newlist, *v, *seq, *callable;
/* Keyword arguments are passed through list.sort() which will check
them. */
if (!_PyArg_UnpackStack(args, nargs, "sorted", 1, 1, &seq))
return NULL;
newlist = PySequence_List(seq);
if (newlist == NULL)
return NULL;
callable = _PyObject_GetAttrId(newlist, &PyId_sort);
if (callable == NULL) {
Py_DECREF(newlist);
return NULL;
}
assert(nargs >= 1);
v = _PyObject_FastCallKeywords(callable, args + 1, nargs - 1, kwnames);
Py_DECREF(callable);
if (v == NULL) {
Py_DECREF(newlist);
return NULL;
}
Py_DECREF(v);
return newlist;
}
i'm looking at this line in particular: ```c
callable = _PyObject_GetAttrId(newlist, &PyId_sort);
so, &PyId_sort is from a macro: _Py_IDENTIFIER(sort). the declaration of that macro is as follows: ```c
typedef struct _Py_Identifier {
struct _Py_Identifier next;
const char string;
PyObject *object;
} _Py_Identifier;
#define _Py_static_string_init(value) { .next = NULL, .string = value, .object = NULL }
#define _Py_static_string(varname, value) static _Py_Identifier varname = _Py_static_string_init(value)
#define _Py_IDENTIFIER(varname) Py_static_string(PyId##varname, #varname)
so it literally must get that identifier ("sort") as an attribute via the `_PyObject_GetAttrId` function (which just calls `_PyObject_GetAttr` with the name string internally).
this part indicates that it literally just makes a list out of it ```c
newlist = PySequence_List(seq);
if (newlist == NULL)
return NULL;
actually no
This looks to me as if it just copies the list, then sorts it
PySequence_List is defined as follows: ```c
PyObject *
PySequence_List(PyObject *v)
{
PyObject result; / result list */
PyObject rv; / return value from PyList_Extend */
if (v == NULL) {
return null_error();
}
result = PyList_New(0);
if (result == NULL)
return NULL;
rv = _PyList_Extend((PyListObject *)result, v);
if (rv == NULL) {
Py_DECREF(result);
return NULL;
}
Py_DECREF(rv);
return result;
}
actually yeah
it literally makes a list from the sequence
and performs .sort on it
i would expect it to be smarter than that given the fact that it doesn't actually return a list
hm? I think it does...
really?
oh huh
i thought it was one of those fancy functions that returned a special iterable like range
makes sense though
The manual reference counting in the c part is so annoying when writing a module. Py_DECREF brings back some bad memories
I wonder if e.g. heapifying it and returning the lowest element on each next() call as a generator would be more efficient than really sorting it as a whole
haha yeah i know what you mean grote. makes C code more gruelling than it needs to be at times
also, does list[x] do something different to list.__getitem__(x) internally? it seems to, at least: ```py
import cpystructs
@cpystructs.PyCFunction
... def new_getitem(self, item):
... return "lol no"
...
list_struct = cpystructs.PyTypeObject.from_object(list)
list_struct.tp_methods.contents.ml_meth = new_getitemtest = ["hello", "there", 1, 2, 3]
test.getitem(1)
'lol no' # this works as intended
test[1]
'there' # but this doesn't
even though they are said to be equivalent: ```py
list.getitem.doc
'x.getitem(y) <==> x[y]'
hmm.. well, there's two definitions of the getitem implementation: c PyObject * PyList_GetItem(PyObject *op, Py_ssize_t i) { if (!PyList_Check(op)) { PyErr_BadInternalCall(); return NULL; } if (!valid_index(i, Py_SIZE(op))) { if (indexerr == NULL) { indexerr = PyUnicode_FromString( "list index out of range"); if (indexerr == NULL) return NULL; } PyErr_SetObject(PyExc_IndexError, indexerr); return NULL; } return ((PyListObject *)op) -> ob_item[i]; } which i believe is list.__getitem__(x), and also:
static PyObject *
list_item(PyListObject *a, Py_ssize_t i)
{
if (!valid_index(i, Py_SIZE(a))) {
if (indexerr == NULL) {
indexerr = PyUnicode_FromString(
"list index out of range");
if (indexerr == NULL)
return NULL;
}
PyErr_SetObject(PyExc_IndexError, indexerr);
return NULL;
}
Py_INCREF(a->ob_item[i]);
return a->ob_item[i];
}
which i think is list[x]
surprised me that PyList_GetItem doesn't just wrap around list_item
oh hmm, apparently one of my related function type declarations was wrong. let's see if that does anything.
>>> import cpystructs
>>> @cpystructs.ssizeargfunc
... def first_getitem(self, item):
... print("first!")
...
>>> @cpystructs.PyCFunction
... def second_getitem(self, item):
... print("second!")
...
>>> struct = cpystructs.PyTypeObject.from_object(list)
>>> struct.tp_as_sequence.contents.sq_item = first_getitem
>>> struct.tp_methods[0].ml_meth = second_getitem
>>> x = [1, 2, 3]
>>> x[2]
3 # so i assumed the first one didn't work
>>> x.__getitem__(2)
second! # but this one did work
>>> import dis
first! # but then this happened as i tried to import dis for debugging
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.7/dis.py", line 8, in <module>
from opcode import *
TypeError: attribute name must be string, not 'NoneType'
>>>
time to investigate what exactly the BINARY_SUBSCR instruction does.
it calls PyObject_GetItem
so... let's see then. what does that do?
oh hmm
so, that checks if struct.tp_as_mapping.contents.mp_subscript exists in the type struct before going for struct.tp_as_sequence.contents.sq_item
well then, let's see if changing that first one does the magic i want
>>> import cpystructs
>>>
>>> @cpystructs.binaryfunc
... def new_getitem(self, item):
... print("moist")
...
>>> struct = cpystructs.PyTypeObject.from_object(list)
>>> struct.tp_as_mapping.contents.mp_subscript = new_getitem
>>> test = [1, 2, 3]
>>> test[1]
moist
>>>
that output describes me pretty accurately at this point
but __getitem__ behaves normally, so you'd have to modify both of these:
struct.tp_as_mapping.contents.mp_subscript``` for `x[y]`
and
```struct.tp_methods[0].ml_meth``` for `x.__getitem__`
@sick hound is this what you were looking for?
thanks
@brisk zenith know of a good UI library for a drag-and-drop view?
nope
>>> for x in [1]:
... for x in [2]:
... for x in [3]:
... for x in [4]:
... for x in [5]:
... for x in [6]:
... for x in [7]:
... for x in [8]:
... for x in [9]:
... for x in [10]:
... for x in [11]:
... for x in [12]:
... for x in [13]:
... for x in [14]:
... for x in [15]:
... for x in [16]:
... for x in [17]:
... for x in [18]:
... for x in [19]:
... for x in [20]:
... print(x)
...
20
>>> for x in [1]:
... for x in [2]:
... for x in [3]:
... for x in [4]:
... for x in [5]:
... for x in [6]:
... for x in [7]:
... for x in [8]:
... for x in [9]:
... for x in [10]:
... for x in [11]:
... for x in [12]:
... for x in [13]:
... for x in [14]:
... for x in [15]:
... for x in [16]:
... for x in [17]:
... for x in [18]:
... for x in [19]:
... for x in [20]:
... for x in [21]:
... print(x)
...
SyntaxError: too many statically nested blocks```
i'm surprised that gives a SyntaxError to be fair
The rationale for using SyntaxError is in there
It's not much, though
But SystemError is not an exception that should be raised. SystemError is for errors that can't be occurred in normal case. It should only be caused by incorrect use of C API or hacking Python internals. I think SyntaxError is more appropriate in this case (as in case of passing more than 255 arguments to a function).
huh fair enough
"incorrect use of C API or hacking Python internals" so basically it should only be caused by this channel? :P
haha most certainly
also apparently python checks the number of arguments before checking if any of them are the same ```py
def lol(a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a):
... return 'lol'
...
File "<stdin>", line 1
SyntaxError: more than 255 arguments```
i wonder what happens if you exceed 65535 local variables in a scope so that not even extended args can cover it
#esoteric-python : Institute for the Pythonically Insane
:D
it seems like you can have multiple EXTENDED_ARGs if you need them
here's the end of a dis of a code object that creates a 70000-element tuple 288360 LOAD_NAME 69990 (v69990) 288362 EXTENDED_ARG 1 288364 EXTENDED_ARG 273 288366 LOAD_NAME 69991 (v69991) 288368 EXTENDED_ARG 1 288370 EXTENDED_ARG 273 288372 LOAD_NAME 69992 (v69992) 288374 EXTENDED_ARG 1 288376 EXTENDED_ARG 273 288378 LOAD_NAME 69993 (v69993) 288380 EXTENDED_ARG 1 288382 EXTENDED_ARG 273 288384 LOAD_NAME 69994 (v69994) 288386 EXTENDED_ARG 1 288388 EXTENDED_ARG 273 288390 LOAD_NAME 69995 (v69995) 288392 EXTENDED_ARG 1 288394 EXTENDED_ARG 273 288396 LOAD_NAME 69996 (v69996) 288398 EXTENDED_ARG 1 288400 EXTENDED_ARG 273 288402 LOAD_NAME 69997 (v69997) 288404 EXTENDED_ARG 1 288406 EXTENDED_ARG 273 288408 LOAD_NAME 69998 (v69998) 288410 EXTENDED_ARG 1 288412 EXTENDED_ARG 273 288414 LOAD_NAME 69999 (v69999) 288416 EXTENDED_ARG 1 288418 EXTENDED_ARG 273 288420 BUILD_TUPLE 70000 288422 RETURN_VALUE
huh TIL
the next logical question would be what happens if you put 9223372036854775808 elements in a list so it becomes a negative length
sounds like a plan :^)
apparently making the size of a list -1 does nothing at all ```py
test
[]
len(test)
-1```
...but if you append to it it crashes :(
huh ```py
len(test)
-2
test.append(int)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
MemoryError```
if you try to append to a list with a length of -2 you get a memory error
extend works fine though apparently
as long as the extend gets it to a length of 0 or something positive
and if you deallocate a list of a negative length python crashes
...this is interesting... ```py
len(test)
-1
test
(,)```
a tuple with a negative length is (,)
wat ```py
what[0][0][1]
Fatal Python error: GC object already tracked
Current thread 0x0000380c (most recent call first):```
@brisk zenith Entended args in python 3 are of infinite length
Just just stack up multiple EXTENDED_ARGs in a row
fair enough
It's a pisstake to generate them though because they go in reverse length to how you'd do a loop of ```py
while arg:
e_arg = arg & 0xff
arg >>= 8
So you have to build an array of them and reverse it
@replace_builtin_method(list.append)
def new_append(original, self, item):
# let's be evil and append twice
original(self, item)
original(self, item)
x = [1, 2, 3]
x.append(4)
print(x) # [1, 2, 3, 4, 4]
this is really hot
@sick hound python [print(x) for x in iter(lambda a=[0]:[a.append(a[0]+1),a.pop(0)][1],-1)] this is infinite counting with no recursion like what you sent 2 days ago
simple golfing challenge here: given two strings, split the first string at occurences of the second string but include the separator on either side of each new part, then print it. example:
input:
hello world!
o
output:
hello
o wo
orld!
my shortest is 46
is the separator an arbitrary string or a single character? (not sure if it matters yet, but still)
arbitrary string
input: this test is a test string test
output:```
this test
test is a test
test string
well, mine's 46 as a function, 54 if inputs are supplied from input
huh that's nice
what's your code? mine's ```py
s=input()
r=input()
print(*s.split(r),sep=f"{r}\n{r}")
s,r=input(),input();print(s.replace(r,r+"\n"+r))
oh huh idk why i used a fstring there
yeah, that should save 3 bytes
f = lambda s,r:print(*s.split(r),sep=r+'\n'+r)
@brisk zenith i looked at yours for the sep bit
byte's is better tbh :D
f=lambda s,r:print(s.replace(r,r+'\n'+r)) 
Sleep sort:
#!/usr/bin/env python3
from asyncio import run, sleep, wait
from sys import argv
async def f(n):
await sleep(n)
print(n)
if __name__ == '__main__':
run(wait(list(map(f, map(int, argv[1:])))))
Credit u/random_cynic: https://www.reddit.com/r/ProgrammerHumor/comments/bdd6fi/sleep_sort_for_lazies/ekxrpr5
lol, that is brilliant, not sure if it will be always able to handle floats properly, there you might have a race conditions which would result in invalid order.
i don't understand asyncio that well, what's actually going on there and how does it sort?
@brisk zenith its running f on all of the input values simultaniously
ohhhh
obviously larger int causes longer sleep
you spawn "threads" which sleep for N seconds where N is a value of element in the list, and then return/print value
so technically if you don't have race conditions that would sort it
Shebangs in 2019 ๐ค
you're saying that as if the shebang is the strange thing in that code.
of course it is
everything else in that code would do well in a production environment /s
@brisk zenith can i give you a golfing challenge? create a lambda that counts infinity from 0 till infinity with no recursion errors
currently im at 58 characters
also you can use a generator
[*iter(lambda _=[0]:(_.append(_[0]+1),print(_.pop(0))),0)]```
i=0
while 1:i=(print(i),i+1)[1]
31 characters
@rugged sparrow
Oh wait, does it have to be a lambda?
Challenge: find a way to do an exhaustive map function without calling list or map
Basically similar to ```kt
myArray.forEach { x => println(x*x) }
Since Python's `map` function has been a generator since Py3, find a way to make it not be a generator. Comprehensions are allowed, but other ways are more impressive.
The bad way to do it is take find a way to make it not be a generator literally and [*map(...)]
I think ```py
map = lambda f, d: [] if not d else ([f(d[0])] + map(f, d[1:]))
Could probably make a nice lazy wrapper with getitem so you could index it and it'd just do that single one
@desert garden remove "return" and it works
Lol
Been a long day 
you can always replace map with reduce :P
In [8]: f = lambda x: x*x
In [9]: r = reduce(lambda x,y: x+[f(y)], range(10), [])
In [11]: def my_map(func, sequence):
...: return reduce(lambda x,y: x+[func(y)], sequence, [])
Oh damn code boxes with scrolly things 0.o?
that seems new indeed
Oh they actually did it?
I feel like there's a minor bug with this scrollbar
Given that it's allowing me to scroll as if the codeblock is taking up twice the width of my monitor, and the code inside it takes up barely a third
newCard = lambda card,suit:type(
'Card', (object,),{
'card':card,
'suit':suit,
'visible':False,
'setVisible':lambda self,o=1:self.__setattr__('visible',o),
'getSuit':lambda self,c=0:[f'\x1b[1;{31 if self.suit <= 1 else 0}m' if c else ''][0] + 'โฅโฆโฃโ '[self.suit] + ['\x1b[0m' if c else ''][0],
'fullCard':lambda self,f=0:self.getSuit(self.visible or f)+self.card if self.visible or f else '[]',
'getValue':lambda self:'A23456789XJQK'.index(self.card),
'getColor':lambda self:'red' if self.suit <= 1 else 'white'
}
)()``` declaring classes like this is weird
yeah i did that in my one-line implementation of polish notation. we couldn't use lists so i made a full stack class in a lambda :D
i just realized i can use a __init__ method ๐ python newCard = type( 'Card', (object,),{ '__init__':lambda self,card,suit:[ self.__setattr__('card',card), self.__setattr__('suit',suit), self.__setattr__('visible',False), None ][3], 'setVisible':lambda self,o=1:self.__setattr__('visible',o), 'getSuit':lambda self,c=0:[f'\x1b[1;{31 if self.suit <= 1 else 0}m' if c else ''][0] + 'โฅโฆโฃโ '[self.suit] + ['\x1b[0m' if c else ''][0], 'fullCard':lambda self,f=0:self.getSuit(self.visible or f)+self.card if self.visible or f else '[]', 'getValue':lambda self:'A23456789XJQK'.index(self.card), 'getColor':lambda self:'red' if self.suit <= 1 else 'white' } )
but it has to return None
yup
this is really cool
never knew i could do any of this
wait can it have class methods?
of course
@classmethod
def stuff(cls, things):
...
is just syntactic sugar for ```py
def stuff(cls, things):
...
stuff = classmethod(stuff)
@rugged sparrow
oh thats cool
so you could do ```py
...
"stuff": classmethod(lambda cls: ...),
...
true
so you could write literally any python script in one line using type and lambda
hmm. i wonder if its possible to write a translator
it's been tried before, and it gets real tricky when async and await syntax comes in
try and except is a major one too
can't do that in one line
oh true
you could always translate try and except like this exec('try:\n\tprint("entering try block")\n\t1/0\nexcept:print("test")') but that kinda defeats the purpose
yeah definitely.
yeah that's what i mean when i said it's been tried before. it does a good job though.
does it do try/except?
yea
https://github.com/csvoss/onelinerizer/blob/7c36b8ce1374840893fde2f5c05048c379ec71e2/onelinerizer/onelinerizer.py#L686 @brisk zenith its OS too
interesting
yea. i wonder how it works
Anyone interested in helping me write a .pyc parser?
Made progress using existing methods but I wanna learn more about how it really works
These bytes are a code object somehow
yeah
do marshal.loads(...) on everything past the first 12 or 16 bytes
gives you a code object
kinda disappointing how easy it is but y'know
haha
@brisk zenith i have a challenge for you
get to a bash shell (like what you'd get from running os.system('bash')) after running del __builtins__
so you have no __import__
or any builtin functions lol
i assume del __builtins__ must be the first thing done?
yea
hm
''.__class__.__class__((lambda:0))(''.__class__.__class__((lambda:0).__code__)('''need to make a code object'''),{})()
this is how far ive gotten
there are canned builtin discovery code snippets
@tropic gulch wdym?
I'm currently searching for the link...
https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html leads to https://www.reddit.com/r/Python/comments/hftnp/ask_rpython_recovering_cleared_globals/ which has one version to recover builtins
18 votes and 17 comments so far on Reddit
guess there are more similar variants out there
(lambda:0).__globals__['__loader__'].load_module('os').system('bash')```
del __builtins__
__loader__.__class__("os", "/usr/lib/python3.7/os.py").load_module().system("bash")
heck you beat me to it almost
your example won't work if run as a file i'm pretty sure, right?
hmm one sec
works fine in the REPL though
yea
i did the exact same thing the first time haha
(lambda:0).__globals__['__loader__'] is the same as just __loader__
yea i noticed lmao
this is where i tried the exact same thing pretty much
add globals().clear() before del __builtins__
haha
wow del __builtins__ isn't even needed
globals().clear() is enough to be a right twat
yea i just realized that
lol
@brisk zenith if you know how to write a code object capable of importing then my over complicated thing from earlier would work
the IMPORT_NAME bytecode instruction relies on the prescense of __import__ i think.
thats frustrating
can you still open files?
also, another question, now that globals is cleared, can the other files run?
possibly.
this could be a fun challenge for the esoteric python challenges github. like maybe have people try to rebuild globals() after its been cleared
i've had many impossible ideas for the repo in the past :D. i've decided that i want to keep them reasonably possible so that there can be overly-complex and beautifully weirdly simple solutions
cause if it's too hard, only one or two people might make successful submissions and there's little fun in that, really.
true
although looking at the reddit post @tropic gulch sent earlier, it is possible
I have seen some code that would brute-force through all the attributes etc of an object recursively and report all instances of builtins that it finds. The output list was long.
But I can't find it any more
[x for x in "".__class__.__base__.__subclasses__() if x.__name__ == "BuiltinImporter"][0].load_module("os").system("bash")
well, this works.
but is there a way to do it without literals? i just said that as a joke but.. i think there is.
depends what we're calling a "literal".
are True and False literals?
probably not
if not, my little code from over a year ago will help.
what code?
well, if we need to use any integers, my code from a year ago converts an integer into a bunch of True and << and ^
but no literals
woah thats cool
looking for it
[x for x in False.__class__.__base__.__base__.__subclasses__() if x.__name__ == "BuiltinImporter"][False].load_module("os").system("bash") well this has no ints in it now
yup
so we consider list comps to be literals? if not, its easy i think..
!eval ```py
print((True << (True << True) ^ True << (True ^ True << True) ^ True << (True ^ True << (True << True)) ^ True << (True << (True ^ True << True)) ^ True << (True ^ True << (True ^ True << True)) ^ True << (True << True ^ True << (True ^ True << True)) ^ True << (True ^ True << True ^ True << (True ^ True << True)) ^ True << (True << (True << (True << True)))))
@brisk zenith Your eval job has completed.
69420
yeah okay
True.__repr__().__class__ this gets str
ooh we could use int.to_bytes with that True << shenanigans to convert a really big integer into strings
ooh we could
only issue is that to_bytes needs a byteorder string arg
we could probably find an object whose __doc__ contains "big"
and .split()[True << ...] that fucker
you go do that while i convert "BuiltinImporter" into a bunch of booleans and bitwise operators.
to_bytes has the word "big" in it
yeah but these True << ... stuff get real big and nasty
43 has "big",
okay one sec, i might just use the __doc__[275:278] stuff
(True-True).__class__.to_bytes.__doc__.split()[43][True:True<<True<<True] this gives the string big
43 in there
True.__class__.__base__.to_bytes.__doc__[(True ^ True << True ^ True << (True << (True << True)) ^ True << (True << (True ^ True << True))): (True << True ^ True << (True << True) ^ True << (True << (True << True)) ^ True << (True << (True ^ True << True)))]
this also gives the string "big"
would using 43 instead of 275 and 278 be larger?
no probably not
but i realise now that 275 and 278 are tiny compared to the int needed for BuiltinImporter as bytes
also (True-True).__class__ is smaller than True.__class__.__base__
we're not golfing at this point lmao
True lmao
i'll get the things for "os" and "bash" now, one sec
ok
"os" without literals is py True.__class__.__base__.to_bytes((True ^ True << True ^ True << (True << (True << True)) ^ True << (True ^ True << (True << True)) ^ True << (True << True ^ True << (True << True)) ^ True << (True << (True ^ True << True)) ^ True << (True ^ True << (True ^ True << True)) ^ True << (True << True ^ True << (True ^ True << True)) ^ True << (True ^ True << True ^ True << (True ^ True << True)) ^ True << (True ^ True << (True << True) ^ True << (True ^ True << True)) ^ True << (True << True ^ True << (True << True) ^ True << (True ^ True << True))), (True << True), True.__class__.__base__.to_bytes.__doc__[(True ^ True << True ^ True << (True << (True << True)) ^ True << (True << (True ^ True << True))): (True << True ^ True << (True << True) ^ True << (True << (True << True)) ^ True << (True << (True ^ True << True)))]).decode()
True.__class__.__base__.to_bytes((True << (True ^ True << True) ^ True << (True ^ True << (True << True)) ^ True << (True << True ^ True << (True << True)) ^ True << (True << (True ^ True << True)) ^ True << (True ^ True << (True ^ True << True)) ^ True << (True << (True << True) ^ True << (True ^ True << True)) ^ True << (True ^ True << (True << True) ^ True << (True ^ True << True)) ^ True << (True << True ^ True << (True << True) ^ True << (True ^ True << True)) ^ True << (True << (True << (True << True))) ^ True << (True ^ True << (True << True) ^ True << (True << (True << True))) ^ True << (True << True ^ True << (True << True) ^ True << (True << (True << True))) ^ True << (True ^ True << (True ^ True << True) ^ True << (True << (True << True))) ^ True << (True ^ True << (True << True) ^ True << (True ^ True << True) ^ True << (True << (True << True))) ^ True << (True << True ^ True << (True << True) ^ True << (True ^ True << True) ^ True << (True << (True << True)))), (True << True << True), True.__class__.__base__.to_bytes.__doc__[(True ^ True << True ^ True << (True << (True << True)) ^ True << (True << (True ^ True << True))): (True << True ^ True << (True << True) ^ True << (True << (True << True)) ^ True << (True << (True ^ True << True)))]).decode()```
"bash"
but hey, no literals
here's the code i wrote on my first day in this server for making this True shenanigans: ```py
def true_shift(value):
code = ""
count = 0
if value == 0:
return
elif value == 1:
return 'True'
while value != 0:
if value % 2 == 1:
if count != 0:
code += "True << {} ^ ".format(true_shift(count))
else:
code += "True ^ "
count += 1
value >>= 1
return '({})'.format(code.strip(" ^ "))
while True:
print(true_shift(int(input("number: "))))
i've been an #esoteric-pythonista since day 1 :^)
damn impressive
@brisk zenith (111).to_bytes(1,'big') this gets o but requires 'big'
let's lay this out a bit. py str_big = True.__class__.__base__.to_bytes.__doc__[(True ^ True << True ^ True << (True << (True << True)) ^ True << (True << (True ^ True << True))): (True << True ^ True << (True << True) ^ True << (True << (True << True)) ^ True << (True << (True ^ True << True)))
then we can reuse it, simple
from a quick grep through the cpython source code, i can't see any
there'll be loads of ways to make it shorter. let's focus on a way to make it work.
i don't like relying on that though
true
ah im on 3.7.3
and in 3.6.8 it's index 69 ||insert obligatory teenager joke||
lmao
thats very weird
is there still something that does that job in 3.1.5 thats similar?
lemme check
nothing that i can immediately see
closest is imp.NullImporter but it behaves differently
i dunno what it really does tbh
(((True<<True^True<<True<<True<<True)*(True<<True^True<<True<<True<<True)+(True<<True^True<<True<<True<<True)+True).to_bytes(True,'big') + ((True<<True^True<<True<<True<<True)*(True<<True^True<<True<<True<<True)+(True<<True^True<<True<<True<<True)+True+(True<<True<<True)).to_bytes(True,'big')).decode()
does it have a __doc__
Null importer object
thanks
very nice
yeah great
awesome
oh
imp.NullImporter.find_module.__doc__ => Always return None
it has brighter aspirations than me, at least
lmao
there's object.__subclasses__ for 3.1.5, how queer.
just as an aside, i have plenty of spare space so i'm just gonna install the most recent minor release of all python versions. /shrug
haha, i just don't use my space all that much
but anyways, getting off-topic
how to we find BuiltinImporter using its name
i see no problem with building it using to_bytes
store the string to a var
then use .index()
oh wait
damn it
cant use .index
yup :D
and index doesnt have key
i mean, we can't use listcomps but what's stopping us from doing ... ```py
for thing in True.class.base.base.subclasses():
if thing.name == (... builtinimporter ...):
importer = thing
break
...
no literals
i don't think for relies on iter internally, i think it does all that itself
yah that would work
also we can create an iterator if we want
for building the string with our own sort of range function
how do you mean?
wait nevermind
what i thought would give me the iter class didnt
lol making classes after globals().clear() doesnt work with class but it does using type
yeah cause __name__ has to be defined i think
this is our final working code
no globals, no literals, bash shell
damn that long line of True<< lmao
haha, little did i know over one year ago that the code i scribbled up would come in handy for something so restrictive :D
honestly that was a fun challenge
idk lmao
ah 3.2
i only learned python midway thru last year
pretty good progress
thanks
i've been pythoning for around 2 and a half years.
damn
thats awesome
ironically i started with a much more pain in the ass language lmao
before i learned python i learned objectiveC
cause i wanted to make shit for jailbroken phones
but im already way better at python than i am in objC
i learned windows batch a little bit and got scared of for loops before being told by a java + javascript hobbyist developer that python is a good starting point for actual programming
hey i also messed with batch for a while
then we didn't talk for 2 years and recently we got back in touch. now i'm quite good at python and programming concepts (back then i wasn't at all) and he's a professional developer at a bank.
so everyone's a winner
true lol
i taught myself python when i realized my compsci teacher didnt know it well enough to teach it
so i guess thats a good reason lol
haha fair enough.
anyways, if you get any more interesting challenges, let me know. that one was fun.
will do! i was just procrastinating on my homework and was wondering how difficult it would be
still am procrastinating lmao
i'm going to go to bed now though, it's 2am and my brain is evaporating into nitroglycerin and is ready to explode ferociously at any point.
goodnight :D
Oh man I think I actually figured out the marshal format
hm?
@brisk zenith do you know what "$" is in python? It throws a syntax error so I think it's reserved, but idk what for
literally any invalid token will throw a syntax error
it's not reserved, it's just not used currently
besides, this isn't PHP
@brisk zenith I guess I assumed it would be treated like "_" where it can be a var
Variable characters accepted are https://docs.python.org/3/reference/lexical_analysis.html#identifiers
@brisk zenith i thought of a challenge. get to list,dict,int,str,double,bool,objectandset classes from only True
for example: True.__class__ -> bool
double and set might be harder
True.__float__().__class__
True.__class__.__base__.__base__ is object
makes perfect sense
mhm
object and type are the only builtin objects which are direct instances of themselves as far as i'm aware
i want to give a name for that property but i can't think of any lmao
yea
i assume you mean only using True once btw
True.__class__.__bases__.__class__ -> tuple
i know how to get a mappingproxy but not a dict
True.__class__.__dict__
hmm
easier way of getting list -> True.__dir__().__class__
yeah cause globals and stuff
let's make a list of these so that we can keep track. i'll keep editing when we find something new (sorry modlogs :D) ```py
bool: True.class
int: True.class.base
str: True.doc.class
float: True.float().class
object: True.class.base.base
tuple: True.class.bases.class
list: True.dir().class
bytes: True.doc.encode().class
not types but still significant bits and bobs:
False: True.imag.bool()
NotImplemented: True.subclasshook()
None: True.dir().class().sort()
ooh wavy
let's go for that for now.
aight
NotImplemented: True.__subclasshook__()
method-wrapper: True.__abs.__class__
hm.. well, if we're going for all base classes, that's a bit trickier
cause i doubt i even know them all
thats true lol
https://docs.python.org/3/library/stdtypes.html lets get all the ones listed here
bool,int,float,complex,list,tuple, (range might not be possible),str,bytes,set,frozenset,dict,module,function,method
okay neat
code,None,NotImplemented
so final list to find is python bool int float complex list tuple str bytes set frozenset dict module function method code None NotImplemented
@brisk zenith and maybe range
okay sure
True.__class__.__class__.__base__.__subclasses__()[-1].__init__.__class__ -> function
-1
maybe. what if it's written in C? won't get a function there i'm pretty sure

