#esoteric-python
1 messages · Page 67 of 1
i didn't figure it out but I'll just rearrange my code to fit in a second update
I just realised I'm still defining variables in my code lmao
I have variables from a to j
haha
almost finished with you attacking, then I just have make the opponent do a random attack and display hp and then I'm done
(also I've had to lower my font size 3 times to keep it fully on screen lmao)
damn thats awesome
Also debugging this thing is an absolute nightmare
e.update({'g': d( (h[2 ],b[3],b[4][(1 if g[3]==0 else 4)],(2+f[3]), (1 + .5 if h[ 1] in
TypeError: 'int' object is not subscriptable
serious about what? i onelined minesweeper?
no the fact that I've found 3 bugs and it still isn't working
it means you're doing py a_tuple // a_list
prob ```(x[2]//x[3])//50
>>> () // []
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for //: 'tuple' and 'list'```
since 50 isn't a list (hopefully), i'm guessing that x[2] is a tuple and x[3] is a list
@gilded orchid
(hopefully) lmao
globals().update('50':[])
that wouldn't work actually
jk that doesnt actually let you do 50 == []
50 is a constant
x should just be tuple which just has 5 numbers
which means I have to check every time I call that lambda
try printing x
can you send lines 12,13,14
((print(x),x[2]//x[3])[1]))```
turns out x is (70, 100, (359, 266, 254, 269, 298), [1], 2, 1.5)
[(1 if h[3]==0 else 4)] turns out this returns [1]
I thought it would just return the number 1
its inside [] tho, so its a list
Ok, finally got it to cause no errors
turns out the tuple was a wrong index
also turns out i messed this up
how?
no clue
I tested it when I made it and it worked perfectly
but now it's returns 16836 damage
whats it look like rn?
d=lambda x:(((((((x[1]*2)
//5)+2)*x[0]*
(x[2]//x[3])) //50)+2)*x[4])
Also x is this: (Power, Level, Attack, Defence, STAB)
(STAB is a modifier that can either be 1 or 1.5)
hmm
lambda x:((((((2*x[1])//5)+2)*x[0]*(x[2]//x[3]))//50)+2)*x[4]```
@gilded orchid ^
wait wtf
aren't they the same
they are
but mine worked i think
idk why
x = [100,2,5,5,1.5]
and it returned 9
I have a feeling I've messed up what x is
print it
thats 6 values
oh wow I'm blind
lmao
(100, 100, 266, 298, 1) It should be this I think
which is why it gave such a high number
the defence was set to 1 lmao
haha
d( (h[2 ],b[3],b[3],(1 if h[3]==0 else 4),(2+h[3]), (1 + .5 if h[ 1] in
b[1:3]else 1))
now I have to go back to the code that had 3 errors earlier
what errors?
(1 if h[3]==0 else 4) I actually have no clue what I was thinking here
There isn't any number that needs to be 1 or 4
anyway I'm gonna stop spamming this channel now, cya
maybe it was for spacing?
Turns out I had done two different things for the same index, except I didn't use any square brackets
whait what?
howd you manage that lol
also py tryExceptRet = lambda t,args=[],f=lambda e=0:None, e=Exception,r=[],y={}:[ #t is (try lambda), args are passed to t(*args), f is (except lambda),e is Exception or [Exception1,...] y.update({0:type( 'tryExcept',(*(lambda d=[]:[d.append(c) if c.__name__=='ContextDecorator' else None for c in object.__subclasses__()] and d)(),),{ "__init__":lambda self,**kwargs:self.__dict__.update(kwargs), "__enter__":lambda self:None, "__exit__":lambda self, *args:not r.append(self.f(*[args[1]]*self.p)) if any([e in (args[0] or object).__mro__ for e in self.e]) else False } ) }), r.clear(), r.append(y[0](f=f,e=e if isinstance(e,list) else [e],p=f.__code__.co_argcount == 1)(t)(*args)), r[0] ][3] #ret from either block (except block only if try throws Exception) its shorter now
oh wait i dont need y anymore
tryExceptRet = lambda t,args=[],f=lambda e=0:None, e=Exception,r=[]:[ #t is (try lambda), args are passed to t(*args), f is (except lambda),e is Exception or [Exception1,...]
r.clear(),
r.append(
type(
'tryExcept',(*(lambda d=[]:[d.append(c) if c.__name__=='ContextDecorator' else None for c in object.__subclasses__()] and d)(),),{
"__init__":lambda self,**kwargs:self.__dict__.update(kwargs),
"__enter__":lambda self:None,
"__exit__":lambda self, *args:not r.append(self.f(*[args[1]]*self.p)) if any([e in (args[0] or object).__mro__ for e in self.e]) else False
}
)(f=f,e=e if isinstance(e,list) else [e],p=f.__code__.co_argcount == 1)(t)(*args)),
r[0]
][2] #ret from either block (except block only if try throws Exception)``` @brisk zenith ive managed to cut alot of length off of it
oh neat!
@brisk zenith what do you think about the idea we said earlier about having a folder on the github for workarounds of lambda restrictions?
on the pydis repo? i'd rather not, because i'd like people to think of ways of doing that themselves. of course, i encourage everyone to take inspiration from other people's submissions by all means. however, having a section of generic esoteric code makes it too easy to copy-paste into your own submissions.
thats true
dict(map(lambda x:(x.__name__,x),object.__subclasses__()))['className']``` this is a interesting way of getting any currently initiated class thats in ``object.__subclasses__()`` without having to import it
{x.__name__:x for x in object.__subclasses__()}['className']```
is a more compact way to do it
@gilded orchid maybe seperatly from pydis we can open an organization for sharing this kind of examples
Couldn't one of us just make a GitHub repo called 'python lambda workarounds'
recipes sounds better
TryExceptElse = type("TryExceptElse", (__import__("contextlib").ContextDecorator,), {
"__init__": lambda self, except_ = lambda: None, else_ = lambda: None, exceptions = (Exception,): [setattr(self, name, value) for name, value in locals().items()][0],
"__enter__": lambda self: None,
"__exit__": lambda self, exception_type, *_: sum([(True,self.except_())[0] if issubclass(exception_type or type, self.exceptions) else False, (True,self.else_())[0] if exception_type is None else False])
})
# Minified version
TryExceptElse=type("",(__import__("contextlib").ContextDecorator,),{"__init__":lambda self,ex=lambda:None,el=lambda:None,e=(Exception,):[setattr(self,n,v)for n,v in locals().items()][0],"__enter__":lambda x:0,"__exit__":lambda self,e,*_:sum([(1,self.ex())[0]if issubclass(e or type,self.e)else 0,(1,self.el())[0]if e==None else 0])})
That's my edited version of the try/except
>>> b = type('test', (), {'__init__':lambda self, a,b:[setattr(self, "a", a),setattr(self, "b", b)]})
>>> b(1,2)
Traceback (most recent call last):
File "<pyshell#15>", line 1, in <module>
b(1,2)
TypeError: __init__() should return None, not 'list'
I'm trying to use the line class thing but I keep on getting this error, how do I fix this?
you need __init__ to return None
[setattr(self, "a", a), setattr(self, "b", b), None][-1]``` try replacing `[setattr(self, "a", a),setattr(self, "b", b)]` with this
oh ok, that makes sense, thanks 😃
since setattr also returns None you could also use [setattr(self, "a", a), setattr(self, "b", b)][0]
Is there a way to loop through all the arguments the class has and use setattr with them
I know you could use map() but can you get a list of all the arguments?
.__dir__()
Oh, nevermind, that's for attributes.
>>> globals()
Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
globals()
TypeError: string indices must be integers
I was messing around and somehow got this to happen
and this
>>> print('Test')
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
print('Test')
TypeError: 'int' object is not subscriptable
I used globals().update to change builtins to some random number
>>> print
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not subscriptable```
LOL
also changing it to string gives the other error
yep
I tried to change builtins to a lambda that printed out what got sent to it but it didn't work
it's subscripting builtins, not calling it
oh right, nvm then lol
>>> __builtins__=type('',(),{'__getitem__':lambda s,a:(builtins.print(a),builtins.getattr(builtins,a))[1]})()
>>> print
print
<built-in function print>
>>> print('lol')
print
lol```
that works though
>>> print(int(input()))
print
int
input
42
42```
wow
@sick hound i made a couple changes to my version of the try/except
mine returns the value from either block, also has support for passing the exception to the except block
>>> import sys
>>> __builtins__ = sys.modules
>>> os
<module 'os' from 'C:\\Users\\Aaay\\AppData\\Local\\Programs\\Python\\Python36\\lib\\os.py'>
>>> sys
<module 'sys' (built-in)>
>>> functools
<module 'functools' from 'C:\\Users\\Aaay\\AppData\\Local\\Programs\\Python\\Python36\\lib\\functools.py'>
>>> importlib
<module 'importlib' from 'C:\\Users\\Aaay\\AppData\\Local\\Programs\\Python\\Python36\\lib\\importlib\\__init__.py'>
>>> sysconfig
<module 'sysconfig' from 'C:\\Users\\Aaay\\AppData\\Local\\Programs\\Python\\Python36\\lib\\sysconfig.py'>
>>> _io
<module 'io' (built-in)>```
#t is try block (lambda)
#a is a tuple or list of arguments passed as t(*a)
#f is except block (lambda) and can have up to 3 arguments;
#1:Exception Class, 2:Exception Instance, 3:Traceback (*args works)
#e is Exception or [Exception1, Exception2,...]
#return val can be (in order) try() result, except() result, None
tryExceptRet = lambda t,a=(),f=lambda:None, e=Exception,r=[]:[
r.clear(),
r.append(type(
'',
({x.__name__:x for x in object.__subclasses__()}['ContextDecorator'],),
{
'__enter__':lambda self:setattr(self,'c',f.__code__),
'__exit__':lambda self,*a:not r.append(
f(
*a if self.c.co_flags == 71 else a[0:self.c.co_nlocals]
)
) if any(
map(
(a[0] or object).__mro__.count,e if e.__class__ == list else [e]
)
) else False
}
)()(t)(*a)),
r[0],
][2]```
minified
```py
tryExceptRet=lambda t,a=(),f=lambda:None,e=Exception,r=[]:[r.clear(),r.append(type('',({x.__name__:x for x in object.__subclasses__()}['ContextDecorator'],),{'__enter__':lambda self:setattr(self,'c',f.__code__),'__exit__':lambda self,*a:not r.append(f(*a if self.c.co_flags==71else a[0:self.c.co_nlocals]))if any(map((a[0]or object).__mro__.count,e if e.__class__==list else[e]))else False})()(t)(*a)),r[0],][2]
``` @sick hound
huh
@sick hound think you could help me debug my pyc/bytecode parser? https://github.com/martmists/bytepatches/issues/1
This seems to be the only issue so far (not including adding all opcodes)
Generators are function calls
>>> dis.dis(c) # (a for b in c)
1 0 LOAD_CONST 0 (<code object <genexpr> at 0x0000018F0FF27C00, file "", line 1>)
2 LOAD_CONST 1 ('<genexpr>')
4 MAKE_FUNCTION 0
6 LOAD_NAME 0 (c)
8 GET_ITER
10 CALL_FUNCTION 1
12 RETURN_VALUE
>>> dis.dis(c.co_consts[0])
1 0 LOAD_FAST 0 (.0)
>> 2 FOR_ITER 10 (to 14)
4 STORE_FAST 1 (b)
6 LOAD_GLOBAL 0 (a)
8 YIELD_VALUE
10 POP_TOP
12 JUMP_ABSOLUTE 2
>> 14 LOAD_CONST 0 (None)
16 RETURN_VALUE```
@grave rover that's not a bug, generators are function calls
...?
it looks like you're parsing it fine
except for the fact that the names of the functions are missing in MAKE_FUNCTION
what's actually the problem?...
@grave rover
found what the bug was
now to parse imports...
1 0 LOAD_CONST 0 (0)
2 LOAD_CONST 1 (('y', 'z'))
4 IMPORT_NAME 0 (x)
6 IMPORT_FROM 1 (y)
8 STORE_NAME 1 (y)
10 IMPORT_FROM 2 (z)
12 STORE_NAME 2 (z)
14 POP_TOP
16 LOAD_CONST 2 (None)
18 RETURN_VALUE
```how would I parse this to a tree-view, hmm
@grave rover looks like you always get that sequence
the 0 is level (number of .'s before imported name), the rest of the module name including package is the import name argument, then sequence of import_from and store, then pop_top
>>> dis.dis('from .p.x import y, z as zz')
1 0 LOAD_CONST 0 (1)
2 LOAD_CONST 1 (('y', 'z'))
4 IMPORT_NAME 0 (p.x)
6 IMPORT_FROM 1 (y)
8 STORE_NAME 1 (y)
10 IMPORT_FROM 2 (z)
12 STORE_NAME 3 (zz)
14 POP_TOP
16 LOAD_CONST 2 (None)
18 RETURN_VALUE```
i'd probably make either two lists or a list of 2-tuples with the imported names and stored names
[and keep in mind the stores can be store_fast if importing inside a function]
they can be any kind of store, if the name being imported is defined as global/nonlocal for instance
i don't know how you're organizing regular variable stores
maybe just define it as a pseudo-function and unpacking assignment, e.g. represent it the exact way you'd represent y, zz = __import__('p.x', ..., ..., ('y', 'z'), 1), except without the name lookup on __import__
depends on how abstract you want your syntax tree to get vs the bytecode ops
how does AST represent it?
>>> ast.dump(ast.parse('from .p.x import y, z as zz'))
"Module(body=[ImportFrom(module='p.x', names=[alias(name='y', asname=None), alias(name='z', asna
me='zz')], level=1)])"```
AST distinguishes "y as y" from "y", but bytecode doesn't
I have it as STORE_NAME(target_var_name, target_token)
and I can't peek forwards as to what the next two bytes will be
well
after IMPORT_NAME I cant guarantee if any IMPORT_FROMs are made until I instantiate them
i'd consider the entire sequence LOAD_CONST[int] LOAD_CONST[Tuple[str]] IMPORT_NAME (IMPORT_FROM STORE)* POP_TOP as a unit, and generate your tree node based on the contents of that
consume the entire bytecode until POP_TOP
uh
if the rest of stuff after IMPORT_NAME doesn't match (IMPORT_FROM STORE)* POP_TOP I'd just consider it unparseable bytecode garbage
lemme give that to you
er it'll be either that or a store for a module import (either non-from or from .)
but the second arg (the tuple) would have been None in that case
1 0 LOAD_CONST 0 (0)
2 LOAD_CONST 1 (None)
4 IMPORT_NAME 0 (sys)
6 STORE_NAME 0 (sys)
2 8 LOAD_CONST 0 (0)
10 LOAD_CONST 1 (None)
12 IMPORT_NAME 1 (matplotlib.pyplot)
14 STORE_NAME 2 (matplotlib)
3 16 LOAD_CONST 0 (0)
18 LOAD_CONST 2 (('plot', 'legend'))
20 IMPORT_NAME 1 (matplotlib.pyplot)
22 IMPORT_FROM 3 (plot)
24 STORE_NAME 3 (plot)
26 IMPORT_FROM 4 (legend)
28 STORE_NAME 4 (legend)
```op after this is POP_TOP
like i said, you get either a store right away, or a sequence of import_from/store followed by pop_top
that's py import sys import matplotlib.pyplot as matplotlib from matplotlib.pyplot import plot, legend
https://github.com/martmists/bytepatches/blob/master/bytepatches/parser.py if I remember git urls
I guess it's theoretically conceivable in bytecode that it could store both, or have a tuple and only store the module anyway, or do something weirder, but I don't think there's a way to generate that
load_const[int] load_const[tuple[str]|None] import_name
( (import_from store)+ pop_top
| store
| import_star)
or, more precisely based on the value of the tuple argument
load_const[int]
( load_const[tuple[str]] import_name (import_from store)+ pop_top
| load_const[None] import_name store
| load_const[('*',)] import_name import_star)```
(i'm using pseudo regexes to describe my understanding of the grammar of generated bytecode)
so after the import_name you'll see either import_from, a store instruction, or import_star
like, an excessively literal interpretation of stack-based operands means otherwise you'd do stuff recursively
like, the easy way is to say from x import y, z becomes pop_top(import_from(import_from(import_name('x', 0), 'y', 'y'), 'z', 'z')) but that's a difficult tree to work with
that'd be more robust to unusual bytecode patterns though i guess
since it'd let you import_from from any object rather than just an immediately preceding import_name
you'd probably want to at least flatten out sequences of import_from/store
so that'd flatten to something import_from(import_name('x', 0, ('y', 'z')), ('y', 'z'), ('y', 'z')) based on a simple rule that if your import_from is followed by another import_from, that gets turned into a list of names and store-destinations instead of just one
what do you think @grave rover
how will I integrate that in my current code tho
uh
the self.pop calls take previous ops and add them to the current token
ok
and self._ops is a list not popped from
yup
ok i'm confused
i don't understand how your tree represents opcodes that do not place exactly one value on the stack
how does a store appear in the tree
sec
because fundamentally what's happening with import from is
the module is placed on the stack
then values are repeatedly retrieved from it with import_from, and they're placed in their destination with store instructions
the module stays on the stack while this is happening, it's not placed in a variable
import_from is basically just like load_attr except it doesn't remove the module from the stack
ok i think the whole conceptual problem with your tree structure
is that you assume that nothing interacts with operands that it does not pop from the stack
well look at your tree now
IMPORT_NAME[1](matplotlib.pyplot, []),
STORE_NAME[3](plot, IMPORT_FROM[3](plot)),
STORE_NAME[4](legend, IMPORT_FROM[4](legend)),```
the module returned by IMPORT_NAME should, properly, be an argument to both IMPORT_FROM ops
next(op for op in self._ops[::-1] if op.op_name == "IMPORT_NAME")
hmm
are there any ops that you're currently handling that return two values?
no that won't work either
ok uh
what if you turned the tree inside out
the tree item for every opcode that returns a value on the stack, contains every operation that occurs while it is still on the stack
Hm
Ideally I'd have the IMPORT_FROM on the IMPORT_NAME since it'd make the other steps easier
Like converting bytecode to code
so your tree would look like LOAD_CONST(0, [ LOAD_CONST(('plot', 'legend'), [ IMPORT_NAME(matplotlib.pyplot), [ IMPORT_FROM(plot, [STORE_NAME(plot)]), IMPORT_FROM(legend, [STORE_NAME(legend)]), POP_TOP]) ]) ]) ])
no, what i'm saying is
don't close the list until the value is popped from the stack
i don't even know how you'd do it in code
it'd probably require reworking the whole thing 😦
but for example, py [ IMPORT_FROM(plot, [STORE_NAME(plot)]), IMPORT_FROM(legend, [STORE_NAME(legend)]), POP_TOP]) ] is a sequence of operations that works with one value (the module) on the stack, and pops it at the end.
LOAD_CONST(('plot', 'legend'), [
IMPORT_NAME(matplotlib.pyplot), [...])
])``` is a sequence of operations that consumes one excess value from the stack (the LOAD_CONST(0)), since IMPORT_NAME pops two arguments
i just don't know how you even can properly represent a mixture of import_from and stores in the current structure
eh
a weakness in the current tree structure seems to be that it assumes that every operation that doesn't return a value onto the stack (e.g. stores) happens at the top level, not inside the "arguments" to another operation
and I don't know how to fix that
sure
in python code
but in bytecode, you're absolutely storing plot while the module operand that will be used for import_from(legend) is still on the stack
it's not even some_func(ASSIGNMENT), not really
the assignment isn't being passed to some_func, it's just happening while the argument list for some_func is being set up
so it's like if you had some_func(ASSIGNMENT, 1) and some_func only actually sees 1 as the argument
I need to see code to understand what you mean tbh
ok wait what
so how does that show up in the tree representation? the same operation shows up multiple places?
i didn't know that was an option - it shouldn't be, you could very easily make trees that can't be represented in bytecode that way
ok i am not talking about your code - i am talking about how the bytecode itself works
like
if you use self.last for IMPORT_FROM, what does that make your tree look like?
this? py STORE_NAME[3](plot, IMPORT_FROM[3](plot, IMPORT_NAME[1](matplotlib.pyplot, []))), STORE_NAME[4](legend, IMPORT_FROM[4](legend, IMPORT_NAME[1](matplotlib.pyplot, []))), POP_TOP[0](IMPORT_NAME[1](matplotlib.pyplot, [])),
uhh
it would work for the first IMPORT_FROM
not for the second since for the second one self.last becomes a STORE_NAME
ok that's another problem then
STORE_NAME doesn't put anything on the stack
there needs to be a way to reference the expression generating the top (and second, etc) item on the stack for any of this to work at all
not just "the last operation executed regardless of if it put anything on the stack or not"
i really do think your code needs to be able to recognize patterns rather than simply going one instruction at a time
i haven't looked at it enough to know how you're going to deal with conditionals, loops, etc, but any approach needs to be able to handle embedded conditionals inside expressions, not just a top-level "basic block" pass
I'm not exactly emulating the stack
I'm just adding ops to a list
I leave running the code to the end user
ok
but if you're trying to turn it into a tree, you need the stack to know what operations feed their results into what other operations
a list doesn't have that issue, but i thought you were trying to make a tree
Yeah but like, I have a list and tree and both are added to at the same time, the tree just gets popped from for building the tree
@sick hound in case you care, i made with:
#w is the function to do work with, orig syntax is (with w():)
#f is executed in the context of w.
#If s is set to a string, and that string is the name of the first var in f, w will be passed through it
#a is the args passed to f, after the first var if s is set
#will return the return val of f
withFunc = lambda w,f,s='',a=[]:type(
'',
({x.__name__:x for x in object.__subclasses__()}['ContextDecorator'],),
{
'__init__':lambda self,c:setattr(self,'c',c),
'__enter__':lambda self:self.c.__enter__(),
'__exit__':lambda self,*args,**kwds:self.c.__exit__(*args,**kwds)
}
)(w)(f)(*([w] if (lambda c=f.__code__.co_varnames:c and s==c[0])() else [])+a)```
Beautiful
did you see my tryExcept from earlier @arctic bridge ?
#t is try block (lambda)
#a is a tuple or list of arguments passed as t(*a)
#f is except block (lambda) and can have up to 3 arguments;
#1:Exception Class, 2:Exception Instance, 3:Traceback (*args works)
#e is Exception or [Exception1, Exception2,...]
#return val can be (in order) try() result, except() result, None
tryExceptRet = lambda t,a=[],f=lambda:None, e=Exception,r=[]:[
r.clear(),
r.append(type(
'',
({x.__name__:x for x in object.__subclasses__()}['ContextDecorator'],),
{
'__enter__':lambda self:setattr(self,'c',f.__code__),
'__exit__':lambda self,*a:not r.append(
f(
*a if self.c.co_flags == 71 else a[0:self.c.co_nlocals]
)
) if any(
map(
(a[0] or object).__mro__.count,e if e.__class__ == list else [e]
)
) else 0
}
)()(t)(*a)),
r[0],
][2]
it can all be onelined, because why not
Nice
i might try to make a oneline code generator this summer
neat
9<<(7<<60) largest possible number in Python using only 10 bytes of code
hmm interestin'
More than 10^242944768872896860
Yeah, throws MemoryError, but what’s the point of it anyway? 
This number is so big that it requires almost 1 EiB of memory to hold it, which is a little bit more than I have on my computer. Luckily, you only need to use around 0.2% of the world's storage space as swap to hold it. The value in binary is 1001 followed by 8070450532247928832 zeros.
STORE_DEREF(i)¶
Stores TOS into the cell contained in slot i of the cell and free variable storage.
So is this 'cell and free variable storage' essentially a list?
what is a 'cell' in this context?
@brazen geyser what?
There are a number of places where things are stored in/loaded from the 'cell and free variable storage'
I've been able to glean what free variables are, but what are cells?
and what/where are they stored in?
is it basically just a list?
So afaik, python has a set of "free" variables
Like there is a technical maximum per script
And there is extended variables too
@sick hound might know
ok so this is the C code
case TARGET(STORE_DEREF): {
PyObject *v = POP();
PyObject *cell = freevars[oparg];
PyObject *oldobj = PyCell_GET(cell);
PyCell_SET(cell, v);
Py_XDECREF(oldobj);
DISPATCH();
}
now to track down PyCell_SET
and GET
#define PyCell_GET(op) (((PyCellObject *)(op))->ob_ref)
#define PyCell_SET(op, v) (((PyCellObject *)(op))->ob_ref = v)
LIST_APPEND(i)¶
Calls list.append(TOS[-i], TOS). Used to implement list comprehensions.
what does this even mean? append only takes one argument
@brazen geyser could be pseudo code for the C implementation. Which would prob be given a pointer to the first item of the list and the item to append
@rugged sparrow thinking about it again, i reckon TOS[-i] is meant to be self and it's literally list.append as in the unbound method
oh that makes sense
can you show any disassemblies that have STORE_DEREF?
@grave rover this might actually work
(from r/SoftwareGore)
Oof
And huh, sorry if it is considered as a meme
@grave rover STORE_DEREF is associated with nonlocal
>>> def f():
... x = None
... def g():
... nonlocal x
... x = 1
...``` ```py
Disassembly of <code object g at 0x0000000002AF2DB0, file "<stdin>", line 3>:
5 0 LOAD_CONST 1 (1)
2 STORE_DEREF 0 (x)
4 LOAD_CONST 0 (None)
6 RETURN_VALUE```
[and just like the other stores, you can get it from any that assigns a name, e.g. def/class/import]
>>> from ctypes import*;1/(cast(pointer(c_int(0x5F37642F-(cast(pointer(c_float(42)),POINTER(c_int))[0]>>1))),POINTER(c_float))[0])**2
39.27731871084027```
Does anyone have a snippet to map dict.__getattr__ to use dict.__getitem__ so you can use JS-style dict lookups?
@desert garden you can always make an inherited class. but i assume you want to make normal dicts behave that way?
Yeah
hmm
class dictJS(dict):
def __getattr__(self,item):
return self.__getitem__(item)``` cause thats all the new class needs
I'm on mobile right now but in the past I've tried ctypes'ing it in and it didn't work
I want native {}s to use it
maybe could replace builtins dict
one sec
nope :/
ill do some research tho
@desert garden https://pypi.org/project/forbiddenfruit/ this can do it
can forbiddenfruit overload dunders now?
Traceback (most recent call last):
File "test.py", line 8, in <module>
curse(dict, '__getattr__', get_item)
File "/home/jeremiah/.pyenv/versions/3.7.2/lib/python3.7/site-packages/forbiddenfruit/__init__.py", line 412, in curse
_curse_special(klass, attr, value)
File "/home/jeremiah/.pyenv/versions/3.7.2/lib/python3.7/site-packages/forbiddenfruit/__init__.py", line 329, in _curse_special
tp_as_name, impl_method = override_dict[attr]
KeyError: '__getattr__'
rip
yeah I guess someone'll come up with some ctypes voodoo
probably
My usually ctypes voodoo didn't work on it when I tried, oddly
It can patch in things like str.spongebob(), but I think there's something special about dict.__getattr__
@desert garden dict.__getattr__ is actually dict.__getattribute__ first of all
I'm on mobile :). Don't wanna type that out lol
>>> x.__getattribute__
Segmentation fault (core dumped)
chronos@localhost ~ $ ``` how to know youre getting somewhere lmao
Lmao
>>> proxy_builtin(dict)['__getattribute__'] = lambda self,item:self.__getitem__(item)
>>> x= {'x':1}
>>> x
{'x': 1}
>>> x.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'x'
>>> x.__getattribute__
<bound method <lambda> of {'x': 1}>
>>> x.__getattribute__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: <lambda>() missing 1 required positional argument: 'item'
>>> x.__getattribute__(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
KeyError: 1
>>> x.__getattribute__('x')
1
>>> ``` @desert garden
i dont think that dict actually uses __getattribute__ to get attributes
its just for subclasses
There should be some way to force it to though
true
import ctypes
class PyObject(ctypes.Structure):
pass
Py_ssize_t = hasattr(ctypes.pythonapi, 'Py_InitModule4_64') and ctypes.c_int64 or ctypes.c_int
PyObject._fields_ = [('ob_refcnt', Py_ssize_t),('ob_type', ctypes.POINTER(PyObject)),]
class SlotsPointer(PyObject):
_fields_ = [('dict', ctypes.POINTER(PyObject))]
def proxy_builtin(_class):
name = _class.__name__
slots = getattr(_class, '__dict__', name)
pointer = SlotsPointer.from_address(id(slots))
namespace = {}
ctypes.pythonapi.PyDict_SetItem(ctypes.py_object(namespace),ctypes.py_object(name),pointer.dict)
return namespace[name]
``` @desert garden this is what im trying rn
>>> proxy_builtin(list)['index'] = lambda *args:print('test')
>>> [1].index()
test``` btw this works. so i think that overriding any of the "magic" methods is difficult
ctypes.memmove didnt work
honestly @brisk zenith probably would know more towards getting that to work
@rugged sparrow builtin methods are written in C, you cannot simply overwrite them with python functions. instead, you should use the ctypes.CFUNCTYPE decorator/function to convert it to a C function pointer
how would i then apply it?
well, builtin methods are just pointers to C functions, so you just overwrite the pointer in memory
And I can get the current location using ctypes I assume?
@brisk zenith how can i get the original functions pointer?
uhh.. depends on its location within the PyTypeObject C struct
it's kinda really tricky to do
ah
without spaghetti code, that is
my cpystructs code would help with it somewhat though
did you ever post that?
yeah, but i haven't had the time to bring out any updates for it and it's still very WIP
ah so it might not work for this?
it would certainly help but i recommend you use it as a reference until i get time to work on it properly and make it fully functional and whatnot.
I was using the snippet @rugged sparrow shared, (i actually took it from stackoverflow)
it sometimes gives segfault, sometimes runs as expected
Yeah that's where I got it
FORBID_BY_TYPE_ACCESS = {
'FunctionType': [
"__globals__",
]
}
...
for typ, forbids in FORBID_BY_TYPE_ACCESS.items():
members = get_members(getattr(types, typ))
for forbidden in forbids:
del members[forbidden]
this is the code
@gilded orchid how's the Pokemon thing going?
i am curious about this too
I kind of stopped doing it as I couldn't really finish it due to really poor planning on my part, I might restart it sometime though
The main mistakes I made were not doing the damage formula correctly (I missed of out two of the modifiers, critical hits and the random 85% to 100% modifier) and using way to many variables
@gilded orchid I might give it a shot if you don't mind
Yeah I don't mind, you'll probably do it 10x better then I ever could lmao
Lmao aight
@gilded orchid @brisk zenith https://repl.it/@chilaxan/Pokemon-One-Liner in case you want to see what i have so far
Are you doing it for the code art challenge, or just as a one-liner?
im one-lining it first
then im gonna format it into the Pokemon word and maybe a pokeball
oh ok
Also just skimming through your code, wouldn't it be shorter to do map(lambda a:setattr(self,a,locals()[a]),['name','type','stats','moves']) instead of
setattr(self,'name',name),
setattr(self,'type',pType),
setattr(self,'stats',stats),
setattr(self,'moves',moves),
in the pokemon class?
oh ok, makes sense
yea 😃
what did you think of my type based attack strength?
with my hugeass dictionary lmao
i guess it works lmao
I tried storing the type weaknessess with the actual pokemon itself
But it kind of looked like a mess
this is kinda a mess lol
'getCurrentStat':lambda self,user,stat:__import__('math').floor(((self.__dict__[stat] + __import__('random').choice(range(5,15)))*2*user.level)//100)+((user.level+10) if stat=='hp' else 5)
What does this do?
its this formula
im not doing them lmao
i couldnt figure out a good way to implement
and they dont have that much of an effect in a single battle
You could just make the IVs always 31
oh yeah, weren't they called DVs in gen 1
I guess that works
Is there a way to make a lambda (as an argument of a lambda) that changes the locals() in a lambda and makes them actually update
wow I worded that badly
i dont think you can change the locals() in a lambda at all
I guess abusing globals() works just as well
true
if its a small value, then ill just have mutable list in the defaults of the lambda and add the value to it with append
Is there a way to have arguments in a lambda without using any spaces?
like lambda x,y,z:(x,y,z)?
There's a space between lambda and x (i'm was trying to do a oneliner with 0 spaces)
Ah
umm
one sec
you can do lambda\ x:x
@gilded orchid but that has an extra newline
that's not one line anymore though
nvm
challenge 08 is here: python REPL!
this time we're looking for novel solutions to executing python code, all wrapped up in a nice interactive shell (much like the regular python REPL). you can make the code as weird, short, or even as beautiful as you want, but the way it works internally should be the most interesting and unique part of it. you can find more information about the task and restrictions on the repo: https://github.com/python-discord/esoteric-python-challenges/tree/master/challenges/08-python-repl
for those of you who are still working on previous challenges, don't worry. you can still make submissions for any challenge at any point, so just keep working on it as normal :D
i'd also like to thank the other event handlers for planning out this challenge, as i've been too busy to do it myself recently. of course, if you have any ideas that you think would be good for the next challenge, just let me know!
oh, and i know that there are a few more PRs that i should merge. i'll do that tomorrow, i don't have any time now. :)
oooo that looks like a tricky challenge
wait
is this basically you have to write your own python code parser/
without eval exec and compile. that is just code masochism @brisk zenith 😄
Is it allowed to use AST?
oh something like https://github.com/isidentical/pyty
I think i need to add a few more bytecodes and a repl then its done
@gilded orchid were you planning on doing ascii art for the pokemon?
for the challenge, perhaps have code that sinputted written to a py file as a method thats imported on startup, and reload the module and run the method u just wrote to it
@rugged sparrow nope I wasn't planning to do that
weird question, is there a way to print something without using any brackets?
like no ()? @gilded orchid
Yeah
i dont think so
@gilded orchid progress btw https://repl.it/@chilaxan/Pokemon-One-Liner
@gilded orchid heres the finished oneline
@rugged sparrow so how u learned coding?
oo
Onix's Earthquake Missed!
doesn't earthquake have 100% accuracy
wait did you implement the 1/255 bug?
@rugged sparrow
it's getting miss a lot though
yeah I just missed 4/7
should be fixed now @gilded orchid
note that i dont have PP yet
so you can just spam powerful moves
also does it always do move one if you type something that isn't 1-4?
yea
i could have implemented my oneline input loop but i wanted to get a first version done
could you use the PokeAPI to let the user choose their pokemon?
nah cause i had to implement the moves
PokeAPI also has moves though
how to make a python REPL
-> add an input field
-> add an output field
-> run os.system("python -c '<code with proper quotes>'")
-> done
yes but we're looking for novel solutions. if you're not going to think of weird and interesting ways to solve the challenge, then don't. :D
@grave rover i dont think that would solve the challenge. doesnt preserve variables
that too.
I know, just memeing
I might actually go for a fancy REPL
sucks not having exec tho
oh yea @brisk zenith if i want to have files like .pngs in my submission, should i do a folder?
thinking about using fabulous and some 8 bit images to add something to the pokemon thing when i reformat it
yeah for sure. if your submission is more than one file, use a folder to avoid cluttering everything else. seems like you're putting a lot of effort into this, very looking forward to it :D
I might try some fancy stuff with prompt_toolkit
I might even be able to port some of this https://cdn.discordapp.com/attachments/517536012549881866/527591403228758026/unknown.png
Sounds good
It may be a bit till it's well and truly done tho. There isn't any time limit on submitting right? @brisk zenith
dont think so
not at all, please don't feel rushed or anything. you could even make submissions for the first challenges if you find yourself bored at any point, i don't mind.
Sweet
i just found out about this
JSFuck is an esoteric subset of JavaScript, where code is written using only six characters: [, ], (, ), !, and +. The name is derived from Brainfuck, an esoteric programming language that also uses a minimalistic alphabet of only punctuation. Unlike Brainfuck, which require...
owo
its scary
I wonder if you can do something like that with python
:incoming_envelope: :ok_hand: Un-muted @rugged sparrow.
With colour?
I'm looking forward to trying out making a REPL
Unfortunately I have exams so I must wait :(
@gilded orchid with ANSI escape codes
gotta love on the spot patching of imported modules ```py
setattr(f,'init',(lambda self,image:[setattr(self,'img',image.convert('RGBA')),self.resize(None)][0])),
*this was to allow passing a PIL Image instance instead of a file path
@sick hound that's fine, just focus on your exams and work on it when you've got time :D
i'll be making my own solutions to the challenges when i have time
Juan having "time"
fuck off you dosy bellend <3
Haha
No using eval? Sounds like a chance for globals()['e' + 'v' + 'a' + 'l'](input())
globals()['__builtins__'].__dict__['e'+'v'+'a'+'l'] @desert garden
(that still counts as eval and is therefore an uninteresting solution ;D)
@brisk zenith would getting eval through a really weird way be good? Like using ctypes and grabbing the memory address?
It's still eval but its weird eval
i'd be impressed if you can somehow call the default eval C function of the main interpreterstate struct, sure :^)
@brisk zenith i tried to make eval my self (with compiling step) but it isn't hard but time consuming
you need to implement one by one
actually two by two (implement compiler first than evaluator)
btw with PEP570 they added posonlyargs to CodeType
hm okay. i mean, this challenge is quite tricky compared to the other ones, so it's fine if submissions take longer to come in. just take your time, there's no rush or anything
@gilded orchid @brisk zenith check it out. I havent layed it out into artwork yet, but the game works
you need to have pillow and fabulous installed
is there any hacky chance that int.__mod__ could be made to use math.remainder's behavior
i'd assume not because C but still :X
@sick hound yes using ctypes
you sure? i thought you could only patch python-defined methods via ctypes.pythonapi
youd have to mess with memory addresses manually
oh fun
yea
I have a great idea to do this but execution will be difficult
Yup I got it
Yeet
Wait n fuck I need compile()
It's a really weird challenge
I think I might write a bytecode interpreter if I get the chance
The worst part is that I'm so close
For now I'll just use file imports I guess
I'll change it later to something ast-based with a twist :3
What if we just copy paste pypy
sure. i mean really, anything is acceptable just as long as it's interesting and unique
I just noticed something
>>> dis.dis('250 + 250 == 500')
1 0 LOAD_CONST 2 (500)
2 LOAD_CONST 1 (500)
4 COMPARE_OP 2 (==)
6 RETURN_VALUE
>>> dis.dis('500 == 500')
1 0 LOAD_CONST 0 (500)
2 LOAD_CONST 0 (500)
4 COMPARE_OP 2 (==)
6 RETURN_VALUE```
WAT
>>> compile('250 + 250 == 500', '', 'eval').co_consts
(250, 500, 500)```
seems like a bug in the bytecode optimiser or something
not exactly a bug. just a micro-optimization missed.
it's probably relatively rare to use constants with comparison expressions
whereas people will use them with arithmetic all the time, easier to type 22/7 than 3.142856142856142856142856142856
Even though 22/7 is ok but not really pi tbh
>>> compile('1 + 2', '', 'eval').co_consts
(1, 2, 3)```
it looks like it optimizes with basic arithmetic expressions like 250 + 250 or 1 + 2 but then doesn't get rid of the old constants
>>> compile('(1 + 2, 15)', '', 'eval').co_consts
(1, 2, 15, 3, (3, 15))```
it only actually uses the last constant there
the bytecode is optimized but the constants aren't
There's probably some legacy reason they have to leave in the old constants
You could probably ask on the mailing list
tfw I have a bytecode optimizer that fixes that
speaking of which, I need to optimize more
@rose imp please use bot commands in #bot-commands in future
oops sorry I thought I was in that channel
Anyone here have experience with the python CAN package ?
is the python CAN package weird, obfuscated, golfed, or generally weird?
@gilded orchid i finished up the pokemon thing. i just havent formated it yet. do you know any easy way to put an image as a background somewhere i can type it?
to make formating easier?
I don't get what you mean?
like i finished onelining it, but formating it to the pokemon logo is a pain. cause its 8000 - 9000 characters
oh right, maybe you could find a way to get a translucent overlay window of the pokemon logo
which editor do you use?
rn im using code pad text editor cause im on a chromebook
but if there is something online thatd be great
Maybe you could set up an OBS window with your codepad editor and a pokemon logo, then you could look at the obs window while typing in the codepad window
hmm ok
(the reason I suggested that is because I've seen someone use it to put two game windows on top of eachother, both with 50% transparency)
ah makes sense
@sick hound there just aren't that many examples. But I got my stuff working. It's pretty easy and sweet when it works. I was having an issue with the python libraries and the hardware drivers. I finally found the function to close my listener and shutdown the bus.
I'm using python to send new firmware images to micro controllers. So bootloader running on the micro. I convert the hex to binary in python , then send it across the CAN bus. Used TK library to make a little GUI. Working pretty well. Just the exe I build from it is pretty large.
If I were to do a code art esolang could I submit it to both challenges?
Finished my bytecode editor
... in Excel
jesus christ why would you do that to yourself lmao
lol
ok nvm
Only works on *nix platforms.
@brisk zenith pls review
is your solution just an image? I'm really confused
...wtf py Traceback (most recent call last): File "C:\Users\Aaay\AppData\Local\Programs\Python\Python36\lib\runpy.py", line 193, in _run_module_as_main "__main__", mod_spec) File "C:\Users\Aaay\AppData\Local\Programs\Python\Python36\lib\runpy.py", line 85, in _run_code exec(code, run_globals) File "image (1).png\__main__.py", line 2, in <module> File "", line 2, in <module> ModuleNotFoundError: No module named 'fcntl'
that's on windows and I know it only works on *nix platforms
but... HOW
WTF is going on there
how on earth did you make a python file into a png and have it not look like a garbled mess
it contains __main__.py
but not fcntl
>>> dis.dis(code)
1 0 LOAD_CONST 0 (0)
2 LOAD_CONST 1 (None)
4 IMPORT_NAME 0 (atexit)
6 STORE_NAME 0 (atexit)
2 8 LOAD_CONST 0 (0)
10 LOAD_CONST 1 (None)
12 IMPORT_NAME 1 (fcntl)
14 STORE_NAME 1 (fcntl)
3 16 LOAD_CONST 0 (0)
18 LOAD_CONST 1 (None)
20 IMPORT_NAME 2 (random)
22 STORE_NAME 2 (random)
4 24 LOAD_CONST 0 (0)
26 LOAD_CONST 1 (None)
28 IMPORT_NAME 3 (signal)
30 STORE_NAME 3 (signal)
5 32 LOAD_CONST 0 (0)
34 LOAD_CONST 1 (None)
36 IMPORT_NAME 4 (struct)
38 STORE_NAME 4 (struct)
6 40 LOAD_CONST 0 (0)
42 LOAD_CONST 1 (None)
44 IMPORT_NAME 5 (termios)
46 STORE_NAME 5 (termios)
7 48 LOAD_CONST 0 (0)
50 LOAD_CONST 1 (None)
52 IMPORT_NAME 6 (time)
54 STORE_NAME 6 (time)
9 56 LOAD_CONST 0 (0)
58 DUP_TOP
60 STORE_GLOBAL 7 (width)
62 STORE_GLOBAL 8 (height)```
this is weird
it doesn't contain compile
or code
how would you make a png file contain main.py?
i have no idea
i'm guessing there's some kind of very weird compression going on here
I don't think that's what they had in mind when they said 'code art' lmao
it generates a code object with loads of names that don't appear in the file
I can't really talk since I don't know anything about bytecode, but is it maybe an import?
it's importing names and defining functions
all of those names have to come from somewhere
but they're not in the file
...wat
where on earth is main.py coming from
WHAT THE... HOW...
inspect.getsource returns code
it loads a code object with marshal
and then executes it
i have no idea how they put that in a png file
@wind maple pls explain lmao
and actually the code in there isn't even in the file
don't explain, i'm having fun figuring it out :P
...zipimporter
you put a zip file in a png?
wow
it does contain PK
IT'S A ZIP FILE
YOU PUT A ZIP FILE IN A PNG
the zip file has a main.py
but how does the zip get decompressed
i guess python does it
the image and zip file are completely separate
IEND®B`‚PK
IEND®B`‚ is the end of the .png file
PK is the beginning of the .zip file
why does python ignore the image then, if it does decompress the zip?
turns out just renaming it to a zip and unzipping it gives you the code
I just renamed it to image.zip
ava@madoka ~/example> unzip image.png
Archive: image.png
warning [image.png]: 456 extra bytes at beginning or within zipfile
(attempting to process anyway)
inflating: __main__.py```works4me
oh
i already managed to do it
by removing the PNG from the beginning in a text editor
...so you put python code in a .zip file in a .png file
I was considering doing more layers of dumb unnecessary obfucsation
I am so confused...
I feel like this is taking esoteric-python to a whole new level lmao
@wind maple do you know why the python interpreter ignores the png file and unzips the python file?
yes
zip files are scanned from the end
it sees that the file ends in the zip end of archive marker and starts scanning backwards
wow that is weird
@wind maple that's pretty cool, i'll test it soon. :D
if you do it right, the zip file should think it's a self-extracting zip and not get any errors
if you just concatenate the zip to the png or whatever, some zip tools can still handle it but it's not a well-formed zip
so some tools can handle it and others can't
zip -A can fix it
@wind maple
(now i'm wondering if there's a way to put the png inside the zip)
nope, local file header is required to be followed directly by the data
i wonder if there's a way to embed the zip central directory and file data in the png as chunks instead of concatenated to the end
png allows "ancillary" chunks, that decoders are meant to ignore if they don't recognize
so you could just make a big hzIp chunk with a zip file in it or something
and that should be ignored
@gilded orchid Images start at the header, Zip files at the footer
Python checks the footer first if it doesn't end in .py[cod]?
If it's a zip it unzips it which works fine, it ignores the first data
Then it runs main.py
I think the most you can do is an image, PDF and then a zip
>>> os.dup2(3,0)
>>> Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> >>>```
what does that do lmao
it duplicates the file descriptor 3 to stdin
in that case, file descriptor 3 was a file containing b'1/0\nos.dup2(5,0)\n'
and file descriptor 5 was a copy of stdin
Hello, can someone help me with pygame like with importing images to it
eval("""eval("print('!First£`!Second£y`!Third£qy`!Fourth£zqy`!Fifth£]zqy`!Sixth£[]zqy`!Seventh£=[]zqy`!Eighth£-=[]zqy`!Ninth£*-=[]zqy`!Tenth£&*-=[]zqy`!Eleventh£^&*-=[]zqy`!Twelfth
£%^&*-=[]zqy`')+'!','On the ')+'£','day of Christmas\nMy true love sent to me')+'%','Twelve Drummers Drumming,\n')+'^','Eleven Pipers Piping,\n')+'&','Ten Lords-a-Leaping,\n')+'*','Nine Ladies Dancing,\n')+'-','Eight Maids-a-Milking,\n')+'=','Seven Swans-a-Swimming,\n')+'[','Six Geese-a-Laying,\n')+']','Five Gold Rings,\n')+'z','Four Calling Birds,\n')+'q','Three French Hens,\n')+'y','Two Turtle Doves, and\n'+'`','A Partridge in a Pear Tree.\n\n')""".replace('+','.replace('))
I have to find an error in this
oh god why
@gilded orchid look at the code that the eval is running
>>> print("""eval("print('!First£`!Second£y`!Third£qy`!Fourth£zqy`!Fifth£]zqy`!Sixth£[]zqy`!Seventh£=[]zqy`!Eighth£-=[]zqy`!Ninth£*-=[]zqy`!Tenth£&*-=[]zqy`!Eleventh£^&*-=[]zqy`!Twelfth
... £%^&*-=[]zqy`')+'!','On the ')+'£','day of Christmas\nMy true love sent to me')+'%','Twelve Drummers Drumming,\n')+'^','Eleven Pipers Piping,\n')+'&','Ten Lords-a-Leaping,\n')+'*','Nine Ladies Dancing,\n')+'-','Eight Maids-a-Milking,\n')+'=','Seven Swans-a-Swimming,\n')+'[','Six Geese-a-Laying,\n')+']','Five Gold Rings,\n')+'z','Four Calling Birds,\n')+'q','Three French Hens,\n')+'y','Two Turtle Doves, and\n'+'`','A Partridge in a Pear Tree.\n\n')""".replace('+','.replace('))
eval("print('!First£`!Second£y`!Third£qy`!Fourth£zqy`!Fifth£]zqy`!Sixth£[]zqy`!Seventh£=[]zqy`!Eighth£-=[]zqy`!Ninth£*-=[]zqy`!Tenth£&*-=[]zqy`!Eleventh£^&*-=[]zqy`!Twelfth
£%^&*-=[]zqy`').replace('!','On the ').replace('£','day of Christmas
My true love sent to me').replace('%','Twelve Drummers Drumming,
').replace('^','Eleven Pipers Piping,
').replace('&','Ten Lords-a-Leaping,
').replace('*','Nine Ladies Dancing,
').replace('-','Eight Maids-a-Milking,
').replace('=','Seven Swans-a-Swimming,
').replace('[','Six Geese-a-Laying,
').replace(']','Five Gold Rings,
').replace('z','Four Calling Birds,
').replace('q','Three French Hens,
').replace('y','Two Turtle Doves, and
'.replace('`','A Partridge in a Pear Tree.
')```
there's a random " that goes over multiple lines and doesn't ever get closed
where? the one on the first line?
yes
you don't have any " to end that string
and also inside that string you have a lot of strings that end with an actual newline instead of a \n character
I thought I only put \n, it goes onto one line?
nvm turns out there was one newline
I'm still getting EOL while scanning string literal?
I changed it to:
eval("""eval("print('!First£`!Second£y`!Third£qy`!Fourth£zqy`!Fifth£]zqy`!Sixth£[]zqy`!Seventh£=[]zqy`!Eighth£-=[]zqy`!Ninth£*-=[]zqy`!Tenth£&*-=[]zqy`!Eleventh£^&*-=[]zqy`!Twelfth£%^&*-=[]zqy`')+'!','On the ')+'£','day of Christmas\nMy true love sent to me'")+'%','Twelve Drummers Drumming,\n')+'^','Eleven Pipers Piping,\n')+'&','Ten Lords-a-Leaping,\n')+'*','Nine Ladies Dancing,\n')+'-','Eight Maids-a-Milking,\n')+'=','Seven Swans-a-Swimming,\n')+'[','Six Geese-a-Laying,\n')+']','Five Gold Rings,\n')+'z','Four Calling Birds,\n')+'q','Three French Hens,\n')+'y','Two Turtle Doves, and\n'+'`','A Partridge in a Pear Tree.\n\n')""".replace('+','.replace('))
eval("print('!First£`!Second£y`!Third£qy`!Fourth£zqy`!Fifth£]zqy`!Sixth£[]zqy`!Seventh£=[]zqy`!Eighth£-=[]zqy`!Ninth£*-=[]zqy`!Tenth£&*-=[]zqy`!Eleventh£^&*-=[]zqy`!Twelfth£%^&*-=[]zqy`').replace('!','On the ').replace('£','day of Christmas
My true love sent to me'").replace('%','Twelve Drummers Drumming,
').replace('^','Eleven Pipers Piping,
').replace('&','Ten Lords-a-Leaping,
').replace('*','Nine Ladies Dancing,
').replace('-','Eight Maids-a-Milking,
').replace('=','Seven Swans-a-Swimming,
').replace('[','Six Geese-a-Laying,
').replace(']','Five Gold Rings,
').replace('z','Four Calling Birds,
').replace('q','Three French Hens,
').replace('y','Two Turtle Doves, and
'.replace('`','A Partridge in a Pear Tree.
')```
if you want the string to contain the actual text \n instead of a newline you need \\n
also... what on earth are you doing?
Code Golf is a game designed to let you show off your code-fu by solving problems in the least number of characters.
why do you have an extra eval in the eval?
so I can do `.replace('+','.replace')
the first eval is enough to let you do that
wait how would I do it with one eval?
because then the .replaces would have to be a string
which would only be possible if an eval was inside another eval?
...no
why do you need two evals?
you can do one eval that converts + into .replace(
and then that's all you need
what's the second one for???
oh wow I'm dumb, nvm lol
On the First daTwo Turtle Doves,
of Christmas
MTwo Turtle Doves,
true love sent to me
`On the Second daTwo Turtle Doves,
seems correct 🤔
eval("""print('!First£`!Second£3`!Third£23`!Fourth£123`!Fifth£]123`!Sixth£[]123`!Seventh£=[]123`!Eighth£_=[]123`!Ninth£*_=[]123`!Tenth£&*_=[]123`!Eleventh£^&*_=[]123`!Twelfth£%^&*_=[]123`')+!','On the ')+£',' day of Christmas\\nMy true love sent to me\\n')+%','Twelve Drummers Drumming,\\n')+^','Eleven Pipers Piping,\\n')+&','Ten Lords-a-Leaping,\\n')+*','Nine Ladies Dancing,\\n')+_','Eight Maids-a-Milking,\\n')+=','Seven Swans-a-Swimming,\\n')+[','Six Geese-a-Laying,\\n')+]','Five Gold Rings,\\n')+1','Four Calling Birds,\\n')+2','Three French Hens,\\n')+3','Two Turtle Doves, and\\n')+`','A Partridge in a Pear Tree.\\n\\n')""".replace('+',".replace('"))
AttributeError: 'NoneType' object has no attribute 'replace'?
nvm I got it
print(...).replace
^
print returns None lol
Hey guys, what about "weirdest while True loop definition"? For example,
while not False:
...
while [x for x in range(1)]:
...
while bool(1):
...
not esotericey enough i'd say
@gilded orchid your suggestions? :)
while __build_class__:
...```
import sys
def trace(frame, event, arg):
if event == 'line':
if frame.f_code.co_code[frame.f_lasti]==116 and frame.f_code.co_names[frame.f_code.co_code[frame.f_lasti+1]]=='_begin':
frame.f_lineno += 1
trace.start = frame.f_lineno
elif frame.f_code.co_code[frame.f_lasti]==116 and frame.f_code.co_names[frame.f_code.co_code[frame.f_lasti+1]]=='_end':
frame.f_lineno = trace.start
return trace
sys.settrace(trace)
def test():
_begin
print('Hello!')
_end
test()```
@marsh void how about that?
there's no while loops in it but print('Hello!') still gets executed forever
and you can't do break or continue
smh using sttrace slows everything down loads
Use some bytecode manipulation and just replace _end with a jump to the _begin
And replace _begin with some nops
Literally just realised you can enumerate a dict to get the ‘index’ of each key:value pair.
Decided to make a search dict by index because why not? lol
and yes I know there’s other ways which are less lines aka list(dict.items())[index_to_get] but just interesting that you can do it like this too (and my method actually stores the index as well, rather than just doing list[index])
Well yeah
Hey pythoners, so our main friends are lambda, map, zip, reduce?
for one-liners, I'd say lambdas, list comprehension and maybe short circuiting are the most important
for golfing i'd say eval is most important
making code as short as possible
Doing something in as little characters as possible
It's called code golfing because you try to get as low a score as possible in golf
try golfing the definition of "golfing"
"DoThingMinLen"
that's what code golf is, golfed
why say lot word when few word do trick
we move OT?
Example:```python
eval("""print('!First£!Second£3!Third£23!Fourth£123!Fifth£]123!Sixth£[]123!Seventh£=[]123!Eighth£_=[]123!Ninth£_=[]123!Tenth£&*_=[]123!Eleventh£^&=[]123!Twelfth£%^&*_=[]123'+!','On the ')+£',' day of Christmas\nMy true love sent to me\n')+%','Twelve Drummers Drumming,\n')+^','Eleven Pipers Piping,\n')+&','Ten Lords-a-Leaping,\n')+*','Nine Ladies Dancing,\n')+','Eight Maids-a-Milking,\n')+=','Seven Swans-a-Swimming,\n')+[','Six Geese-a-Laying,\n')+]','Five Gold Rings,\n')+1','Four Calling Birds,\n')+2','Three French Hens,\n')+3','Two Turtle Doves, and\n')+`','A Partridge in a Pear Tree.\n\n'))""".replace('+',".replace('"))
The 2200 character lyrics of 12 days of christmas cramed in 606 characters
wow cool
that stuff is hella unreadable tbh, or at least I’m not used to it as for now
But yeah, after second reading through, starts to make sense lol
Fortunately, the kind of code you golf isn't the type you need to maintain later.
Yeah, fortunately 
yeah but that kind of defeats the point of oneliners
i usually dislike the use of eval like that when golfing
i care
real drama is about to start lol
eval is a cheaty golf
Most things you can do with eval you can do with clever tricks too
i've seen exec used quite a lot, esp in py 2
hm
I've used it a few times for edge cases
Like for codingame challenges where multiple inputs are required a,b,c=eval('input(),'*3)
>>> 'hello world'''
'hello world'```
Weird lol
But understandable, since it most likely prints('hello world') then scans and finds ''
Yeah it does
>>> 'a''b''c'
'abc'
turns out you don't need to use + to add string together
just a combined string literal, 'hello world' and '' - if you directly write multiple string literals after another, they get interpreted as single string, which allows you to e.g. switch quotes or f-/r-strings without an explicit concatenation
It's also useful if your lines get too long
yeah
my_string = (
"this will all "
"be one string"
)
>>> print('this is a very '
... 'long string')
this is a very long string```
wait ellipsis lol
REPL
but yeah, it’s cool that it works like that
just python repl
though even is you write a +, the interpreter will optimize it to a single literal
>>> dis.dis("'hello''world'")
1 0 LOAD_CONST 0 ('helloworld')
3 RETURN_VALUE
>>> dis.dis("'hello'+'world'")
1 0 LOAD_CONST 2 ('helloworld')
3 RETURN_VALUE
What is that though?
bytecode disassembly
but I wonder what that 0 vs 2 in the second to last column means
it's the actual argument in the bytecode
for LOAD_CONST, it's the index of the constant in the list of constants stored internally in the code object
@tropic gulch because it still compiles constants for the original strings
>>> compile("'hello'+'world'",'','eval').co_consts
('hello', 'world', 'helloworld')``` doesn't do it for me in 3.7, but does in 3.6.6
I think I saw someone complaining about that a few days ago, idk if it was in here or on a mailing list
🤷
class LOL:
def __init__(self):
pass
def __hash__(self):
return hash(self)**2
lol = LOL()
hash(lol)
oh man why this code isn’t working? what is that weird RecursionError?
you've accidentally made your __hash__ method recursive, since doing hash(self) will call __hash__, so your method just continually calls itself until you run out of memory
@marsh void
Yeah I know, decided to do it as a joke but failed lol
Is there a way to update an something in a list variable using global.update()?
globals().update({aList[2]:3}) something like this
well, globals["list_name"][2] = 3
or, globals["list_name"].__setitem__(2, 3) i believe
oh ok, thanks
does that mean you can run python in lua in python?
Yes
And Lua in python in lua in python
Not much of a point though since both Lua instances share the same runtime, same with python
a=[0,1]
eval('a+=sum(a[-2:])\n'*31)
'\n'.join(a)
Why doesn't this work as a golf for the fibonacci sequence
It gives a SyntaxError
eval evaluates an expression
2+2 or print("hello") are expressions
a+=sum(a[-2:])``` is not an expression
use exec instead
@gilded orchid
then I get:TypeError: 'int' object is not iterable
what's your code?
a=[0,1]
exec('a+=sum(a[-2:])\n'*31)
'\n'.join(a)
you can do a+=[sum(...)]
Is using phi formula and listcomp for it considered inefficient?
phi = (1+5**0.5)/2; [int((phi**n-(1-phi)**n)/(5**0.5)) for n in range(10)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
not golfing, but still pretty math beautiful
[x for x in range(2, a+1) if not any(x % y is 0 for y in range(2, int(x**0.5)+1))]
gets all prime numbers up to a
what do you guys think about this?
Too much whitespace
[x for x in range(2, a+1)if~any(x%y==0for y in range(2,int(x**0.5)+1))+2]
Can invert all the checks for ```py
[x for x in range(2,a+1)if all(x%y for y in range(2,int(x**0.5)+1))]
you can also use .5 instead of 0.5
[x for x in range(2,a+1)if all(x%y for y in range(2,int(x**.5)+1))]```
heh well, is it the shortest one?
is what the shortest what
Yeah well
[x for x in range(2,a+1)if all(x%y for y in range(2,int(x**0.5)+1))]
so is this one kind of the best in terms "short and efficient"?
range arguments have to be an int
yeah but it'd be an int even if the int() isn't there
Nope
Makes no difference with brackets since it does ** first anyway
@gilded orchid
that would be correct though
Not an int though
oh yeah, nvm I'm dumb
Lol
Is there a shorter alternative to ~<...>+2 for negation?
Using a tilda had the advantage of removing any whitespace around not, but iirc there's a shorter way I can't remember
huh, that isn't python, is it?
It is
~ is a bitwise inverse
So True goes to -2 and False to -1
Then if you +2 it it's essentially negated the boolean
By putting the +2 at the end not the start you can minimize leading whitespace
ah, so <...> isn't part of the syntax but just your placeholder, got it
if it's really just True and False as input x, how about 1-x?
.. does -x not work?
-True is still -1, -False is still 0
ohh i misunderstood the question, my bad.
x^1
True^1 is 0, False^1 is 1
So I guess it’s the best one
how does matplotlib work? eg. you need to assign stuff to variables for them to actually work (but the variables are not attached to anything), otherwise that line does nothing
(eg. making an animated graph, something something FuncAnimation but i havent used matplotlib in some time)
Could you give an example of the weirdness? Are you sure you don't use the variable later?
yes
i remember doing a graph thing for the last AoC
animation or not it relied on a variable assignment (literally just a = some_code_i_forgot)
It could be to do with reference counting and garbage collection
If you have to store lots of text in a code golf, is there a simple way to compress and decompress it to save characters?
It depends
Sometimes there's an easy way to do it (for long text use b64 encoding or something) but other timesx you'll have to be real creative
@marsh void thanks that's the one I was thinking off
Has the advantage of not leading with a number so you can avoid whitespace
Yeah, Ava was the first though >.>
Also, kinda not esoteric, but I was wondering, is it ok to use ; structures in packages?
for instance, in decorators:
def benchmark(function):
def decorator(*args, **kwargs):
import time; start = time.perf_counter()
res = function(*args, **kwargs); end = time.perf_counter()
estimated = (end-start)*1000; print(f"Executed function {function.__name__}(*args, **kwargs), estimated time: {estimated:.2f}ms.")
return res
return decorator
what would be the benefit of that?
There are no benefits, just it’s more comfortable for me to write some lines like that
but it's far less comfortable for us to read, so don't :D
Do semicolons function identically to new lines?
Also what do you think about "black" code style?
@gilded orchid no, you can't indent after them
oh ok
there are some cases where semicolons just can't be used
I was just gonna use it to replace \n in some of my evals in code golfs
well yeah you can in places
[print(i)for i in range(51)if any([map(int,bin(i)[2:]%a for a in(2,i))])^1] gives SyntaxError: Generator expression must be parenthesized
what does that mean?
(for context, I'm trying to print all the pernicious numbers from 0 to 50)
it means you need to put parentheses (( and )) around a generator expression
map(int,bin(i)[2:]%a for a in(2,i))```
@gilded orchid
also what is a pernicious number
'A pernicious number is a positive number where the sum of its binary expansion is a prime number.'
oh
