#esoteric-python
1 messages · Page 76 of 1
curse(FunctionType, "__new__", my_func)
FunctionType is just a utility for instance checks or creating functions, not the actual type
try type(lambda: 0)
On mobile
uh, no, it is the actual type
>>> import types
>>> types.FunctionType is type(lambda: 0)
True```
But thats ok right?
you can't modify type because those functions are handled in C
Whenever I curse I do something like this:
i_add = int.__add__
def new_add(...):
if (...):
return ...
return i_add(...)
curse...```
I guess we could try using import hooks
get all attributes
find all instances of functions
and patch them
problems will happen with nested functions but I'll figure it out
@grave rover its possible to change it with ctypes. it just takes some effort
*and a bit of segfaults on failing
well yea
Ctypes won't fix it because you'd override the default wouldn't you
Also, there's no way to access a class after bytecode was generated but before the creation of the class object, right
well ik juanita wrote a way to mod int.__add__ by modifying the func pointer
yes, although you might get a bit of a problem with int>(5, 6)
>>> int = type('',(int,),{'__gt__':lambda self, other:print(other) if type(other) == tuple else super().__gt__(self, other)})()
>>> int > (5,6)
(5, 6)
>>>``` @sick hound could do this
or something like that
@formal sandal yea its a valid Ast, but a little messy
@rugged sparrow yeah but now try (int, int) > (5, 6)
so what does MyClass<(int, int)>(5, 6) return
because we need to call something on MyClass with int, int and then call the result of that with 5, 6
so itll evaluate ret = MyClass.__gt__(self, (int, int)) then ret.__gt__(self, (5,6))
youre doing a < b > c
>>> class MyClass():
... def __lt__(self , other):
... return (self, other)
...
>>> MyClass = MyClass()
>>> MyClass<(int, int)>(5, 6)
False``` i at least got it to run
oh wait i had int overwritten
hmm
@grave rover what about writing a __main__ wrapper
wdym
So you call your file like this:
python mywraper file.py
And you do some find all def and add your decorator
it'd be impossible to trigger file.py:__main__
?
set __name__ in your wrapper then
not?
You set name
even by messing with runpy or w/e?
__name__ == '__main__'
import file.py
nah nah not like that
No
That how things like cprofile etc works
Exec isnt bad if you know what you are doing
Or dont care hahah
@pure dew I though #esoteric-python was all about being messy!
Hm, this is better and still valid
lets do it
You can pass exec a globals dict
i just installed 3.8
we can now set local vars in oneliners easily
with the walrus operator
ive got 3.9 installed already
any major stuff?
ah nice
i was installing on a chromebook in dev mode
so i may have bugs
¯_(ツ)_/¯
d = {}
d[1] = d
print(d)
>>> {1: {...}}
Had no idea you could do this
idk if this is esoteric but it is interesting
That's simply assigning value
Yeah, I had no idea you could assign a dictionary value to itself
well you can also make a tuple that contains itself
>>> t
((...),)
>>> t[0] is t
True```
You are not assigning value, you are assigning references
so yes it can contain references to itself
Cool
You can now do this terrible thing instead of for loops
n=10
while(n:=n-1):
print(n)
Might be useful for golfing, since while(n:=n-1) is shorter than for n in range(1,10,-1)
n=0
while (n:=n+1)%10:
print(n)
You can also do this
I'm a bit of a stranger to Ubuntu, but I couldn't seem to install it with apt
Ubuntu only updates repositories like twice a year
Hence why I use Arch
Though I think you could get it working with pyenv
Ah. I guess I'll go the tarball route.
@snow beacon you can add the repo manually
i think its called deadsneks or something
yeah
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get install python3.8
i was trying to install 3.8 some weeks ago but it wouldn't detect openssl
I think it should automatically build with it if you just install openssl
you'd think
Unless you're on macos which requires some build env vars iirc
ubuntu
I wonder if 3.8 and 3.9 have stuff that we could use to make shit even more broken
might just go back to arch, i only moved to ubuntu because the wireless drivers arch was using were wonky --- but it was the better distro
No wireless problems on Arch for me, just install iw/iwd and it works somehow, make sure to use NetworkManager tho
i think it's because of the age of my machine, the drivers it used when booting from usb were fine
If it works from USB it should work from the device itself
you'd think
Try listing all packages installed on the USB
How old is you pc?
almost old enough to have its own discord account
Haha
U ever think of upgrading
a lot of our projects seem to be vizualizing stuff so id imagine some amount of power is needed? Or was it powerfull when you bought it?
i'll upgrade when it breaks
@marsh void 3.8 breaks our new method implementation
Yeah
Maybe there is another way actually?
There def is. Also it could be my installation specifically, I had to compile on a chrome book
but offset of 16 isnt the dict anymore
🤔
salt, grats on helper!
thanks!
@marsh void the assignment expressions mean stuff like ```py
(lambda:(x := int(input()),x**x,)[1])()
10
10000000000
hurrah for setting locals
>>> (lambda y=[0]:(y[0] := 10,y))()
File "<stdin>", line 1
SyntaxError: cannot use named assignment with subscript
>>> ``` sadly sub-scripting doesn't work :/
by hand
oh
haha
Lol
n=0
while n:=-~n%11:print(n)
can this be golfed anymore? for context this is equivelent to (but is one byte shorter than):
for n in range(1,11):print(n)
haha
No one is
@rugged sparrow have you figured the number though
For me +16 returns NULL
Yeah I think that python handles the methods declared in c differently now
So idk
@juanita
Maybe there is a more concise version?
!e
def curry(func, n=None):
if n is None:
n = func.__code__.co_argcount
if n <= 1:
return func
else:
return lambda x: curry(
lambda *args: func(x, *args),
n - 1)
addc = curry(lambda a, b: a + b)
inc = addc(1)
print(inc(6), inc(7))
@formal sandal Your eval job has completed with return code 0.
7 8
@formal sandal Well, you could remove the else 🙂
I'm not talking about golfing...
I mean, conceptually more concise.
Maybe something like
def len(x):
if x is a function:
if x has __len in its default kwargs => return its value
else: return number of arguments
else:
return the old len
Or just make a separate flen function.
Ah sorry, I misunderstood you 🙂 And perhaps I misunderstand that curry function, but isn't it what functools.partial does?
curry is supposed to transform a function like f(a, b, c) into f(a)(b)(c)
(f:=lambda n:1 if n == 1 else n * f(n-1))
print(f(6)) #720
``` recursive factorial lambda using assignment expressions
You could have done that with a regular assignment statement
true
but that can be contained within another lambda
and you can use them in map
*for example
Or you could use a y-combinator like the rest of us peasants and groundlings
That's all I'd heard of.
@opal totem yup, welcome to #esoteric-python
What are some other cool ways to golf some builtins (aside from these)
list(...)
[*...]
math.sqrt(9)
9**.5
I can offer the reverse```py
[f(x) for x in y]
[*map(f, y)]
math.floor(n)
n//1
Note: // does not cast to int
Oh yeah oops
Although they're pretty similar
It'd still be shorter even if you put an int() around it due to the import math
just int(n) would work
^
oh yeah good point
only for positive floats though
it rounds up for negatives because it actually truncated the decimal.
>>> 1j
1j
>>> 2j
2j
what is j?
an imaginary unit
imaginary unit
strange that it doesn't accept i which I think is more used by the people that need them in python
i believe it's because i is commonly used as an index variable, as in for i in range (...)
It's very common in those old style for loops.
oh ok
I was just wondering because I made a thing to test every two character combination as python code and see what it evaluates to
and I got a bit confused when I saw 5j
:D
>>> -1j
(-0-1j)
can someone explain this
>>> 1_2_3_4_5_6_7_8_9_0
1234567890``` or this?
Lol
chilaxan's one: this is a new syntax in python ~3.5 I believe, it is used to make your numbers more readable
100_000 instead of 100000
complex numbers are a + bj so I guess when you do -bj, it also shows the a to be clearer
maybe
>>> 0o1750
1000
what?
Octal
octal I think
base 8 numbers
oh right
>>> 0x
File "<stdin>", line 1
SyntaxError: invalid hexadecimal literal
>>> 0o
File "<stdin>", line 1
SyntaxError: invalid octal literal
>>> 0_
File "<stdin>", line 1
SyntaxError: invalid decimal literal``` these are new in 3.8 right?
the specific errors
I'm getting invalid token in 3.7
cool
also
>>> lambda:1()
<stdin>:1: SyntaxWarning: 'int' object is not callable; perhaps you missed a comma?
<function <lambda> at 0x7ca952f78430>
>>>``` this is neat
There's also a warning for using is with literals now.
>>> () is ()
<stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
True
>>> ``` nice
im curious if the syntax warnings are silenceable
why the kwargs
also the warnings arent handled as exceptions
Anyone wanna golf pythagorean triplets?
Sounds like fun torture on mobile
Here's a program that completes a Pythagorean triple: lambda*v:sum(a**2for a in v)**.5
(I'm not sure this is the objective)
Btw there's an equation for the triplets
a*a and b*b to cut off a couple more
Did you mean the triple creator or calculator?
It generates the third term of a Pythagorean triple
I was thinking creator
I have a non-golfed creator script
But then again it's really simple
f=lambda n,m:(m*m-n*n,2*m*n,m*m+n*n)``` Give it two different positive integers in ascending order, generates a triplet
Shorter, but less general:
g=lambda a:(a,c:=a*a//2+1,c-1)``` It doesn't find all triplets, only those where there's a difference of 1 between the longest sides (still infinitely many). Call with an odd number >= 3.
The brackets aren't necessary
Oh? Sweet, two chars saved 🙂
a*a is shorter than a**2
Indeed it is. Edit time.
there's no reason for double /
But ew, floats
it won;t go to floats
it will
then a*a//2+1
a*a+1>>1 is perfectly valid
less brackets
yeah both of those work
no
it would.
oh I get it
why wouldn't it work?
:D
Getting pretty short!
chilaxan@iBP-PC:~$ python3
Python 3.8.0 (default, Oct 16 2019, 20:51:08)
[GCC 7.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> x[0] = (x := [0])
>>> x
[[...]]
>>>``` uh this works in 3.8
i understand why it works. but it feels broken
it makes sense why it works
¯_(ツ)_/¯
x[0] = (globals().update({'x':[0]}),x)[1]``` its the same as this in 3.7
ohno
is try-except one-lineable?
It already was @marsh void, but it might be easier now
I mean, using a context decorator isn't too hacky
or an old tryExceptRet
with suppress(Exception): ... 
@marsh void my tryExceptRet uses a context decorator to suppress and gather what exceptions happened
Yeah. I'm probably gonna rewrite it for 3.8 to use walrus tho
>>> (x:=[]).append(x)
>>> y[0]=(y:=[0])``` these both have the same result of initializing the var, then storing itself within it
that makes sense
it makes sense that it works
but id feel like python should check that y is subscriptable before getting the value to store
>>> 'a'[0] = print('hello')
hello
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment```
¯_(ツ)_/¯
i guess i just assumed it would eval assignments left to right
at least for subscriptable items
>>> x[0]=x=[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> y=y[0]=[0]
>>> ```
i mean i get why it works
guess i thought it translated x[0] = 1 to x.__setitem__(0,1) internally
>>> dis.dis('x[0] = 1')
1 0 LOAD_CONST 0 (1)
2 LOAD_NAME 0 (x)
4 LOAD_CONST 1 (0)
6 STORE_SUBSCR
8 LOAD_CONST 2 (None)
10 RETURN_VALUE```
also x.__setitem__(0,1) wouldn't make sense
>>> test[0] = 1
Real setitem 0 1
>>> test.__setitem__(0, 1)
Fake setitem 0 1```
Here's a little challenge idea
Find a way to change the __class__ attribute of an object, if you can
We need to find __dict__ of a class which is non-mappingproxy first
>>> s = __import__('ctypes').py_object.from_address(id(object)+16).value
>>> s['__class__'] = None
>>> s
segmentation fault``` @hollow patrol 
@marsh void Let's go one farther
Actually no
Okay, you did that
Somehow you actually did that
Good job
Well
And it is an old method, not going to work on 3.8
oh
@hollow patrol you can in <3.8
but not 3.8?
alright, find out how to do it in 3.8 🙂
>>> __import__('ctypes').py_object.from_address(id(object)+8).value = int
>>> object
0```
Offset of sizeof(c_size_t)
oh
our method works in 3.8 too
Oh yeah
oh nice
huh
epic
neat
haha
what
What module is the sizeof from
Ctypes
Alright
I think they were optimized in 3.8
Also chilaxan I rewrote anony
Nice
This time now it's much better
And much more flexible
And also much more readable
You can create custom statements by overriding anony's statement class
So next
Create some sort of metaclass or something
Which allows any instance of any class of this metaclass to have an overridable class method
hang on what ```py
cast(id(object.dict), py_object)
py_object(<method-wrapper 'repr' of py_object object at 0x000001B9F8602CC0>)```
Yup
Something funky is going on behind the scenes
@sick hound the weird thing is, I saw the same behavior on a rpi3 with python 3.5 yesterday
I feel like the repr just happens to be at the same location as the dict start
by chance
its not actually the repr
if you try to store a ref to it the interpreter segfaults
so uhm
I have a solution but it is meh
[obj for obj in gc.get_objects() if obj == dict(cls.__dict__)][0]
@rugged sparrow @wind maple here is some terrible solution which doesn’t include ctypes at all
Let’s improve this one then
should use is
solution for what
Yeah because
dict(...) creates a new dict
Different ID
oh right
what are you even trying to do
oh cpython again
this channel should just be renamed to cpython-abuse
or a new channel be created
😤
most do
then epic
you ok?
getDict = lambda c:next(o for o in __import__('gc').get_objects() if o=={**c.__dict__})```
yeah this one is cool
The problem is though
Doesn’t our dict creating add to the newer objects?
the dict is only created after get_objects is called
^ that too
although there is a problem
>>> import gc
>>> class Trick:
... def __eq__(self, other):
... return True
...
>>> trick = Trick()
>>> getDict = lambda c:next(o for o in __import__('gc').get_objects() if o=={**c.__dict__})
>>> getDict(object)
<__main__.Trick object at 0x000002196DBC3F98>```
>>> import gc
>>> trick = dict(object.__dict__)
>>> getDict = lambda c:next(o for o in __import__('gc').get_objects() if o=={**c.__dict__} and type(o) is dict)
>>> getDict(object)
{'__repr__': <slot wrapper '__repr__' of 'object' objects>, '__hash__': <slot wrapper '__hash__' of 'object' objects>, '__str__': <slot wrapper '__str__' of 'object' objects>, '__getattribute__': <slot wrapper '__getattribute__' of 'object' objects>, '__setattr__': <slot wrapper '__setattr__' of 'object' objects>, '__delattr__': <slot wrapper '__delattr__' of 'object' objects>, '__lt__': <slot wrapper '__lt__' of 'object' objects>, '__le__': <slot wrapper '__le__' of 'object' objects>, '__eq__': <slot wrapper '__eq__' of 'object' objects>, '__ne__': <slot wrapper '__ne__' of 'object' objects>, '__gt__': <slot wrapper '__gt__' of 'object' objects>, '__ge__': <slot wrapper '__ge__' of 'object' objects>, '__init__': <slot wrapper '__init__' of 'object' objects>, '__new__': <built-in method __new__ of type object at 0x000000006DF7C5C0>, '__reduce_ex__': <method '__reduce_ex__' of 'object' objects>, '__reduce__': <method '__reduce__' of 'object' objects>, '__subclasshook__': <method '__subclasshook__' of 'object' objects>, '__init_subclass__': <method '__init_subclass__' of 'object' objects>, '__format__': <method '__format__' of 'object' objects>, '__sizeof__': <method '__sizeof__' of 'object' objects>, '__dir__': <method '__dir__' of 'object' objects>, '__class__': <attribute '__class__' of 'object' objects>, '__doc__': 'The most base type'}
>>> _ is trick
True```
nope
def get_dict(cls):
getDict(cls)['__test__'] = None
actual = getDict(cls)
actual.pop('__test__', None)
return actual``` @sick hound
two calls but no tricks
lol
>>> 0xfor 0
15```
took me a moment but it makes sense
the syntax highlighting did ruin the surprise for me though. still didnt understand why it picked 15 over 0 until i remembered 0 is false...
oh i guess it always picks the first one if they both are True
[0xfor i in range(10)]
I have made an atrocious thing
!e
class run_on_in:
def __init__(self, func, *args):
self.func = func
self.range = range(*args)
def __contains__(self, x):
for i in self.range:
self.func(i)
def Range(*args):
def inner(func):
return run_on_in(func, *args)
return inner
_ = object()
(0xfor _) in Range(5)(
print
)```
@formal sandal Your eval job has completed with return code 0.
001 | 0
002 | 1
003 | 2
004 | 3
005 | 4
By the way... Did you know that there is a Category Theory module in sympy?
spends the rest of his life in front of a computer with the latest version of sympy
do we know of a way to replace a method-wrapper function with our own function? (typically in a mappingproxy)
well you can make ints callable ```py
from ctypes import *
def new_call(self, args, kwargs):
... print('hello')
... return self
...
(c_void_p*52).from_address(id(int))[16] = cast(CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_void_p)(new_call), c_void_p)
5()
<stdin>:1: SyntaxWarning: 'int' object is not callable; perhaps you missed a comma?
hello
5```
syntaxwarnings are gonna be the bane of #esoteric-python
yes i know this is horrific and traumatizing, let me do it anyway
well in that case, #esoteric-python's next project is to find out how to disable syntax warnings
lol
very epic
How terrible was my truck patch in the new get_dict function though?
Does someone know how to override any of the dunder methods though?
You can do a stop warnings from printing using warnings.filterwarnings I think
Wait nvm, you can't disable syntax warnings with that
!e ```python
instr = "Mary had a little lamb"
output = list(instr)
output[::2], output[1::2] = instr[::2], instr[1::2][::-1]
print(''.join(output))
@distant wave Your eval job has completed with return code 0.
Mbra al t liatdehlyma
I wonder
!e ```python
a=lambda x,y=[]:(y:=list(x),(y[::2],y[1::2]:=x[::2],x[1::2][::-1]),''.join(y))[2]
print(a("Mary had a little lamb"))
@distant wave Your eval job has completed with return code 1.
001 | File "<string>", line 1
002 | a=lambda x,y=[]:(y:=list(x),(y[::2],y[1::2]:=x[::2],x[1::2][::-1]),''.join(y))[2]
003 | ^
004 | SyntaxError: invalid syntax
I'll try to get on that soon
But touching the ci monstrosity I wrote gives me a headache
Open an issue and get someone else to do it :P
It's snekbox rite?
The ci is a little broken, sort of not really
So I wanna fix it
But want to perhaps redo it...
I wanna watch, it sounds fun
Yeah its senkbox
Tbh you could upgrade and it will probably all work
I don't think there's a need to revamp the in conjunction
Can be done separately
Just discovered that {'a', 'b'}.pop() randomly picks 'a' or 'b'
But it doesn't work with ints for some reason
Does it work with large ints?
Like 25000
Hm, that's not very large
I guess it's just that ints have constant hash values.
>>> {'a','b'}.pop()
'b'
>>> {'a','b'}.pop()
'b'
>>> {'a','b'}.pop()
'b'
>>> {'a','b'}.pop()
'b'
>>> {'a','b'}.pop()
'b'
>>> {'a','b'}.pop()
'b'
>>> {'a','b'}.pop()
'b'
>>> {'a','b'}.pop()
'b'
>>> {'a','b'}.pop()
'b'
>>> ``` @gilded orchid seems to be fixed in 3.8
was prob a bug with how sets handle .pop
Yeah, since sets are meant to be unordered, but pop pops the last item
Even if you restart the interpreter?
(though the warnings are annoying)
alias python3="python3 -W ignore"
wow
lmao
@rugged sparrow
alias python3="python3 -W ignore"
Shouldn't it make it infinitely recursive?..
Oh yeah
Or does it only allow one level?
Honestly idk. I have mine set to alias python
Not python3
It only allows one level
Just tested
smart lol
probably
class hm:
def __matmul__(self, other):
print('why')
sent, everyone = hm(), hm()
sent @everyone```
Before 3.8, I think sets were meant to pop in orders based on hash values. Strings have nondeterministic hashes.
Afterwards, they probably put the and dicts in line with each other.
did you know you can do "enhanced" expansion in loops
for (arg, (param_type, _)) in zip(args, self.sig_map):
where sig_map is a list of tuples
According to the reference, it's the same gammar type as regular assignments, so you can use anything you could there:
for [obj.attribute(blah)[45], *rest] in myiter:
Can you do that with parameters?
function parameters?
Looks like you can't do this: ```python
def foo(a, (b, c)):
File "<stdin>", line 1
def foo(a, (b, c)):
^
SyntaxError: invalid syntax```
It's a little inconsistent with other forms of assignment, but I understand the reasons.
It's for introspection, from memory.
Python 2 allowed unpacking there, it was removed in Python 3 (since it means signatures are really weird).
And that code snippet would run, if you have an obj with the method defined.
ooOOOoo
Feast your eyes
!e ```python
print((lambda x, y=[]:[y.clear(), y.extend(x), list(None for y[::2], y[1::2] in [(x[::2].lower(), x[1::2].upper())]), ''.join(y)][-1])("Mary had a little lamb"))
@distant wave Your eval job has completed with return code 0.
mArY HaD A LiTtLe lAmB
Needs more brackets
weirdCase = lambda s:''.join(map(lambda c:''.join(c[0].lower()+c[1].upper()),zip(s[::2],s[1::2])))
print(lambda x,y=[]:[y.clear(),y.extend(x),[0 for y[::2],y[1::2] in [(x[::2].lower(),x[1::2].upper())]],''.join(y)][-1])("Mary had a little lamb"))
!e ```python
sarcasm = lambda p: sum(map(lambda c:c[0]+c[1],zip(p[::2].upper(),p[1::2].lower())),'')
print(sarcasm("who's fleece was white as snow"))
@distant wave Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 2, in <module>
003 | File "<string>", line 1, in <lambda>
004 | TypeError: sum() can't sum strings [use ''.join(seq) instead]
-.-
!e ```py
(lambda s,a=(str.lower,str.upper):''.join(map(lambda p:ap[0]%2,enumerate(s))))("Mary had a little lamb and its code was shorter than all the others")
Sorry, but you may only use this command within #bot-commands.
weirdCase = lambda s:''.join(map(''.join,zip(s[::2].lower(),s[1::2].upper())))
lambda s,t=''.join:t(map(t,zip(s[::2].lower(),s[1::2].upper())))
Lemme get to an actual computer and ill try to golf more
from functools import reduce
print(reduce(lambda x, y: x.swapcase()+y,"mary had a little lamb"))
what've i done
>>> Settings.set_command
<bound method ? of <class 'pyskell.repl.commands.Settings'>>
how does this hapen
mixing classmethod and custom decorators
what have i done..
def settings_classmethod_hack(func):
func_signature = inspect.signature(func)
def inner_hack(*args):
return func(Settings, *args)
inner_hack.__signature__ = func_signature
return inner_hack
class Settings:
settings = {}
@classmethod
@CommandHandler.command(name="set")
@settings_classmethod_hack
def set_command(cls, opt: str, val: bool):
print(cls)
cls.settings[opt] = val
print(cls.settings)
and it works
print(*map(lambda a:(str.upper, str.lower)[a[0]&1](a[1]), enumerate("Mary had a little lamb.")),sep="")
really tried to find a way to unpack this tuple without using partial
@pure dew isn't that what functools.wraps is for?
Not sure if it clones the signature, but it does do name and docs
!e ```python
from functools import wraps
def d(a):
@wraps(a)
def b(*args):
return a(*args)
return b
@d
def test(a=1, b=2): pass
print(test.signature)
still have that horrid return func(Settings, *args) tho
Also not handling kwargs
s='Mary had a little lamb.';print(*map(lambda s:''.join(s), zip(s[::2].upper(),s[1::2].lower())),sep='')```
Hmm, shorter, but rip on odd length
its a command dispatcher for a repl
I feel like args.insert(0, Settings) makes more sense
but if it's a tuple that doesn't work
Honestly what you've got seems fine
all that seems like extra work tbh
this is another command
@CommandHandler.command(name="quit")
def quit_command():
print(paint("\nExiting..", "red"))
exit()
that earlier one only needs the classmethod decorator because its a classmethod and my decorator doesn't play nicely with that
Here's mine, which is probably ugly as sin and indev
if event in EVENT_MAPPING:
if EVENT_MAPPING[event] == "bot":
preargs = (self.bot,)
elif EVENT_MAPPING[event] == "context":
# BAD BAD BAST
preargs = (models.Context(args[0], args[0].channel, args[0].channel.guild),)
else:
preargs = (self.bot,)
else:
preargs = (self.bot,)
[
asyncio.create_task(coroutine(*preargs, *args, **kwargs))
for coroutine in self.event_registry[event]
]
It's really not that bad, it's just async, and doing the same really
coroutine(*preargs, *args, **kwargs) is the same as your func(Settings, *args)
but thats only for commands inside the settings class
I just build preargs dynamically based on whether the handler is a command specific one or not
all the others are just result = command(*new_args)
I don't know whether to be proud or sad
I don't have any particularly nasty bits of code in here
yet
its mostly clean
I did make a discovery tho
if source[0] == ":":
name, *args = source[1:].split()
print(handler.dispatch(name, *args))
``` this is allowable syntax, and actually works
yeah, it's pretty nice
@formal sandal Here's my syntax demo so far for the pyskell "compiler"
class ListManipulation:
getFourth : str.str
getFourth(s) | s @ 3
head : list(a).a
head(a, *_) | a
tail : list(a).list(a)
tail(_, *tail) | tail
equivalent haskell code:
module ListManipulation where
getFourth :: [Char] -> [Char]
getFourth s = s !! 3
head :: [a] -> a
head x:xs = x
tail :: [a] -> [a]
tail x:xs = xs
@grave rover do you prefer this or the monstrosity that was pycss?
and boom, this is a totally valid ast
class ListManipulation:
getFourth : str.str
getFourth(s) | s @ 3
head : list(a).a
head(a, *_) | a
tail : list(a).list(a)
tail(_, *tail) | tail
class Main(main):
from ListManipulation import getFourth, head
main : IO()
main | (arr := [0, 1, 2, 3, 4])
print, head, arr
print, getFourth, arr
more spam, but here's some custom ast progress https://paste.a-sketchy.site/nucagiwapo.py
This channels is too quiet for spam be a concern.
true
@pure dew is this just you redifining a buch of dunder methods or is there something really weird going on?
To make debugging easier, I wrote a little graphing function using pydot
Here's the result of graphing the ast from the code in the paste: https://paste.a-sketchy.site/nucagiwapo.py
because i can, ya know
Somebody stop me before I go too far
test : Dict(Char, List(Pair(_, b))).Char.Int.b
if res[1] and res[4].startswith(res[5][0]) and not res[6]:
new_current.append((res[0], res[1], res[2], res[5][0], res[4][len(res[5][0]):], [], res[5][0]))``` is this code esoteric or just bad?
Oi! Helpful advice belongs in other channels.
This is the channel for golfing code until it's unreadable, but maybe that code is leaning too heavily on the 'unreadable' side.
b=bool
nc += [r.m,r.t,r.x,r.s.l,r.i[r.s.l.l:],[],r.s.l] if b(r.t)&b(r.sw(r.s.l))&~b(r.v) else []
b=bool
nc += ([r.m,r.t,r.x,r.s.l,r.i[r.s.l.l:],[],r.s.l],[])[b(r.t)&b(r.sw(r.s.l))&~b(r.v)]
Hm, it's missing something
b=bool
# do not touch
nc += ([r.m,r.t,r.x,r.s.l,r.i[r.s.l.l:],[],r.s.l],[])[b(r.t)&b(r.sw(r.s.l))&~b(r.v)]
There
!e ```python
nc = []
nc += []
print(nc)
b = bool
print((1, 2)[b(1)&b(0)])
@distant wave :white_check_mark: Your eval job has completed with return code 0.
001 | []
002 | 1
b=bool
# do not touch
m,t,x,s,i,v=*r.it()
nc+=([m,t,x,s.l,i[s.l.l:],[],s.l],[])[b(t)&b(r.sw(s.l))&~b(v)]
a.e.s.t.h.e.t.i.c
yeah fuck it lets go: longest code to print "hello"
most meaningful lines
alpha = range(255)
count = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
alpha_dict = {}
alpha_list = []
for letter, count in zip(alpha, count):
alpha_dict[letter] = count
for letter, count in alpha_dict.items():
if count:
alpha_list.append(chr(letter) * count)
print("".join(alpha_list))```
@plucky bane that'll be £200k please.
okay, £98k if we ignore pep8
Nice
Sorry I broke my cheque
@wide cypress thats horrific
thank you, thank you.
lol
>>> @new_method(int)
... @property
... def length(self):
... return len(str(self))
...
>>> a = 13
>>> a.length
2
>>> a = 241
>>> a.length
3``` haha, seems fun
cool decorator
It takes a while to overwrite with a property though, which is weird
Using the new GC method though
new gc method? 👀
@grave rover I assume he means the method of getting a classes dictionary using the garbage collector instead of ctypes
😮 i heard ppl golf here
me and a few others have been golfing a q from my exam a few days, where we had to convert a string of length n even >= 16 to a string such that the the first n/2 - 5 characters are flipped, the next 10 characters are flipped, and then the last n/2 - 5 characters are flipped
our current best is 54 characters
e=lambda a:(a[(x:=len(a)//2+5):]+a[-x:x]+a[:-x])[::-1]
e=lambda a:(a+a[(x:=len(a)//2-5):-x]+a[:x])[:x+9:-1]
e=lambda a:(a+a[-(x:=len(a)//2+5):x]+a)[~x:x-1:-1]
Yeah I meant the method which uses garbage collector to get the class.__dict__ which I can edit. It is slower than ctypes' one, but in theory works on more python implementations
Gotta install some python implementations to test tho
oh nice job @vestal solstice
50 chars
we're also doing the same for other algorithm in the paper, where we had to convert a 2 x n array of players and scores to an a x 11 array, where the initial 2 x n array is structured as follows:
Player Score
123456 12345
123456 13452
112345 12331
...
and the finally array had to list at most 10 scores achieved by the same player
123456 12345 13452 ...
112345 12331 ...
...
The initial input is just a list of tuples
[(123456, 12345), (123456, 13452), (112345, 12331), ...]
and our output is just larger tuples.
Currently, our best golfed solution is
s=lambda a:[*{(i,)+(*(r for j,r in a if i==j),)[:10]for i,_ in a}]
so you are matching scores to players?
yes
the question never specified either so we just went with any 10
k
like, some players may still score less than 10 times
yeah no more than 10
[(123456, 12345), (123456, 13452), (112345, 12331), (3, 2), (3, 4), (3, 1), (3, 2), (3, 123), (3, 213), (3, 123), (3, 1212), (3, 124321), (3, 12), (3, 212)]
thx
any 10 of the 11 scores by player 3 could be in it
and the output should be in order?
nope
the q in the exam itself was to do it in pseudocode (classic high school exams)
yours outputs this:
[(123456, 12345), (123456, 13452), (112345, 12331)]
so i dont need to know what scores belong to what player?
oh wait
uh, idt thats the output?
hmm for me it just outputs the same as the input
[(797, 53), (797, 86), (204, 82), (204, 54), (204, 62), (204, 87), (204, 90), (204, 19), (313, 96), (313, 71), (313, 74), (313, 66), (313, 89), (313, 33), (313, 57), (313, 37), (313, 66), (313, 100), (313, 68), (313, 82), (313, 46), (313, 30), (553, 49), (553, 49), (553, 28), (553, 47), (553, 33), (553, 39), (553, 83), (553, 23), (553, 92), (553, 34), (553, 94), (553, 69), (553, 50), (553, 70), (553, 85), (469, 28), (469, 76), (469, 86), (469, 45), (469, 88), (469, 70), (469, 52), (469, 58), (469, 51), (469, 83), (634, 70), (634, 39), (634, 80), (634, 58), (634, 34), (634, 19), (634, 59), (634, 20), (133, 49), (133, 55), (133, 83), (133, 98), (133, 68), (133, 90), (133, 66), (133, 89), (133, 12), (133, 97), (133, 11), (133, 31), (133, 64), (756, 89), (756, 64), (756, 42), (756, 84), (880, 35), (880, 75), (880, 28), (880, 73), (382, 93), (382, 61), (382, 77), (382, 49), (382, 11), (382, 34), (382, 48), (382, 69), (382, 77), (382, 33), (382, 17), (382, 19), (382, 72), (382, 87), (828, 35), (828, 72), (828, 99), (828, 17), (828, 12), (828, 54), (828, 75), (828, 78), (828, 26), (828, 82), (143, 33), (969, 25), (730, 75), (730, 75), (730, 73), (730, 58), (730, 76), (591, 100), (591, 92), (591, 65), (591, 21), (591, 20), (591, 21), (591, 71), (591, 91), (591, 29), (591, 43), (591, 32), (591, 95), (591, 96), (273, 49), (101, 55), (293, 62), (293, 17), (293, 40), (293, 97), (885, 38), (885, 21), (885, 32), (885, 63), (885, 19), (885, 34), (885, 99), (461, 94), (461, 65), (461, 10), (461, 13), (461, 30), (461, 48), (461, 66), (461, 85), (461, 19), (461, 25), (461, 99), (461, 13)]
inp = [(123456, 12345), (123456, 13452), (112345, 12331)]
s(inp)
[(112345, 12331), (123456, 12345, 13452)]```
thats a randomly generated series of (player, score) tuples
i got
[(880, 35, 75, 28, 73), (133, 49, 55, 83, 98, 68, 90, 66, 89, 12, 97), (469, 28, 76, 86, 45, 88, 70, 52, 58, 51, 83), (969, 25), (730, 75, 75, 73, 58, 76), (313, 96, 71, 74, 66, 89, 33, 57, 37, 66, 100), (756, 89, 64, 42, 84), (461, 94, 65, 10, 13, 30, 48, 66, 85, 19, 25), (382, 93, 61, 77, 49, 11, 34, 48, 69, 77, 33), (553, 49, 49, 28, 47, 33, 39, 83, 23, 92, 34), (273, 49), (634, 70, 39, 80, 58, 34, 19, 59, 20), (591, 100, 92, 65, 21, 20, 21, 71, 91, 29, 43), (204, 82, 54, 62, 87, 90, 19), (828, 35, 72, 99, 17, 12, 54, 75, 78, 26, 82), (797, 53, 86), (293, 62, 17, 40, 97), (143, 33), (101, 55), (885, 38, 21, 32, 63, 19, 34, 99)]
as output
you can unpack instead of concatenating tuples```py
s=lambda a:[{(i,[r for j,r in a if i==j][:10])for i,_ in a}]
saves 4
lol, thats 3 ppl who've found it independently now
wait no
thats slightly different
s=lambda a:[*{(i,*(r for j,r in a if i==j))[:11]for i,_ in a}]
!e ```python
from typing import List
oracle_none = object()
def oracle(path: str) -> str:
return ".".join(_oracle(path))
def _oracle_iterrepr(obj: iter) -> str:
MAX = 40
res = ""
for item in obj:
n = repr(item)
if len(res + n) > MAX:
res += ", ..."
break
if res:
res += ", "
res += n
if not res:
res = "empty"
return res
def _oracle_repr(obj: object) -> str:
if isinstance(obj, dict):
return f"{{{_oracle_iterrepr(obj.keys())}}}"
if isinstance(obj, list):
return f"[{_oracle_iterrepr(obj)}]"
return repr(obj)
def _oracle(path: str) -> List[str]:
path = path.split(".")
res = []
parent = globals()
for item in path:
next_parent = getattr(parent, item, oracle_none)
if next_parent is not oracle_none:
parent = next_parent
res.append(_oracle_repr(parent))
continue
try:
parent = parent[item]
except KeyError:
return res + [f"(Not Found: {item})"]
except TypeError:
try:
parent = parent[int(item)]
except (ValueError, IndexError):
return res + [f"(Not Found: {item})"]
res.append(_oracle_repr(parent))
return res
testlist = []
testlist2 = [1, 2, 3, "a", "b", oracle]
print(oracle("oracle.globals.testlist2.-1.globals.testlist.0"))
@distant wave :white_check_mark: Your eval job has completed with return code 0.
<function oracle at 0x7f42321b5830>.{'__name__', '__doc__', '__package__', ...}.[1, 2, 3, 'a', 'b', ...].<function oracle at 0x7f42321b5830>.{'__name__', '__doc__', '__package__', ...}.[empty].(Not Found: 0)
@distant wave i did some more benchmarks and this seems to be very slightly faster than the other resolve:
@lru_cache(128)
def compiled(code):
return compile(code, '<cached>', 'eval', optimize=2)
def resolve(name):
return eval(compiled(name))
odd
plus the added benefit of automatically resolving attributes
oh wow, changing that eval call to eval(compiled(name), globals()) actually makes it faster too
not sure why
guess there's a check that gets bypassed if globals param isnt None
In [26]: f = lambda:lambda x:x
In [27]: a = defaultdict(f)
In [28]: a[1]
Out[28]: <function __main__.<lambda>.<locals>.<lambda>(x)>
i feel like this is useful for something
continuing from the messages between
https://discordapp.com/channels/267624335836053506/303906556754395136/638073584157327391
and
https://discordapp.com/channels/267624335836053506/303906556754395136/638080360260829205
what exactly does LOAD_CLOSURE do to cause this behaviour?
bytecode gurus hear my call
>>> def test():
... x = []
... def inner():
... x.append(1)
... return x
... return inner
...
>>> something = test()
>>> something()
[1]
>>> something()
[1, 1]
>>> something()
[1, 1, 1]
>>> something.__closure__
(<cell at 0x000002077C84E708: list object at 0x000002077C9D24C8>,)
>>> something.__closure__[0]
<cell at 0x000002077C84E708: list object at 0x000002077C9D24C8>
>>> something.__closure__[0].cell_contents
[1, 1, 1]
>>> something.__closure__[0].cell_contents.append(4)
>>> something()
[1, 1, 1, 4, 1]```
@brazen geyser it seems to be something to do with __closure__
right, according to the docs
MAKE_FUNCTION(argc)¶
Pushes a new function object on the stack. From bottom to top, the consumed stack must consist of values if the argument carries a specified flag value
0x01 a tuple of default values for positional-only and positional-or-keyword parameters in positional order
0x02 a dictionary of keyword-only parameters’ default values
0x04 an annotation dictionary
0x08 a tuple containing cells for free variables, making a closure
the code associated with the function (at TOS1)
the qualified name of the function (at TOS)
and the MAKE_FUNCTION for wrapped has 0x08 passed as its argument so ye
so then the question becomes wtf is a closure in this context
ive heard of the term used to refer to anonymous functions but nothing quite like this
Doesn't the closure just allow inner to store the value of x even though it's outside the function?
yeah something like that
usually x would be deleted after test finished, but inner keeps a reference to it and there's a reference to inner so it gets kept
and it's in the closure
okay now it's making sense.
though id still like to see an exact definition of what cell and closure mean
closure is just a fancy term for upvalue capture in this context i think
A cell is an object with a reference contained in it. Used exclusively for function closures iirc
You don't need a box in a dynamically typed language.
Although honesty I don't know why you need a cell.
so it's like a temporary storage location for a reference used during compilation?
storage location with an index
Not temporary, it's used when the function runs, I think.
Not certain of that, actually.
!e
import re
re.compile(r"\bHello[0-9]+\s+world(?=123)", re.DEBUG)
@formal sandal :white_check_mark: Your eval job has completed with return code 0.
001 | AT AT_BOUNDARY
002 | LITERAL 72
003 | LITERAL 101
004 | LITERAL 108
005 | LITERAL 108
006 | LITERAL 111
007 | MAX_REPEAT 1 MAXREPEAT
008 | IN
009 | RANGE (48, 57)
010 | MAX_REPEAT 1 MAXREPEAT
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/ozukojuyar
def load_cls_dict(cls):
"""Gets 'cls.__dict__' that can be edited."""
for obj in gc.get_objects():
try:
if obj == dict(cls.__dict__) and type(obj) is dict:
return obj
except:
continue
raise ValueError(
'Failed to find editable __dict__ for {}.'.format(cls)
)
def get_class_dict(cls):
"""Slower than load_cls_dict. Used to prevent cls.__dict__ copy trick."""
maybe_actual = load_cls_dict(cls)
maybe_actual[13] = 13
actual = load_cls_dict(cls)
actual.pop(13, None)
return actual``` Ok here are the versions I am using, feel free to golf and other stuff
Maybe except: instead of except Exception:?
Not sure if it is possible to get BaseException direct subclass, haha
But ok, let's have it
is it possible that dict doesn't return a dict?
Oh, no, lemme explain
class tricker:
def __eq__(self, other):
return True
trick = tricker()```
@formal sandal here
oh
is it possible to make a function run with a specific globals and locals dict?
without exec
eval?
@brazen geyser both eval and exec take globals and locals arguments
without exec or eval
>>> import inspect
>>> inspect.currentframe().f_locals = {}
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
inspect.currentframe().f_locals = {}
AttributeError: attribute 'f_locals' of 'frame' objects is not writable
>>>
rip
alternatively, can you make name resolution in a dynamically created module work like it would in an ordinary module?
e.g. imagine you had this file: module.py
class A:
pass
def new_a():
return A()
doing this in another file would be no problem:
import module
a = module.new_a()
v.s. using a dynamically generated module
import sys
from types import ModuleType
module = ModuleType('module')
sys.modules['module'] = module
class A:
pass
def new_a():
return A()
module.A = A
module.new_a = new_a
del new_a
del A
a = module.new_a()
which results in the following error:
Traceback (most recent call last):
File "C:/Users/admin/Documents/Projects/shm_server/scrap.py", line 19, in <module>
a = module.new_a()
File "C:/Users/admin/Documents/Projects/shm_server/scrap.py", line 11, in new_a
return A()
NameError: name 'A' is not defined
im guessing it involves making a spec first then using importlib to create the module based on the spec instead
Repost from python-discussion, but I'm especially proud of this, and it is pretty much just esoteric python https://paste.a-sketchy.site/mujopepuye.py
File imports work
That file doesn't actually run, right?
It doesn't start with an 'import PyskellParser' or anything, so it'll error on include being an undefined identifier.
uh no
you still have to python -m pyskell pyskell/examples/import.py
I'll make an import based entry point after a while
@pure dew actually, imports dont work like that in C
yea I know
#import "..." just searches local first, then global, and the other way around for <>
Actually, this works in HTML (at least in firefox):
<b> aaaaaaaaaaa <i> bbbbbbbbbbb </b> ccccccccccc </i>
Despite the fact that you can't really turn it into a nested structure.
So firefox transforms that HTML:
Maybe it's possible to do this in programming as well?
fizzbuzz(n) =
from [ ( n%3==0 { ) n%5==0 } ]
mapto [ n ( "Fizz" { "FizzBuzz" ) "Buzz" } ]
See, it's like a Venn diagram.
There are two circles, "divisible by 3" and "divisible by 5". Everything outside the circles will result in n being return, the intersection will give "FizzBuzz" and so on.
Insertion sort:
isort list =
let m = min list
split [(== m) ]
apply [( id ) isort ]
as [( a ) b ]
return a ++ b
And, of course,
qsort x:xs =
split [( < x ) ( > x )]
apply [(qsort) id (qsort)]
as [( lt ) eq ( gt )]
return lt ++ eq ++ gt
A bit verbose, but
binsearch list x =
if list == []
return Nothing
else
let mid = list.middle
if mid == x
return Just x
list
split [(< mid) (> mid)]
as [( lt ) ( gt )]
elif mid < x
return (binsearch gt x)
elif mid > x
return (binsearch lt x)
else
impossible
The idea is that you can intertwine not only data structures, but control flow.
This might be useful if you have something like:
if green:
color = CO_GREEN
GreenManagerSingleton.Initialize()
else:
print(123)
robot.abort_exhumation()
if green:
color = CO_RED
GreenManagerSingleton.deinitialize()
return 0
else:
return 1
```where the control flow is "interrupted" by some common action.
Check whether a user (if the username and password are correct) is an admin:
check_adminness uname pwd =
from [(uname in UNAMES {match uname pwd}) ]
mapto [(Error "pwd" { User uname }) Error "uname"]
apply [( id { isadmin }) id ]
this isn't right, but it's a start --- it should check for complete containment and probably other things too:
from itertools import combinations
class Venn:
opens = "<({"
closes = ">)}"
def __init__(self, venn_string):
self.venn_string = venn_string
def __repr__(self):
sets = [(character,index)
for index, character in enumerate(self.venn_string)
if character not in self.opens + self.closes]
closures = [(index, self.venn_string.find(self.closes[self.opens.find(character)], index))
for index, character in enumerate(self.venn_string)
if character in self.opens]
for (s1, e1), (s2, e2) in sorted([*combinations(closures, 2)]):
if e1 > s2:
if (s1, e1) in closures:
closures.remove((s1, e1))
closures.extend([(s1, s2), (s1, e2)])
closures.sort()
return ", ".join("&".join(set_ for set_, index in sets if start < index < end)
for start, end in closures)
"""
Venn("<a(b>)") -> a, a&b, b
"""

Actually... I don't know how to specify a three-circle Venn diagram.
Like A, B, C, A&B\C, A&C\B, B&C\A, A&B&C.
yeah, i tried it with 3 and got:
In [159]: print(Venn("<a(b{c)}>"))
a, a&b, a&b&c, a&b&c, b, b&c, c
which isn't right
well, b & c are completely contained in a
Well,
< a ( b { c ) } >
< a a&b\c a&b&c a&c\b
I don't think you can communicate this picture in 1D:
Oh, wait
< a ( b { c > ) }
< a ( a&b\c {a&b&c > b&c\a) c }
But you still can't split it into 7 distinct cases.
I just peeked over here and I'm very confused and scared from these symbols you're throwing here 😄
Maybe it will become more clear if you scroll up to the
fizzbuzz(n) =
from [ ( n%3==0 { ) n%5==0 } ]
mapto [ n ( "Fizz" { "FizzBuzz" ) "Buzz" } ]
```message
They are doing some voodoo invocations @edgy kelp no worries
Actually I'm just procrastinating because I have to do a huge homework task.
automate it
I can't...
That's a physics assignment, and while I can automate the computation, I will still have to write all the steps on a piece of paper
Automate the printing
I would have to buy a plotter since i can't print it.
Automate the buying
I love doing physics calculations with python
<a{b(c>})
i think this is as close as you can get, it doesn't include a&c by themselves
Especially if im not quite getting them, teaching a computer just does it for me
is there any a&b without c
you could do non contiguous sets
a { b ( c > } < )
a ab\c abc bc\a c\(a|b) ac\b
Actually, the correct way to write this would be {b(c>}<a)
this is a tiny one-dimensional torus
boring mode on Maybe <a{b(c>}){b\(a|c)}?
class Venn:
opens = "<({"
closes = ">)}"
def __init__(self, venn_string):
self.venn_string = venn_string
def __repr__(self):
sets = [character for character in self.venn_string
if character not in self.opens + self.closes]
closures = [(index, self.venn_string.find(self.closes[self.opens.find(character)], index))
for index, character in enumerate(self.venn_string)
if character in self.opens]
closure_set = {set_:set(range(start, end+1)) for (start, end), set_ in zip(closures, sets)}
return str(closure_set)
"""
In [170]: print(Venn("<a(b{c>)}"))
{'a': {0, 1, 2, 3, 4, 5, 6}, 'b': {2, 3, 4, 5, 6, 7}, 'c': {4, 5, 6, 7, 8}}
"""
just comparing relations between these sets of numbers would get a lot of the way
but these sets don't have to be contiguous, if you find a nice way to break them up
hmm, you could instead not use the brackets and braces and just use the first appearance of a set symbol to open and a 2nd to close
a b c a b c
| | | | | |
a | | | | |
a&b| | | |
a&b&c | |
b&c| |
c |
∅
seems easier to parse
then you could do:
abcabcaccabb
i think gets all the combinations?
class Venn:
def __init__(self, venn_string):
self.venn_string = venn_string
def __repr__(self):
relations = set()
s = ""
for symbol in self.venn_string:
if symbol in s:
s = "".join(char for char in s if char != symbol)
else:
s += symbol
relations.add("&".join(s))
return ", ".join(relations)
In [177]: print(Venn("abcabc"))
c, , a&b, a, a&b&c, b&c
In [178]: print(Venn("abcabcaccabb"))
c, , a&b, a&c, a, b, a&b&c, b&c
hmm, it uses an empty string for the empty set
i guess that makes sense
class substring(str):
def __sub__(self, other):
return substring("".join(char for char in self if char not in other))
def __add__(self, other):
return substring("".join((self, other)))
class Venn:
def __init__(self, venn_string):
self.venn_string = venn_string
def __repr__(self):
relations = set()
s = substring("")
for symbol in self.venn_string:
s = s - symbol if symbol in s else s + symbol
relations.add("&".join(s) if s else "∅")
return ", ".join(relations)
now we got a nice symbol -- looks nicer if i can subtract with strings
i was able to get all combinations with this string:
In [199]: Venn("abcbabcb")
Out[199]: c, a&b, a&c, a, b, ∅, c&b, a&b&c
It might be cleaner to subclass frozenset
i used a set instead, but it's awkward cause sets dont have __add__
class Venn:
def __init__(self, venn):
self.__make__(venn)
def __make__(self, venn):
relations = set()
s = set()
for symbol in venn:
(set.remove if symbol in s else set.add)(s, symbol)
relations.add("&".join(s) if s else "∅")
self.__rep__ = ", ".join(relations)
def __repr__(self):
return self.__rep__
i mean, instead of subclassing anything
it seems odd that __add__ isn't used for union and __iadd__ isn't update
maybe there's some ambiguity somewhere
It would get confusing with .add, for one.
maybe, but i wouldn't ever call the dunder method with .__add__
If you're subclassing it, it'd come up.
fair
Well, I don't think this will be very useful with conditions. You'd need to make sure they don't overlap and write all the individual cases.
in 3.8 globals().clear() doesnt wipe globals
however it will remove variables created by the script
it basically resets globals instead of clearing it
__builtins__.clear() still breaks everything tho
>>> __name__
'__main__'
>>> globals().clear()
>>> __name__
'builtins'``` (3.8)
lol
how does that happen
>>> globals().clear()
>>> globals()['__builtins__'].clear()
=============================== RESTART: Shell ===============================
>>>
nice
oh right that should be __builtins__.__dict__.clear()
>>> globals().keys()
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__'])
>>> type(__builtins__)
<class 'module'>
>>> globals().clear()
>>> globals().keys()
dict_keys(['__builtins__'])
>>> type(__builtins__)
<class 'dict'>```
it gets cleared, then __builtins__ gets put back as a dictionary
nothing else gets put back
so __name__ goes to __builtins__ and you get 'builtins' ```py
builtins['name']
'builtins'```
thats.. weird. to say the least.
maybe you shouldn't have done globals().clear() then? :P
this is #esoteric-python, everything is weird
it gets cleared, then __builtins__ gets put back as a dictionary why does this happen in particular lmao
well putting it back is probably so that you don't do something silly like del __builtins__ and mess everything up
we have no idea why it becomes a dictionary though
It probably needs to be reconstructed, and dicts are easier.
>>> globals().clear()
>>> import builtins
>>> builtins
<module 'builtins' (built-in)>```
Does it reimport the module, or is that just assignment?
we don't know what you're asking but does this answer your question? ```py
globals().clear()
import sys
sys.modules['builtins']
<module 'builtins' (built-in)>```
Yep.
👀
!e ```python
import sys
builtins.dict.clear()
sys.modules.clear()
import builtins
builtins.print(sys.modules)
@distant wave :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 4, in <module>
003 | ImportError: __import__ not found
I wonder if that's even recoverable
@distant wave if object and True and False exist then its recoverable
Oh no
They dont
I thought we figured out it was recoverable
If you already had an object remaining, likely
!e ```python
import sys
builtins.dict.clear()
sys.modules.clear()
sys.dict
@distant wave :warning: Your eval job has completed with return code 0.
[No output]
!e ```python
import sys
builtins.dict.clear()
sys.modules.clear()
sys.dict.class.globals
@distant wave :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 4, in <module>
003 | AttributeError: type object 'dict' has no attribute '__globals__'
!e ```python
import sys
builtins.dict.clear()
sys.modules.clear()
sys.dict['stdout'].write(sys.dict.class.mro)
@distant wave :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 4, in <module>
003 | TypeError: write() argument must be str, not tuple
!e ```python
import sys
builtins.dict.clear()
sys.modules.clear()
sys.dict['stdout'].write(sys.dict.class.mro.str())
@distant wave :white_check_mark: Your eval job has completed with return code 0.
(<class 'dict'>, <class 'object'>)
Looks recoverable
!e ```python
import sys
builtins.dict.clear()
sys.stdout.write(sys.dict"globals".str())
@distant wave :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 3, in <module>
003 | KeyError: 'globals'
!e ```python
import sys
builtins.dict.clear()
sys.modules.clear()
sys.stdout.write(sys.dict"import".str())
@distant wave :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 4, in <module>
003 | KeyError: '__import__'
It is recoverable even if you don't have sys. Just takes some effort
Cause you still have integer literals
How do you get to importing from integer literals?
I mean, we can get to object and maybe traverse the subclasses tree maybe?
Yea you use the subclasses tree
(1).
!e ```python
import sys
builtins.dict.clear()
sys.modules.clear()
(1).class.mro[-1].subclasses = 1
@distant wave :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 4, in <module>
003 | TypeError: can't set attributes of built-in/extension type 'object'
Also (1).__class__.__base__ == object
!e ```python
print((1).class.mro)
@distant wave :white_check_mark: Your eval job has completed with return code 0.
(<class 'int'>, <class 'object'>)
You'd need to ctypes object to break it further imo
You don't need the 1, the brackets suffice
Admins should create #ctypes-abuse since this is only related to CPython implementation, and not fully belongs to esoteric-python >.>
nah, ctypes fuckery still falls under weird things to do with python, it doesn't matter if its only for one implementation :D
I think that was sarcasm
And yes and no
Maybe we should just have 8 or so different eso channels.
#eso-languages
#eso-ctypes
#eso-obfuscation
#eso-golfing
...
That wouldn't make any sense, though, because this channel is not that popular.
I'd definitely join the esoteric-python discord instance, just sayin'
Idea: could we start weekly or monthly #esoteric-python golfing competitions
maybe there could be a simple task and whoever is able to golf it the best wins I guess
Wasn't there already a competition each week/month that died out?
i mean, the esoteric python challenges aren't strictly about golfing, but there's no reason why people can't submit golfed solutions or work with others to golf it together.
also, i'm trying not to let it die out but interesting ideas are difficult to come up with and i don't have the time forget to spend time every couple weeks or so trying to think of a new challenge.
no one told me this was a thing : for i in range(10):{print(i)}
what are the braces for?
the braces do nothing really, except make it look slightly like a language that uses braces
technically the braces are just syntax for creating sets
from __future__ import braces
^
SyntaxError: not a chance

pretty funny easter egg
I created a Context Manager with the power of a decorator
It's a class
You just subclass it, and implement a extend method (you can also do an __init__)
It converts everything in the context manager to a function
And it also blocks the natural call of the Context Manager
So you can implement your own custom calls for the context manager
With a context manager like this:
class iterate(ContextManager):
def __init__(self, name, iterable):
self.name = name
self.iterable = iterable
def extend(self, func, glob, loc):
for item in self.iterable:
loc[self.name] = item
func()```
You can now do
with iterate('x', range(3)):
print(x)
>>> 0
>>> 1
>>> 2```
If anyone finds it useful, I'll publish it
I would be interested, although my interest is academic rather than practical. I tried to do something similar, and decided it was impossible.
how do you bring the variables to the scope tho? Is it some magical stack-hack or something simple that I am not seeing?
(lambda x:(lambda l: print('print(\'\'.join([*'+(''.join([*map(l,x)]))+']))'))(lambda x:f'(lambda x:chr(x))({ord(x)}),'))```
I just made this terrible thing for the string obfuscation challenge
I probably won't submit it though since it's a bit basic
mfw I had to write shitcode today
instead of calling main I had to call main.callback.__closure__[0].cell_contents
oh god why
I got a challenge for you guys at #esoteric-python (you always came up with crazy thing) can you make this to work? (with some C or something)
False, True = True, False```
oh, it is here lol
@thin trout you mean catch the syntaxError from assigning to a keyword or actually change the behavior
like make False evaluate to True after that
True is not even in globals(), haha
I think it's doable
Haha
First segfault of the challenge lol
this does seem to break everything because python uses those internally.
i just get a bunch of errors because something evaluates to False instead of True etc
what did you do to swap them?
some weird trikery overwriting the bool method
cant do that at all on the boolean type
but you can for ints.
and then everything breaks
>>> bool.__bool__
<slot wrapper '__bool__' of 'int' objects>``` hmm 🤔
yeah
bool is a subclass of int afterall
^

