#esoteric-python

1 messages · Page 85 of 1

acoustic zinc
#

unless I'm misunderstanding what you want from the dynamicdict

fiery hare
#

it creates the missing value based on the missing key

acoustic zinc
#

isn't the use case for that really small

#

and you'd be better off using setdefault probably?

fiery hare
#

what's that?

acoustic zinc
#

a function that no one knows about because of defaultdict

fiery hare
#

but the point is that the missing value is created dynamically based on what the missing key is.

#

this appears to return a constant.

acoustic zinc
#

can't you just do .setdefault(n, func(n)) or something

fiery hare
#

I don't find that as enjoyable to read as how the class I designed would look in action.

#

for the same reason that defaultdict exists.

acoustic zinc
#

enjoyable to read? sure. enjoyable to use? well with your dynamic dict, you need to import stuff, write a new class, and use that

#

it seems a bit contrived

fiery hare
#

that's why I want it to be integrated into the language.

acoustic zinc
#

who would ever actually use this though

fiery hare
#

I'm not sure that that's a fundamentally different question than asking why anyone would use defaultdict

#

it would be another streamlined solution for the handling of missing keys.

formal sandal
#

Is there anything in #esoteric-python that's deliberately easy to use or practical, though?

fiery hare
#

I only asked about it here because my initial comment was about my efforts to implement the class I want in the C code, and I didn't think that would be a popular topic in the general chat.

acoustic zinc
#

@formal sandal yeah but this guy wants it in the standard library

formal sandal
#

Can't you just use lru_cache or something?

acoustic zinc
#

well his class works

#

he just wants it in c so he can import it from collections

fiery hare
#

My implementation compiles, but then from collections import dynamicdict raises ImportError at runtime.

#

I don't know that I fully understand what brings C code into something that's usable in Python.

acoustic zinc
#

do import collections print(collections) just to check that it's pointing to the right version I guess

fiery hare
#

yes, it's the right version.

#

I'm running the repl for the python version in my cpython clone.

acoustic zinc
#

I still don't really get why you need it, but it's odd that that doesn't work

fiery hare
#

I was working on a project a few days ago and was surprised that defaultdict(lambda key: make_something(key)) isn't a thing.

#

which I guess shouldn't be too horribly surprising.

acoustic zinc
#

I mean d.setdefault(key, make_something(key)) is a thing

#

but ok

#

lol

#

also defaultdict(lambda key=None: make_something(key))

#

that is a thing

#

which works

#

oh nvm it isn't

#

well yeah of course it isn't, a lambda is just a function, and when you use a defaultdict you don't pass the key to the function

#

like if you do d = defaultdict(int), when you do d[5] you don't expect it to set it to int(5)

bitter iris
#

Hey @fiery hare sorry for delay, now looking at your code

#

there are some small things that come to my eye, but other then your code looks OK. I think you are missing to add dydict_type to module state which should be end of the module

fiery hare
#

@bitter iris oh, let me look at that

bitter iris
#

here

#

an example would be this

#
    defdict_type.tp_base = &PyDict_Type;
    if (PyType_Ready(&defdict_type) < 0)
        return NULL;
    Py_INCREF(&defdict_type);
    PyModule_AddObject(m, "defaultdict", (PyObject *)&defdict_type);
#

just replace defdict with your dydict

fiery hare
#

thanks! I'm recompiling it now.

#

huh, apparently my pure Python implementation doesn't actually save the value in the dict; it just returns it.

#

so that's a problem.

bitter iris
#

are you planning to propose this feature or adding for just for fun and exercise?

fiery hare
#

definitely for fun/exercise

#

I would write a PEP but I don't know if that would go over well.

bitter iris
#

this probably doesn't deserve a pep but there will be a hot dicussion around the idea because it is relatively big thing

fiery hare
#
>>> from collections import dynamicdict
>>> dynamicdict
<class 'collections.dynamicdict'>
>>> bob = dynamicdict(lambda x: x.upper())
>>> bob['hi']
Segmentation fault
#

idk what I expected.

zealous widget
#

oh, a defaultdict that uses single argument lambdas?

fiery hare
#

I think I know what line of C code is the problem though

#

@zealous widget that's the idea. so the missing value is created based on the new key.

zealous widget
#

dope

#

i could do a python version, which you probably already did

fiery hare
#

I did

#

defining the class in pure Python makes the runtime of import collections way way slower.

bitter iris
#

@fiery hare just throw it to gdb and find where it crashes

fiery hare
#

I'm pretty sure that's where it crashes because that was the line where I guessed.

#

oh I see

#

I initialized the tup as a PyObject pointer, but it only gets a value in that one if statement.

#

but I'm not sure if having NULL in place of the kwargs argument that it wants is correct.

bitter iris
#

yep

fiery hare
#

I'm also upset with myself that I made a commit in which I had a commented-out line.

#
Python 3.8.2+ (heads/3.8-dirty:55a0efb, Apr  9 2020, 15:01:06)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from collections import dynamicdict
>>> bob = dynamicdict(lambda x: x.upper())
>>> bob['hi']
'HI'
>>> bob['hello'] += ' world'
>>> bob['hello']
'HELLO world'
#

omg it worked

bitter iris
fiery hare
#

let's see if I can break it

zealous widget
#

was this your python version:

class DynamicDict(dict):
    def __init__(self, func, *args, **kwargs):
        self.func = func
        super().__init__(*args, **kwargs)

    def __getitem__(self, key):
        if key not in self:
            super().__setitem__(key, self.func(key))
        return super().__getitem__(key)
fiery hare
#

that's the idea, yes

zealous widget
#

i wonder if i can make it better with get

fiery hare
#

get?

zealous widget
#

no, that's not a good idea

#

i'm gonna keep this class around, i'll probably find a use for it somewhere

fiery hare
#

you won't have to if I demand that Guido and friends integrate it into the standard library.

#

though I don't anticipate that happening.

zealous widget
#

yeah, it seems similar enough to defaultdict that it wouldn't be too much effort to include it

#

could just allow defaultdict to accept single or no argument functions

#

well, that might get confusing if you pass int or something

fiery hare
#

yeah, I think they'd have to change how defaultdict is implemented.

zealous widget
#

maybe a kwarg for passing key to the function

#

or just separate classes is fine

fiery hare
#

I saw in the C code that presently, the C function that causes the factory method to be called in the Python code is hard coded to be an argument-less function call.

#

I wish I knew a better way to make the dynamicdict implementation less repetitive.

zealous widget
#

i know nothing about c internals

fiery hare
#

they're something.

#

I have to hop off but thanks @zealous widget @bitter iris @acoustic zinc

acoustic zinc
#

What are you using the dynamicdict for?

fiery hare
#

@rak1507#1964 you could use it for a lot of things.

#

oh looks like rak left the server.

#

oh he was banned.

sick hound
#

ok so

#

i might regret this

#

how can i compact this, while still being able to understand it

#

xD

#

actually nvm i redacted that

brazen geyser
#

iirc defaultdict has an overridable __missing__ magic method that you could use to implement this too @zealous widget @fiery hare

#

ah already mentioned

#

nevermind

#

didnt scroll up far enough

fiery hare
#

@brazen geyser the missing method doesn't cause the new key to be saved.

brazen geyser
#

you can implement it to do such

fiery hare
#

I guess

#

That runtime though

brazen geyser
#

speed vs portability

fiery hare
#

Portability?

brazen geyser
#

if someone wants to use your c implementation of dynamicdict theyll need either a c extension or your specific python build

#

whereas with a pure python approach there'll be no additional dependencies

#

i thought by 'that runtime though' you were referring to runtime overhead

#

which, yeah, pure python implementation will have a significant amount of compared to a c implementation

#

or did i misunderstand?

fiery hare
#

I don't think you did.

#

However I'm considering proposing that it get integrated into the standard library

brazen geyser
#

oh cool

#

personally i think it might make more sense as an addition to defaultdict, rather than a separate class

#

but not sure of what hidden performance gotchas there could be for that

#

do any stdlib modules use defaultdicts? that could probably be the number 1 case against a change to defaultdict

fiery hare
#

The c implementation of defaultdict doesn't let the factory method have parameters.

brazen geyser
#

the proposal would cover that presumably

fiery hare
#

So change defaultdict so that it supports both?

brazen geyser
#

maybe it could be a classmethod. defaultdict.fromcallable

#

yeah

#

at a glace it seems fairly redundant to make an entirely new class for this

fiery hare
#

Defaultdict always uses a callable

#

It just doesn't pass any arguments to it.

#

Yes, it's very repetivie.

#

Repetitive

#

Only a few lines are different

brazen geyser
#

right, so the classmethod would give you a specific type of defaultdict which does that

fiery hare
#

I'd have to see how you can implement a class method directly in C.

brazen geyser
#

defaultdict.keybased? better name?

fiery hare
#

I don't think that would change anything about how it gets implemented in C.

brazen geyser
#

to fix the repetitiveness issue you could probably like, swap in a function pointer somewhere to differentiate between normal and key base default dict behaviour. but... as im typing it out it's starting to seem like a worse and worse idea 😅

#

yes, i mean it might be more accurate than defaultdict.fromcallable for example

#

more descriptive

fiery hare
#

The important part in the C code is that apparently, the way C causes functions to be called in Python is that it passes the callable and the arguments to a C function

#

And the C function can't take any arguments other than the callable itself

fiery hare
#

@brazen geyser I changed the source code for defaultdict (rather than having the other class) so that you can have either behavior, but you still have to give it a callable that takes one argument, even if it doesn't use it

#

because otherwise if you supply a callable that can run with or without an argument, it can't know when you don't want it to pass that argument to the callable.

#

I don't think that would go over well.

#

basically it has to be a separate class or the new implementation of defaultdict wouldn't be backwards compatible.

zealous widget
#

how do you subclass in c

fiery hare
#

@zealous widget you can't because there aren't classes, but I assume there's some concept of extending the behavior of code that already exists.

#

I found my one C course agonizing.

#

And next year during my last semester I have to write an OS emulator, which probably means a return to that realm.

zealous widget
#

does defaultdict extend dict in some manner

#

in c, i mean

fiery hare
#

in C, defaultdicts are a struct that contain a pointer to a dict and a pointer to a defaultfactory

#

problem is, dynamicdict doesn't extend the behavior of defaultdict as much as it changes the behavior of the extension.

gilded orchid
#
>>> factorial = func('x<2', 1, 'True', 'x*factorial(x-1)')
>>> factorial(5)
120

I made this thing

#
def func(*args):
 def a(x):
  for condition, returnarg in zip(args[::2], args[1::2]):
   if eval(condition):
    if type(returnarg)==int:
     return returnarg
    elif type(returnarg)==str:
     return eval(returnarg)
    else:
     return returnarg(x)
 return a

this code is very stupid but it works kind of

#

I probably should've made this a class but whatever

fiery hare
#

@gilded orchid make it a class that only has a static call method

formal sandal
#

Why would it be a class?

fiery hare
#

@formal sandal to make it more esoteric

formal sandal
#

I thought lambdas make things more esoteric

fiery hare
#

They can.

snow beacon
#

There's enough esoteric to go around.

fiery hare
#

Is it conceivably possible to do anything in python with one statement

potent comet
#

Yes.

snow beacon
#

Exception handling is difficult, but beyond that.

potent comet
#
exec("""your code here""")
fiery hare
#

@zealous widget the first person to comment on my idea wasn't a fan.

proper vault
#

Asyncio is a pain to do in one expression

marsh void
#

*laughs in JS*

#

@gilded orchid ah btw, little tip — type(x) is to be better compared using is, e.g. type(x) is int.

gilded orchid
#

ah ok

#

why is that?

potent comet
#

Since you're going to get the class back as a result, there's only one version of any given class. So == is rather redundant.

snow beacon
#

I just use isinstance().

proper vault
#

yeah, definitely isinstance

snow beacon
#

That said, isinstance(True, int) so sometimes type(x) is y is necessary.

formal sandal
#

!e

is_proper_int=lambda x:{*x.__class__.__mro__}&({bool}|{int})&{int,bool}==({*(([([([])])])in()).__class__.__mro__}-{bool,object})
print(is_proper_int(True))
print(is_proper_int(42))
print(is_proper_int(0.5))
night quarryBOT
#

@formal sandal :white_check_mark: Your eval job has completed with return code 0.

001 | False
002 | True
003 | False
formal sandal
#

Slightly obfuscated, but you get the idea.

potent comet
#

Just a little.

formal sandal
#

Yes, a teeny bit.

#

Well, it's not properly obfuscated.

#

It's just confusing.

fiery hare
#

So this is an obfuscated way of determining of an object is an int and only an int?

marsh void
#

not not {type(x)}^{int}?

#

simple but gives some thought

sick hound
formal sandal
#

@fiery hare It checks that an object is an int and not a bool.

#

So it will work with int subclasses.

grizzled cloak
#

ok... very interesting

#
def f(x):
  if x < 2**2**20:
    return -1
  return x

f.__code__.co_consts
Out[4]: (None, 2, 1048576, -1)

it will cache 2 and the result of 2**20, but not the result of 2**2**20.

marsh void
#

¯_(ツ)_/¯

grizzled cloak
#

at what point does it decide not to evaluate a constant expression?

sick hound
#

write a loop and try it out

edgy kelp
#
>>> def f():
...     "a"*5
...     "a"*21
...
>>> f.__code__.co_consts
(None, 'aaaaa')

I have no idea about ints but it skips sequences after 20

#

or something like that

keen spear
#

if it's multiple + chained together it's cached properly

#
  2           0 LOAD_CONST               1 (6)
              2 STORE_FAST               1 (a)

  3           4 LOAD_FAST                0 (x)
              6 LOAD_FAST                1 (a)
              8 COMPARE_OP               0 (<)
             10 POP_JUMP_IF_FALSE       16

  4          12 LOAD_FAST                0 (x)
             14 RETURN_VALUE

  5     >>   16 LOAD_CONST               2 (-1)
             18 RETURN_VALUE
edgy kelp
#

hmm that seems to be a side effect of hwo I wrote it, that limit could be just for the basic interning but it does skip them on a few thousand

sick hound
#

it makes perfect sense to skip at some point since the fact is that evaluating those constants in itself is a full program run

#

unless there are limitations to what it even tries to cache

#

"A"*calculate_the_next_largest_prime()

grizzled cloak
#

hmmm

#

weird

#
def f(x):
    if x < 2**65:
        return x
f.__code__.co_consts
Out[57]: (None, 2, 65)

def f(x):
    if x < 2**64*2:
        return x
f.__code__.co_consts
Out[55]: (None, 36893488147419103232)```
sick hound
#

those are just bitshifts though

#

they are powers of two

grizzled cloak
#

should i try power of 3?

sick hound
#

I don't know if I'm correct but it would make sense since bitshifts are almost free

#

anything of the form 2**k should be able to cache\calculate easily

#

positive or negative exponent

#

but though

grizzled cloak
#

ah

#

as long as the exponent is <= 64 it will cache?

sick hound
#

probably?

grizzled cloak
#
def f(x):
    if x < 3**64:
        return x
f.__code__.co_consts
Out[74]: (None, 3433683820292512484657849089281)
def f(x):
    if x < 3**65:
        return x
f.__code__.co_consts
Out[76]: (None, 3, 65)```
sick hound
#

I don't know why 3**64 would cache though

#

nevermind

#

yeah nevermind

#

it's fine.

grizzled cloak
#

ah.

#

it wont cache 4**64

sick hound
#

try 63

grizzled cloak
#

4**42 is the highest it will cache

#

but you can then just do *4 *4 ...

#

now this is very weird

rugged sparrow
#
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.
>>> f = lambda:0
>>> f.__code__ = f.__code__.replace(co_consts=())
>>> f()
Segmentation fault (core dumped)```
sick hound
#

lol

grizzled cloak
#
def f(x):
    if x < 4**42 * 4**42:
        return x
f.__code__.co_consts
Out[96]: (None, 19342813113834066795298816)
math.log(19342813113834066795298816, 4) # log4(...)
Out[97]: 42.0
#
4**42 * 4**42
Out[98]: 374144419156711147060143317175368453031918731001856
math.log(374144419156711147060143317175368453031918731001856, 4)
Out[99]: 84.0```
#

not like python cant handle that value

#

oh ofc it only has to cache it once

#

lol

#
def f(x):
    if x < 4**42 * 4**41:
        return x
f.__code__.co_consts
Out[103]: (None, 19342813113834066795298816, 4835703278458516698824704)```
#

then it caches both

#

my bad

sick hound
#
>>> 4**(2*42) - (1<<4*42)
0```
#

messed around to get the leftshifts correct

rugged sparrow
#
[(f:=lambda:0).__setattr__('__code__',f.__code__.replace(co_consts=())),f()] 
sick hound
#

what's happening there

rugged sparrow
#

it creates an invalide code object that segfaults python

sick hound
#

but theoretically?

rugged sparrow
#

its prob a python bug

#

co_consts needs to contain None

#

but i set it to an empty tuple and it doesnt verify against it

sick hound
#

it creates a lambda function which gets "named" f, then the __code__ is set to an empty tuple, and then you call the function

rugged sparrow
#

no the __code__ is set to a modified code object

sick hound
#

yeah

#

you're taking the copy of the same __code__ and putting it back in place but replacing the co_consts this time

#

so if you set it to None - this works?

#

it returns 0 in the list comprehension's last element?

#
>>> [(f:=lambda:0).__setattr__('__code__',f.__code__.replace(co_consts=(None,))),f()]
[None, 'exit']```
#

right because the 0 isn't there anymore

#

if it ever even was...?

#

not sure if the lambda gets cached?

rugged sparrow
#

wait

#

the lambda returned 'exit'?

#

hmmm

#

did i just find a mem handling issue

sick hound
#

well it didn't return 0 for sure

#

but I thought that was because the co_consts overrode it

rugged sparrow
#

what version of python are you running?

sick hound
#

Python 3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 22:45:29) [MSC v.1916 32 bit (Intel)] on win32

rugged sparrow
#

hmm

#

i need to test this

marsh void
#

you should not mess with functions

#

in that way

rugged sparrow
#

isnt most of this channel messing with python in ways you shouldnt?

#

wait @marsh void did you implement braces using something like brm?

marsh void
#

I used tokens

#

and tokenizing

#

and yes I did

rugged sparrow
#

damn nice

#

does it fully handle nesting?

marsh void
#

yeah I mean

#

you might try to break it

#

it does not work with py def main() { print('ew'); }

rugged sparrow
#

nice

#

ill check it out

marsh void
#

np

#

have fun ig

#

I need to work with untokenizing a bit

#

current goal is to make it pass flake8 after converting

rugged sparrow
#

oo that would be cool

#

i havent been able to mess with python too much recently

stark fable
#
>>> [(f:=lambda:0).__setattr__('__code__',f.__code__.replace(co_consts=(None,))),f()]
[None, <
 object at 0x000001D413648730>]```
#
>>> res = _[1]
>>> res
<
 object at 0x000001D413648730>``` wat
#
>>> res
<
 object at 0x000001D413648730>
>>> type(res)
<
 object at 0x000001D4134B0AB0>
>>> type_res = _
>>> res
<
 object at 0x000001D413648730>
>>> type_res
<
 object at 0x000001D4134B0AB0>
>>> type(type_res)
< object at 0x000001D4134B0AE0>
>>> type(type(type_res))
< object at 0x000001D41363DE40>
>>> type(type(type(type_res)))
< object at 0x000001D41363DDB0>
>>> type(type(type(type(type_res))))
< object at 0x000001D41363DD20>
>>> type(type(type(type(type(res)))))
< object at 0x000001D41363DD20>
>>> type(type(type(type(type(type(res))))))
segfault```
marsh void
#

Lmfao

stark fable
#

this is similar to the deallocated tuple stuff except the object is a bit more stable

marsh void
#

is .replace really a thing?

rugged sparrow
#

yea

stark fable
#

in 3.8 it is

#

also i found the reason it does that

#
>>> import dis
>>> dis.dis(lambda: 0)
  1           0 LOAD_CONST               1 (0)
              2 RETURN_VALUE
>>> (lambda: 0).__code__.co_consts
(None, 0)```
rugged sparrow
#

ohh

#

sweet

#

i can def abuse that

marsh void
#

lol

rugged sparrow
#

also prob construct valid bytecode that points to a const that doesnt exist

stark fable
#

huh, this is very interesting

#

the result of [(f:=lambda:0).__setattr__('__code__',f.__code__.replace(co_consts=(None,))),f()] changes depending on what you've done before

#

it's deterministic but unpredictable

rugged sparrow
#

welcome to the world of undefined behavior

stark fable
#
>>> open()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: open() missing required argument 'file' (pos 1)
>>> [(f:=lambda:0).__setattr__('__code__',f.__code__.replace(co_consts=(None,))),f()]
[None, 'quit']
>>> [(f:=lambda:0).__setattr__('__code__',f.__code__.replace(co_consts=(None,))),f()]
[None, 'copyright']
>>> 1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> [(f:=lambda:0).__setattr__('__code__',f.__code__.replace(co_consts=(None,))),f()]
[None, <
 object at 0x000002512ABC8730>]```
rugged sparrow
#

by making my lambda:0 load a const from index 9 i got it to make a new empty tuple (normally not possible without weird ctypes)

#
sys.getrefcount(x())
1
>>> x()
((...), ('x',))
>>> x()
((...), (((<NULL>,),),))
>>> x()
[1]    2633 segmentation fault  python3.8
stark fable
#

well that's not an empty tuple but good job anyway

#

whatever that is, it's... very weird

rugged sparrow
#

oh it was an empty tuple originally

#

not entire sure how it changed

#
>>> r = lambda f, **kwargs:setattr(f,'__code__',f.__code__.replace(**kwargs))
>>> x = lambda:0
>>> r(x,co_code=b'd\x09S\x00')
>>> x()
(None,)
>>> x()
('x',)``` uh
#
>>> r(x,co_code=b'd\x10S\x00')
>>> x()
(((<NULL>, b'd\x10S\x00'), ('x',)), 'x')
>>> 1
1
>>> x()
(((((((((...), (...)), ()), ((<NULL>,),)), ((((...),),),)), ()), None), ('x',)), ())```
marsh void
#

lmfao

#

again

rugged sparrow
#
>>> dis.dis(x)
  1           0 RETURN_VALUE```
#

a func that only returns

#

but doesnt gather anything to return

marsh void
#

I think this one is fucking the stack

rugged sparrow
#

im pretty sure that its actually accessing parts of the current stackframe

#

(obviously incorrectly)

formal sandal
#

By the way,

Some advanced styles of programming require updating the types.CodeType object for an existing function. Since code objects are immutable, a new code object needs to be created, one that is modeled on the existing code object. With 19 parameters, this was somewhat tedious. Now, the new replace() method makes it possible to create a clone with a few altered parameters.
This can actually be helpful

#

(new in 3.8)

brisk zenith
#

can actually be helpful?

#

it most definitely is.

#

have you seen my pre-3.8 bytecode patching function which allows for C++-style input and output? it's not pretty :D

bitter iris
#

that posonlyargs addition broke so many code on 3.8

#

That is why replace added

marsh void
#

!eval py def f(*args, **kwargs): print(args, kwargs) f(**{'13': 13})

night quarryBOT
#

@marsh void :white_check_mark: Your eval job has completed with return code 0.

() {'13': 13}
marsh void
#

some fun thing I noticed

marble apex
#

What even IS esorotic python?

marsh void
#

code obfuscation, messing with memory/stack, writing new grammar, golfing stuff

#

!eval py import ctypes t = (0,) ctypes.c_longlong.from_address(id(t) + 24).value = id(t) print(t, t[0], t[0][0])

night quarryBOT
#

@marsh void :white_check_mark: Your eval job has completed with return code 0.

((...),) ((...),) ((...),)
marsh void
#

for example :P

rugged sparrow
#

ah yes. good ol recursive tuple

zealous widget
#

custom interpreter

#
Python 3.8.0 (default, Oct 28 2019, 16:14:01) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(CustomConsole)
>>> f = (x + y from x, y)
>>> f(2, 3)
5
#

this wasn't as hard as i thought, you can subclass InteractiveConsole from code module and just define your own raw_input, alternatively just create an InteractiveConsole and pass in your own readfunc=

zealous widget
#
from code import InteractiveConsole
import re

lambda_pattern = re.compile(r'λ.*[.]')


class CustomConsole(InteractiveConsole):
    def raw_input(self, prompt=""):
        code_ = input(prompt)
        matches = re.findall(lambda_pattern, code_)
        for match in matches:
            code_ = code_.replace(match, f'lambda {", ".join(match[1:-1])}:', 1)
        return code_

cc = CustomConsole()
cc.interact()

and we can do:

>>> f = λxy.x + y
>>> f(2, 3)
5

marsh void
#

hell yes

gilded orchid
#

Is there any way to compile python code into C code? (I tried Nuitka but that uses C++ I think)

#

(also I think??? this is the right place to ask this)

zealous widget
#

you can cythonize it

marsh void
#

^

#

but you get like

#

10k lines

#

xd

stark fable
#

well you could compile python code into code that includes the entirety of CPython and uses that to evaluate the code

#

is that cheating?

potent comet
#

That's what Cython does, it includes the Python C-API and uses that to do everything requiring that.

gilded orchid
#

is that cheating?

not really

#

I kinda just need compilable C code from python code

#

so that could work

#

how would I do that?

snow beacon
#

Out of interest, how much Python code do you have?

gilded orchid
#

I don't really have any specific python code

#

there's a thing that compiles C code to brainfuck, and I'm curious if I go from Python -> C -> Brainfuck

thin trout
#

Okay, hang on a sec

grizzled cloak
#

wouldnt python -> brainfuck -> c be more interesting?

gilded orchid
#

wdym?

#

I'm seeing if I can compile python code to Brainfuck

#

which can only be done by compiling to C first (because ELVM only supports C as a frontend)

thin trout
#
[akarys@mojito Projects]$ python
Python 3.8.1 (default, Feb 17 2020, 11:48:46) 
[GCC 9.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import glob
>>> total = 0
>>> for f in glob.iglob('./**/*', recursive=True):
...   if f.endswith('.py'):
...     with open(f) as fh:
...       total += len(fh.readlines())
... 
>>> total
507852```Hmm, a lot apparently
gilded orchid
#

ah

#

so it's probaly not possible

thin trout
#

Why not compiling python bytecode to brainfuck?

gilded orchid
#

how complex is python bytecode?

thin trout
#

Not a lot

#

It is some stack based pretty simple intructions

gilded orchid
#

because if that were possible you could compile python to a ton of languages

thin trout
#

The issue is that python is stack based

gilded orchid
#

yeah

#

how about compiling python bytecode to C?

thin trout
#

But.. it should be fairly reasonable

#

Should be fairly straitforward tbh

gilded orchid
#

what you recommned for learning about python bytecode?

#

(I only know the very basic stuff about it)

thin trout
#

There is a nice introduction to bytecode at the end of the pytricks book but nothing very advanced

gilded orchid
#

what can be on the stack in python bytecode?

thin trout
#

All arguments are passed through the stack

#

Since python actually use a lot of nested call, that's why it is so important

#

For instance:

#

!e

import dis
dis.dis('''
def add(x, y):
    return x + y

a = 1
b = 2
add(a, b)''')```
night quarryBOT
#

@thin trout :white_check_mark: Your eval job has completed with return code 0.

001 |   2           0 LOAD_CONST               0 (<code object add at 0x7fba2fea85b0, file "<dis>", line 2>)
002 |               2 LOAD_CONST               1 ('add')
003 |               4 MAKE_FUNCTION            0
004 |               6 STORE_NAME               0 (add)
005 | 
006 |   5           8 LOAD_CONST               2 (1)
007 |              10 STORE_NAME               1 (a)
008 | 
009 |   6          12 LOAD_CONST               3 (2)
010 |              14 STORE_NAME               2 (b)
011 | 
... (truncated - too many lines)

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

thin trout
#

You can see in the dissasembly of add() the use of LOAD_FAST which put x and y onto the stack before performing BINARY_ADD, which is going to take the two top objects on the stack, add them and put the result on the stack, then RETURN_VALUE resume the program flow with the returned value being on the top of the stack

#

Then, POP_TOP is used to discard it, because I didn't assigned it

gilded orchid
#

what instructions would I need to implment somthing simple like print(2 + 5)?

stark fable
#
>>> import dis
>>> dis.dis('print(2 + 5)')
  1           0 LOAD_NAME                0 (print)
              2 LOAD_CONST               2 (7)
              4 CALL_FUNCTION            1
              6 RETURN_VALUE```
#

LOAD_NAME, LOAD_CONST, CALL_FUNCTION and RETURN_VALUE, apparently

thin trout
#

the base of the language : the stack machine, call stack, memory space, a manual implementation of print, and the opt codes up here ^

gilded orchid
#

ah

#

this sounds like it could get complicated quickly

thin trout
#

It might sound complicated, but it is actually very straitforward

#

The stack machine is just a stack, nothing else, the call stack is also another stack with two functions to store the next memeory address and jump to another address, and another function to pop the top memory address and jump to it, the memory space is just a dict, and the opt codes can all fit in ~20 lines each

gilded orchid
#

when compiling 5 + 3 it gives

  1           0 LOAD_CONST               0 (8)
              2 RETURN_VALUE
#

is there a way to stop it from evaluating beforehand?

thin trout
#

I think it is a compiler flag, but I'm not sure

gilded orchid
#

is there a limit to the size either of the stacks can reach?

thin trout
#

Apparently you can't disable peephole optimisation

#

There is one

#

But it is more limited by the available memory space

gilded orchid
#

I'm kinda trying to limit used for memory to make it easier, so I might just set a fixed max stack size

thin trout
#

If you run out of space, you should raise StackOverflow

#

the limit in CPython is

#

!e

print(2 ** 32)```
night quarryBOT
#

@thin trout :white_check_mark: Your eval job has completed with return code 0.

4294967296
gilded orchid
#

wow

thin trout
#

(I expected more)

#

You can fit 4294967296 32bits memory address in the current implementation

#

Which is.. 4Gb?

#

Not sure

#

137Gb Google did an approximation nevermiiinndd

stark fable
#

if there are 4294967296 32-bit addresses then isn't that 16 gigabytes?

gilded orchid
#

how does CALL_FUNCTION know how many positional args there are?

proper vault
#

the lowest addressable unit is a single byte

thin trout
#

The code obejct knows it

proper vault
#

on pretty much all modern CPUs

stark fable
#

@gilded orchid the number is the number of arguments

proper vault
#

which is why pointer alignment is a thing

stark fable
#
  1           0 LOAD_NAME                0 (print)
              2 LOAD_CONST               2 (7)
              4 CALL_FUNCTION            1
              6 RETURN_VALUE```
#

CALL_FUNCTION 1

#

-> 1 argument

gilded orchid
#

oh right

thin trout
#

CALL_FUNCTION just store the next address on the call stack and jump to the beginning of the function

gilded orchid
#

do programs always have RETURN_VALUE at the end?

thin trout
#

That's a good question, let's disassemble a file

#

Looks like they do

gilded orchid
#

actually

#

I just found out you can go from C++ -> C using clang

#

so it might be possible to go Python -> C++ (using nuitka) -> C (using clang) -> ELVM -> Brainfuck

#

(even though it'd be horribly inefficient)

thin trout
#

Oh man, you'll start with a two line program and finish with a 25 lines program

snow beacon
#

You're compiling to brainfuck, so I assume efficiency was never a concern.

gilded orchid
#

yeah I guess

snow beacon
#

25 lines is probably quite conservative.

gilded orchid
#

a C lisp REPL compiled to brainfuck is 26MB

#

and 52000 lines

#

(there's some comments added by ELVM)

#

actually it'd be even more inefficient then I thought it would be

#

because to convert from C++ -> C you need to convert to LLVM bytecode first

#

Python -> C++ (using nuitka) -> LLVM Bytecode (using clang) -> C (using llc) -> ELVM Bytecode -> Brainfuck

proper vault
#

why not just take the C source of the python command utility, hardcode the source file to some place in memory, and convert that to LLVM

cursive plover
#

if I may, here's some esoteric C code?

inline int LOG2(uint x){  //x=2^k
    static const int tb[32]={31,0,27,1,28,18,23,2,29,21,19,12,24,9,14,3,30,26,17,22,20,11,8,13,25,16,10,7,15,6,5,4};
    return tb[x*263572066>>27];
}

someone wanna try figure how that returns 0 to 31

proper vault
#

well, it is not guaranteed to work, as it assumes 32bit uint

#

other than that, any 32bit value rishifted 27 bits will have 5 nonzero bits left, which means at 0-31

#

the rest are precomputed magic numbers to make it work

brazen geyser
gilded orchid
#

oh wow

brazen geyser
#

could try out the build from that fork though

cursive plover
#

@proper vault what is the x*263572066 doing there though

proper vault
#

honestly, I doubt it even does log2

#

I am pretty sure LOG2(3) is not meant to be 18

cursive plover
#

oh

#

here's the entire coede

#

for reference

#
//g++  5.4.0

#include <iostream>
#include <cmath>
using namespace::std;
inline int LOG2(uint x){  //x=2^k
    static const int tb[32]={31,0,27,1,28,18,23,2,29,21,19,12,24,9,14,3,30,26,17,22,20,11,8,13,25,16,10,7,15,6,5,4};
    return tb[x*263572066>>27];
}
int main()
{
    for(int i = 0; i < 32; i++){
    cout<<LOG2(pow(2,i))<<endl;
    }
}
#

to reproduce results

proper vault
#

oh, it is supposed to only work on integer powers of 2

cursive plover
#

yes

#

if you see the comment, //x =2^k

proper vault
#

anyway, the reason it is that number specifically, multiplication by a power of 2 is right shift

1111101101011100101001100010
11111    
 11110   
  11101  
   11011 
    10110
     01101
      11010
       10101
...
```each of these sequences of 5 bits is unique
cursive plover
#

hm

#

but I don't see a 00000 in 1111101101011100101001100010 anyplace, how would It get that then

#

cuz it's like going from 0 to 31

brisk zenith
#

if the number is 2 ** 31 then wouldn't multiplying by that really big number cause it to overflow and have its five highest bits be 00000?

#

not really suitable for this channel though :D

proper vault
#

ye, you would get a large enough number that more 0s would appear, but I seem to be wrong as they are duplicate sequences

cursive plover
#

well

#

I'm trying to convert it to python code

#
tb = [31,0,27,1,28,18,23,2,29,21,19,12,24,9,14,3,30,26,17,22,20,11,8,13,25,16,10,7,15,6,5,4]
for i in range(32):
    print(tb[((2**i) * 263572066)>>27])
``` real simple, but I think it isn't right because
#

it only gives me 0,1,2,3,4 and then gives a list index out of range error

proper vault
#

you need to modulo 32

#

as this assumes unsigned overflow on 32 bits

cursive plover
#

oh, yes, it works with modulo 32!

#

hm, but also, how did we know it assumes unsigned overflow again?

proper vault
#

because shifting a 32 bit value 27 bits will yield at most 31

cursive plover
#

oh damn, yeah 😅

sick hound
#

Wait this conversation gave me an idea

#

A python scripts that compiles and runs itself

proper vault
#

that reminds me, what is the shortest quine in python? ```py
quit(open(file).read())

sick hound
#
exec(s:='print("exec(s:=%r)"%s)')
#

But i guess that's cheating too

#

Maybe it isn't

#

I don't know the rules really

#

Doing more investigation it isn't cheating

#

and i also found this quine in ruby on which you can remove 1 single character and it will still work

#
eval='eval$q=%q(puts %q(10210/#{1 1 if 1==21}}/.i rescue##/

1 1"[13,213].max_by{|s|s.size}#"##").gsub(/\d/){["=\47eval$q=%q(#$q)#\47##\47

",:eval,:instance_,"||=9"][eval$&]}
exit)#'##'

instance_eval='eval$q=%q(puts %q(10210/#{1 1 if 1==21}}/.i rescue##/

1 1"[13,213].max_by{|s|s.size}#"##").gsub(/\d/){["=\47eval$q=%q(#$q)#\47##\47

",:eval,:instance_,"||=9"][eval$&]}
exit)#'##'

/#{eval eval if eval==instance_eval}}/.i rescue##/

eval eval"[eval||=9,instance_eval||=9].max_by{|s|s.size}#"##"
#

And there's another one which is technically legal

#
print(__name__)
#

and you have to name the file: print(__name__)

zinc tiger
#

related to the magic log2 function, see also https://en.wikipedia.org/wiki/Fast_inverse_square_root

Fast inverse square root, sometimes referred to as Fast InvSqrt() or by the hexadecimal constant 0x5F3759DF, is an algorithm that estimates ​1⁄√x, the reciprocal (or multiplicative inverse) of the square root of a 32-bit floating-point number x in IEEE 754 floating-point forma...

sick hound
#
for i, v in globals().items():
    print(f"{i} is {v}")
#

Make this not raise an exception

#

without adding lines

#

And without using copy()

rugged sparrow
#
globals = lambda g={**globals()}:g``` add this above it
snow beacon
#

Golfed: globals=lambda:{}

rugged sparrow
#

well i assumed he wanted the same output

snow beacon
#

The only output of their program is __name__ is __main__ for me.

rugged sparrow
#

There should be a little bit more

#

What version of python

buoyant agate
#

Can I remove lines?
||```py
print(*[f"{i} is {v}" for i, v in globals().items()], sep='\n')

snow beacon
#
Python 3.8.2 (default, Feb 26 2020, 22:21:03) 
[GCC 9.2.1 20200130] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> for i, v in globals().items():
...     print(f"{i} is {v}")
... 
__name__ is __main__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
>>> 
#

I can give my neofetch, but I don't think it'll be useful.

rugged sparrow
#

oh itll print more if you get around the exception

formal sandal
#

I think I have found a trick that will confuse some people.

#

!e

# ,= is a brand new operator in Python, and a very useful one.
# It's like += or :=, but with a comma.
# It unpacks a single-element iterable
# into its only element. It's not documented  yet!

my_list = ["hello"]
x ,= my_list
print(x)

my_generator = (x for x in [1, 2, 3] if x < 2)
number ,= my_generator
print(number)
night quarryBOT
#

@formal sandal :white_check_mark: Your eval job has completed with return code 0.

001 | hello
002 | 1
brisk zenith
#

haha, that's fun

edgy kelp
#

nicer alternative 😛

>>> my_generator = (x for x in [1, 2, 3] if x < 2)
>>> [number] = my_generator
>>> number
1
formal sandal
#

Yes, but it doesn't look like := or += or ->=

edgy kelp
#

What does unpacking accept? Just tuples and lists?

formal sandal
#

Any iterable.

edgy kelp
#

on the left side

formal sandal
#

oh

#

I guees so

#

Well, not only tuples

#

!e

(a) = [1]
print(a)
night quarryBOT
#

@formal sandal :white_check_mark: Your eval job has completed with return code 0.

1
formal sandal
#

technically that's not a Python tuple

hot crypt
#

did you mean to print(a)?

edgy kelp
#

Seems to be only parentheses and brackets

assignment_stmt ::=  (target_list "=")+ (starred_expression | yield_expression)
target_list     ::=  target ("," target)* [","]
target          ::=  identifier
                     | "(" [target_list] ")"
                     | "[" [target_list] "]"
                     | attributeref
                     | subscription
                     | slicing
                     | "*" target
formal sandal
#

@hot crypt Yep

#

oops

brisk zenith
#

:D

formal sandal
#

that pinged Static for some reason, not staticmethod

formal sandal
#

I think I reinvented pug... But maybe this can be useful.

#

Input:

%extends[base.html]

%block(body)[
    header(1)[ Lorem ipsum ]
    p[
        Dolor sit amet!
    ]
    p[
        [Welcome to]  fontsize(2em)[my] [homepage!]
    ]
]

Output:

{% extends "base.html" %}
{% block body %}
<h1> Lorem ipsum </h1>
<p> Dolor sit amet! </p>
<p>Welcome to
<span style='font-size: 2em'>my</span>
homepage!</p>
{% endblock %}
#

Because I'm so tired of writing a tag twice!

gilded orchid
#
def test(a):
 b,=a
 return a==b

challenge using that: make this return true

formal sandal
#

!e

def test(a):
 b,=a
 return a==b

x = []
x.append(x)
print(test(x))
night quarryBOT
#

@formal sandal :white_check_mark: Your eval job has completed with return code 0.

True
gilded orchid
#

yep

#

that was 100% identical to my solution

formal sandal
#

!e

def test(a):
 b,=a
 return a==b

print(test("a"))
gilded orchid
#
def test(a):
 b,=a
 return a==b

x=[]
x.append(x)
print(test(x))
night quarryBOT
#

@formal sandal :white_check_mark: Your eval job has completed with return code 0.

True
gilded orchid
#

oh wow

#

I didn't think about that

formal sandal
#

!e

import inspect
import ast

def namespace(fn):
    source = inspect.getsource(fn)
    tree = ast.parse(source)
    local_names_before = set(locals().keys())
    tree.body = tree.body[0].body
    """
    before:            after:
    def fn():          a = 1
        a = 1          b = 2
        b = 2
    """
    exec(compile(tree, "<namespace function>", "exec"))
    new_locals_dict = locals()
    local_names_after = set(new_locals_dict.keys())  - {"local_names_before"}
    new_keys = local_names_after - local_names_before
    return {key: new_locals_dict[key] for key in new_keys}

@namespace
def MyVariables():
    a = 1
    b = 2
    def c():
        return "letter c"

print(MyVariables)
night quarryBOT
#

@formal sandal :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 22, in <module>
003 |   File "<string>", line 5, in namespace
004 |   File "/usr/local/lib/python3.8/inspect.py", line 985, in getsource
005 |     lines, lnum = getsourcelines(object)
006 |   File "/usr/local/lib/python3.8/inspect.py", line 967, in getsourcelines
007 |     lines, lnum = findsource(object)
008 |   File "/usr/local/lib/python3.8/inspect.py", line 798, in findsource
009 |     raise OSError('could not get source code')
010 | OSError: could not get source code
formal sandal
#

god dammit

formal sandal
formal sandal
#

After a bit of tinkering, I was able to make it work!

%extends[base.html]

%block(body)[
    header(1)[ Lorem ipsum ]
    p[
        Dolor sit amet!
    ]
    p[
        [Welcome to]  fontsize(2em)[my] [homepage!]
    ]
    todo [make everything work]
    .class-a class-b class-c [
        p[hello]
    ]
    #my_id [
        p[world]
    ]
    style[
        td {border: 1px solid black; padding: 1em}
    ][
        table(2, 3)
            [a] [b] [c]
            [d] [e] [f]
        elbat
    ]
]
marsh void
#

is it like html but tags are a[stuff] instead of <a>stuff</a>?

formal sandal
#

Well, yes.

#

And making tables is not that bad anymore.

#

Also, as you can see, you can use normal CSS (even SCSS!) in inline styles.

#

But pug uses semantic indents instead of [].

proper vault
#

seems pretty similar to latex syntax-wise

formal sandal
#

now it's time to implement tikz...

#

I would also love table styling similar to latex's arrays, where I can configure alignment, put vertical bars etc.

opal perch
#

@formal sandal what are you doing if I may ask ?

#

@formal sandal do you know of the dominate and pylatex packages ? It kinda looks like you’re merging the two into yet another parser/lexer/doodat

grizzled cloak
#

it parses emu-speak

opal perch
#

@formal sandal if you’re going to integrate tils there is a bit of a hack you can try. Putting ellipsis as the first argument in a python function makes the argspec extra flexible so

def path(..., *args, **kvps) :
#stuff

Gave you an extra argument span to play with and allows more Tex/TikZ like syntax. I forget the full trick but I think you could add key word args before the ellipsis iirc. I only tried it in python 3.6 and a self compiled 3.5 which was rather dodgey.

#

Never heard of that I’ll google it up.

#

@grizzled cloak ok my google foo broke, what is emu speak ?

grizzled cloak
#

the language of emus!

#

it was just a joke 😉

#

because its called emuParse

opal perch
#

My first google hit was “emu’s are gods” so I was like that ain’t parseltongue 😉

formal sandal
#

@opal perch I'm just making a convenient tool for myself. I'm not trying to replicate latex or something.

#

I will take a look at dominate one day, it looks cool

#

Like elm where HTML tags are just functions.

opal perch
#

@formal sandal Ok, hmm... do know of the pyparsing/pylens libraries ? Might help with the parsing. Pyparsing allows you to convert the text as you parse it if you use it right. So you could do wierd things like split your emu into css and html. Which is the best way to eat em really.

#

FYI I met an Australian chef once. Told me the best way to cook emu was with two pots. In the first you place the emu and in the second a brick. When the brick is soft enough to prick with a fork you know that the emu is ready.

formal sandal
#

I'm already using Lark which uses EBNF-like grammar, and I'm quite happy with it.

#

It has a billion extra features I don't even know about...

opal perch
#

Ok, the pylens one was interesting as it led to a project called augeas which allowed one to edit /etc files programmatically.

#

How have you found lark ? I haven’t tried it personally.

#

Granted when I last tried I couldn’t find a nice intro.

formal sandal
#

Lark is very convenient and declarative. You just define the grammar and some handlers inside a transformer.

#

It takes a grammar, a textual input and produces an abstract syntax tree.

#

Then you can either use a Visitor or a Transformer.

#

I have never used a Visitor, though.

opal perch
#

Ok, can you transform the AST and flatten it again to the original text ?

#

Is it possible to include a custom class as the basis for the AST nodes ? I tried something similar in pyparsing with QObjrct to display the AST in a gui. But there are other applications.

#

How do the transformers works. Also thanks for the link I’ll plough through em tomorrow 🙂

formal sandal
#

Well, you can create a transformer that will eventually returns the string that's like the original one.

#

Basically, you can

opal perch
#

Can you access the ast through any other patterns ? E.g. can you travers the ast yourself or does lark control that.

formal sandal
#

You can.

opal perch
#

Cool, I’ll do so. Thanks !

rugged sparrow
#

!e

class Context:
    def __enter__(self):
            self.__backup = {**__annotations__}
            __annotations__.clear()
            return self
    def __exit__(self, *s):
            for key, val in __annotations__.items():
                    setattr(self,key,val)
            __annotations__.clear()
            __annotations__.update(self.__backup)
            del self.__backup

with Context() as c:
        x: 123
        y: 789

print(c.x, c.y)
night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

123 789
cursive plover
#

!e

# ,= is a brand new operator in Python, and a very useful one.
# It's like += or :=, but with a comma.
# It unpacks a single-element iterable
# into its only element. It's not documented  yet!

my_list = ["hello"]
x ,= my_list
print(x)

my_generator = (x for x in [1, 2, 3] if x < 2)
number ,= my_generator
print(number)

hey v_gz, how did you know about it if it hasn't been documented yet

zealous widget
#

lol

#

cute

#

that's just abuse of syntax

#
x, = my_list

which is more apparent if i do this

formal sandal
#

No I haven't yet.

#

SLY would work as well, I guess.

#

How do language parsers work with context-dependent grammar?

#

Like in C++:

Template1 <Template2<T>> a;

((Template1 < Temlpate2) < T) >> a
or
declare a of type Template1[type=Template2[type=T]]?

zealous widget
#

well sly allows lets you declare precedences to avoid reduce reduce conflicts

formal sandal
#

That's possible in Lark as well.

zealous widget
#

i did a parser for boolean logic with sly just to get familiar with it

bitter iris
#

Just to say, if your grammar is simple enough and LL(1) you can generate a parser without depending any library. At least until 3.10.

#

Thanks to lib2to3.pgen2

formal sandal
#

Maybe.

#

There are probably too many options for parsing in python...

#

Anyway, here's what I added.

from ..ext import EmuExtension, register_extension
from ..util import namespace, splat

@register_extension
class BasicTable(EmuExtension):
    grammar_entry_point = "FUNCTION_TAGS"
    name = "tagf_table"
    rule = ' "table" "(" POSITIVE_INTEGER "," POSITIVE_INTEGER ")"  ("[" atom "]")+  "elbat" '

    @namespace(fn=splat)
    def handlers():
        def tagf_table(width, height, *cells):
            if len(cells) != width * height:
                return f"[BasicTable: expected {width * height} cells, got {len(cells)}]"
            output = "<table>"
            for j in range(height):
                output += "<tr>"
                for i in range(width):
                    output += "<td>" + cells[width * j + i] + "</td>"
                output += "</tr>"
            output += "</table>"
            return output
#

Now you can easily add your own extensions to the parser.

#
table (3, 2)
    [a] [b] [c]
    [d] [e] [f]
elbat
zealous widget
#

i can't find any docs for pgen

formal sandal
#

Well, there are docs inside the code.

zealous widget
#

where

formal sandal
#

Oh, hm

#

The actuan pgen doesn't have any docs, I guess

#
# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved.
# Licensed to PSF under a Contributor Agreement.

I'm not sure whether they can add docs to the code

formal sandal
#

Oh wait

wide depot
#

!e

my_list = ["hello"]
x ,= my_list
print(x)

my_generator = (x for x in [1, 2, 3] if x < 2)
number ,= my_generator
print(number)

night quarryBOT
#

@wide depot :white_check_mark: Your eval job has completed with return code 0.

001 | hello
002 | 1
marsh void
#

what were you doing?

snow beacon
#

Testing unpacking the generators?

edgy kelp
#

the ,= operator

formal sandal
#

hey v_gz, how did you know about it if it hasn't been documented yet
We have connections to the CPython core dev team in the staff channel

#

Now this is actually useful.

[
    p[ Hello world. ]
    p[ [X] ?in [set of all X's] ]
    p[
        py-exec
            [print("Hello, world!")]
            [Hello, world!]
    ]
    p[
        py-exec
            [print("Hello, world!")]
            [Hello, world...]
    ]
]
marsh void
#

@formal sandal any source?

formal sandal
#

?

marsh void
#

uhh

#

Like, is this your project?

formal sandal
#

Yes.

marsh void
#

Wanted to know if it is open-source

formal sandal
#

I'm going to publish it eventually, of course.

marsh void
#

Oki

#

Looks pretty cool

formal sandal
#

I can share it on github if you really want to see it, but it really needs refactoring in some places.

marsh void
#

Yeah I don’t mind messy code

#

I am interested in how it gets translated and stuff basically

formal sandal
#

Oh, I'm just using lark, as I said before. So there's nothing really interesting in terms of parsing. But maybe I'm wrong.

marsh void
#

Cool! :)

distant wave
sick hound
#

Hello

#

how can i override a _dict_ of an Enum?

#

Code:

class Color(Enum):
    pass


globals().get("Color").__dict__.update(colorama.Fore.__dict__)
#

Also tried calling Color() but it doesn't work

#

nvm

rugged sparrow
#

What's your goal exactly?

sick hound
#

experimenting

#

like Color.RED should be the same as colorama.Fore.RED

proper vault
#

you could just do ```py
from colorama import Fore as Color

sick hound
#

yes i know

#

as i said, i was just experimenting

proper vault
#

alternatively,

from collections import SimpleNamespace
from colorama import Fore
Color = SimpleNamespace(**vars(Fore))
```or 
```py
from colorama import Fore
Color = type('Color', (), vars(Fore))
gilded orchid
#
sum(iter(int,1))

terrible way of creating an infinite loop

#

and a terrible way of hitting the recursion limit

a=iter(a);next(a)
snow beacon
#

Doesn't that give a nameerror?

gilded orchid
#

nope

edgy kelp
#

!e
a=iter(a);next(a)

night quarryBOT
#

@edgy kelp :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 | NameError: name 'a' is not defined
distant wave
#

!e ```py
a = []
a = iter(a + [a])
next(a)

night quarryBOT
#

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

[No output]
distant wave
#

!e ```py
a = (a := []) + [a]
print(a)

night quarryBOT
#

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

[[]]
distant wave
#

odd.

#

!e ```py
a = []
a += [a]
print(a)

night quarryBOT
#

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

[[...]]
stark fable
#
a = (a := []) + [a]
# is the same as
a = []
a = a + [a]```
distant wave
#

!e ```py
b = (a := [1, 2, 3])
a.append(4)
print(a, b)

night quarryBOT
#

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

[1, 2, 3, 4] [1, 2, 3, 4]
distant wave
#

!e ```py
b = (a := [1, 2, 3]) + []
a.append(4)
print(a, b)

night quarryBOT
#

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

[1, 2, 3, 4] [1, 2, 3]
stark fable
#

assigning to a variable doesn't mutate the value in the variable, it just replaces it entirely with something else

distant wave
#

ah

#

the trick is in the +=

stark fable
#

yep

#

+= calls __iadd__ or whatever it is

#

which for lists changes it in-place

#

what i said was about this

#

that makes perfect sense and i don't really understand what's confusing

distant wave
#

There's only one list initializer called, yet there's two lists in the output

#

!e ```py
a = (a := [1]) + [a]
print(a)

night quarryBOT
#

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

[1, [1]]
formal sandal
#

Is := really a good addition to python?

#

Are there any uses of it besides while loops?

edgy kelp
#

if result := operation(arg)

formal sandal
#

Oh, true

edgy kelp
#

I'm not a fan of all the parentheses you sometimes need but it can make simple conditions nicer

formal sandal
#

You can also create a new variable like this inside a list comprehension, I guess

edgy kelp
#

not nearly as readable though

thin trout
#

The walrus is just syntax sugar anyway, it will probably never allow something we couldn't do before

#

Except if you try to do golfing or functional programming

bitter iris
#

The walrus is just syntax sugar anyway, it will probably never allow something we couldn't do before
It was, at least kind of, but not now.

rugged sparrow
#

!e

(a:=[]).append(a)
night quarryBOT
#

@rugged sparrow :warning: Your eval job has completed with return code 0.

[No output]
rugged sparrow
#

!e

(a:=[]).append(a)
print(a)
night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

[[...]]
sick hound
#

!e

(a:=[1,]).append(a)
for _ in range(10):
  a = a[0]
  print(b)
night quarryBOT
#

@sick hound :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 4, in <module>
003 | NameError: name 'b' is not defined
sick hound
#

!e

(a:=[1,]).append(a)
for _ in range(10):
  a = a[0]
  print(a)
night quarryBOT
#

@sick hound :x: Your eval job has completed with return code 1.

001 | 1
002 | Traceback (most recent call last):
003 |   File "<string>", line 3, in <module>
004 | TypeError: 'int' object is not subscriptable
sick hound
#

!e

(a:=[1,]).append(a)
print(a)
night quarryBOT
#

@sick hound :white_check_mark: Your eval job has completed with return code 0.

[1, [...]]
sick hound
#

!e

(a:=[1,]).append(a)
for _ in range(10):
  a = a[1]
  print(b)
night quarryBOT
#

@sick hound :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 4, in <module>
003 | NameError: name 'b' is not defined
sick hound
#

!e

(a:=[1,]).append(a)
for _ in range(10):
  a = a[1]
  print(a)
night quarryBOT
#

@sick hound :white_check_mark: Your eval job has completed with return code 0.

001 | [1, [...]]
002 | [1, [...]]
003 | [1, [...]]
004 | [1, [...]]
005 | [1, [...]]
006 | [1, [...]]
007 | [1, [...]]
008 | [1, [...]]
009 | [1, [...]]
010 | [1, [...]]
sick hound
#

infinitely nested

#

nicer

#

nice

#

useful

#

!e

(a:=[]).append(a)
(b:=[]).append(b)
print(a == b)
night quarryBOT
#

@sick hound :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 3, in <module>
003 | RecursionError: maximum recursion depth exceeded in comparison
marsh void
#

I think this is possible to make this return True though

#

!e py (a := []).append(a) print(a == a)

night quarryBOT
#

@marsh void :white_check_mark: Your eval job has completed with return code 0.

True
formal sandal
#

!e

def f(x):
    try: f(f(f(f(0))))
    except: f(f(f(f(0))))
f(0)
night quarryBOT
#

@formal sandal :x: Your eval job has completed with return code 139 (SIGSEGV).

001 | Fatal Python error: Cannot recover from stack overflow.
002 | Python runtime state: initialized
003 | 
004 | Current thread 0x00007f5636b4e740 (most recent call first):
005 |   File "<string>", line 2 in f
006 |   File "<string>", line 2 in f
007 |   File "<string>", line 2 in f
008 |   File "<string>", line 2 in f
009 |   File "<string>", line 2 in f
010 |   File "<string>", line 2 in f
011 |   File "<string>", line 2 in f
... (truncated - too many lines)

Full output: too long to upload

formal sandal
#

!e print(0)

night quarryBOT
#

@formal sandal :white_check_mark: Your eval job has completed with return code 0.

0
formal sandal
rugged sparrow
#

!e ```py
def f():
try:f()
except:f()

f()

night quarryBOT
#

@rugged sparrow :x: Your eval job has completed with return code 139 (SIGSEGV).

001 | Fatal Python error: Cannot recover from stack overflow.
002 | Python runtime state: initialized
003 | 
004 | Current thread 0x00007f4435a18740 (most recent call first):
005 |   File "<string>", line 2 in f
006 |   File "<string>", line 2 in f
007 |   File "<string>", line 2 in f
008 |   File "<string>", line 2 in f
009 |   File "<string>", line 2 in f
010 |   File "<string>", line 2 in f
011 |   File "<string>", line 2 in f
... (truncated - too many lines)

Full output: too long to upload

stark fable
#

i think doing try/except resets the way it keeps track of recursion that triggers the recursion limit

#

so if you do that you get an actual stack overflow

formal sandal
#

also

rugged sparrow
#

nah its cause the generic try/except catches the Recursion exception

formal sandal
#

!e

f=int
f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f())))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
night quarryBOT
#

@formal sandal :x: Your eval job has completed with return code 1.

001 | s_push: parser stack overflow
002 | MemoryError
formal sandal
#

^

rugged sparrow
#

!e ```py
def f():
try:f()
except Exception as e:print(e)
f()

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

maximum recursion depth exceeded
snow beacon
#

!e ```py
def f():
try:f()
except Exception as e:
print(e)
f()
f()

night quarryBOT
#

@snow beacon :x: Your eval job has completed with return code 139 (SIGSEGV).

001 | maximum recursion depth exceeded
002 | Fatal Python error: Cannot recover from stack overflow.
003 | Python runtime state: initialized
004 | 
005 | Current thread 0x00007f0e874ee740 (most recent call first):
006 |   File "<string>", line 2 in f
007 |   File "<string>", line 2 in f
008 |   File "<string>", line 2 in f
009 |   File "<string>", line 2 in f
010 |   File "<string>", line 2 in f
011 |   File "<string>", line 2 in f
... (truncated - too many lines)

Full output: too long to upload

snow beacon
#

Okay, I don't know why I expected anything different.

formal sandal
#

Maybe it would be possible to open multiple processes or threads running this function and see what it does.

#

Like, 256 processes.

snow beacon
#

Not sure multiple processes work in snekbox.

formal sandal
#

!e

from multiprocessing import Pool

def f(x):
    return x*x

with Pool(5) as p:
    print(p.map(f, [1, 2, 3]))
night quarryBOT
#

@formal sandal :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 6, in <module>
003 |   File "/usr/local/lib/python3.8/multiprocessing/context.py", line 119, in Pool
004 |     return Pool(processes, initializer, initargs, maxtasksperchild,
005 |   File "/usr/local/lib/python3.8/multiprocessing/pool.py", line 191, in __init__
006 |     self._setup_queues()
007 |   File "/usr/local/lib/python3.8/multiprocessing/pool.py", line 343, in _setup_queues
008 |     self._inqueue = self._ctx.SimpleQueue()
009 |   File "/usr/local/lib/python3.8/multiprocessing/context.py", line 113, in SimpleQueue
010 |     return SimpleQueue(ctx=self.get_context())
011 |   File "/usr/local/lib/python3.8/multiprocessing/queues.py", line 336, in __init__
... (truncated - too many lines)

Full output: too long to upload

formal sandal
#

People say that there are no macros in Python.

#

But we have inspect!

#

!e

import inspect

def destructure(obj):
    if not isinstance(obj, dict):
        raise TypeError(f"{obj} is not a dict")
    parent_frame = inspect.currentframe().f_back
    line = inspect.getframeinfo(parent_frame).code_context[0]
    var_names = map(str.strip, line.split("=")[0].split(","))
    for var_name in var_names:
        yield obj[var_name]

my_dictionary = {"a": 42, "varr": 666, "_": ()}
a, varr, _ = destructure(my_dictionary)
print(a)
print(varr)
print(_)
night quarryBOT
#

@formal sandal :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 13, in <module>
003 |   File "<string>", line 7, in destructure
004 | TypeError: 'NoneType' object is not subscriptable
formal sandal
#

:___ - (

#

Apparently code_context is None even for the frames that were mine!

distant wave
#

Pop quiz: What is the use for the following expression:

#
[*_]
bitter iris
#

exhausting an iterable?

distant wave
#

Not quite, I suppose I wasn't very clear, this'll be used on it's own line, when interspersed with other, normally named code

bitter iris
#

is the whole line consists from that single expression?

distant wave
#

yes

bitter iris
#

then, I couldn't think anything else then just getting all values from an iterable/generator

distant wave
#

Want a tiny hint?

bitter iris
#

yup

distant wave
#

When is _ a defined variable?

vestal solstice
#

in shell

zealous widget
#

when you use that translation module

sick hound
#

!e

from multiprocessing import Pool

def f(x):
return x*x

with Pool(5) as p:
print(p.map(f, [1,m]))

night quarryBOT
#

@sick hound :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 6, in <module>
003 |   File "/usr/local/lib/python3.8/multiprocessing/context.py", line 119, in Pool
004 |     return Pool(processes, initializer, initargs, maxtasksperchild,
005 |   File "/usr/local/lib/python3.8/multiprocessing/pool.py", line 191, in __init__
006 |     self._setup_queues()
007 |   File "/usr/local/lib/python3.8/multiprocessing/pool.py", line 343, in _setup_queues
008 |     self._inqueue = self._ctx.SimpleQueue()
009 |   File "/usr/local/lib/python3.8/multiprocessing/context.py", line 113, in SimpleQueue
010 |     return SimpleQueue(ctx=self.get_context())
011 |   File "/usr/local/lib/python3.8/multiprocessing/queues.py", line 336, in __init__
... (truncated - too many lines)

Full output: too long to upload

sick hound
#

how

#

!e

from multiprocessing import Pool

def f(x):
return x*x

night quarryBOT
#

@sick hound :warning: Your eval job has completed with return code 0.

[No output]
sick hound
#

!e

from multiprocessing import Pool

with Pool:
paas

night quarryBOT
#

@sick hound :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 3, in <module>
003 | AttributeError: __enter__
sick hound
#

!e

from multiprocessing import Pool

with Pool:
pass

night quarryBOT
#

@sick hound :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 3, in <module>
003 | AttributeError: __enter__
sick hound
#

!e

from multiprocessing import Pool

with Pool(1):
pass

night quarryBOT
#

@sick hound :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 3, in <module>
003 |   File "/usr/local/lib/python3.8/multiprocessing/context.py", line 119, in Pool
004 |     return Pool(processes, initializer, initargs, maxtasksperchild,
005 |   File "/usr/local/lib/python3.8/multiprocessing/pool.py", line 191, in __init__
006 |     self._setup_queues()
007 |   File "/usr/local/lib/python3.8/multiprocessing/pool.py", line 343, in _setup_queues
008 |     self._inqueue = self._ctx.SimpleQueue()
009 |   File "/usr/local/lib/python3.8/multiprocessing/context.py", line 113, in SimpleQueue
010 |     return SimpleQueue(ctx=self.get_context())
011 |   File "/usr/local/lib/python3.8/multiprocessing/queues.py", line 336, in __init__
... (truncated - too many lines)

Full output: too long to upload

marsh void
#

Was it worth spamming here?

proper vault
#

@distant wave in the interactive shell, when the previous result was an Iterable (itertools/map) and you wish to inspect the result

marsh void
#

^

#

if you want to inspect the iterator you have

distant wave
#

^ that's it

snow beacon
#

You can golf it a little by doing *_, instead.

zealous widget
#

that's what isidentical said

distant wave
#

neat

zealous widget
#

isidentical: exhausting an iterable?

#

dunno why you said not quite

distant wave
#

IMO exhausting an iterable and unpacking it to view its contents are not the same

zealous widget
#

how do you unpack it without exhausting it

distant wave
#

You don't

#

!e ```py

exhausting an iterable:

[*range(15)]

showing an iterables contents

print([*range(15)])

night quarryBOT
#

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

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
zealous widget
#

i don't understand

#

it's the same thing in the console

marsh void
#

You are still exhausting an iterable, but the purposes are different

zealous widget
#

i don't think a purpose was mentioned

stark fable
#

these two functions are different ```py
def function_one():
2 + 2

def function_two():
return 2 + 2```

#

they do the same thing but you get different results

zealous widget
#

yes, but this was a console-only question

#

isidentical: then, I couldn't think anything else then just getting all values from an iterable/generator
i'm still on team isidentical here

#

i think maybe you were overly pedantic

#

i can try out custom console functions with this though:

In [20]: %a 1 2 3 4
Out[20]: array([1, 2, 3, 4])

In [21]: map(λx.2x, _)
Out[21]: <map at 0x7f245b2fcac0>

In [22]: *_,
Out[22]: (2, 4, 6, 8)
lament ibex
#

Got an idea from that discussion

import sys
import itertools
import builtins
def displayhook(value):
    if value is None:
        return
    print(repr(value))
    try:
        iter(value)
        a, b = itertools.tee(value)
        print("Saved you unpacking:", list(a))
        builtins._ = b
    except TypeError:
        pass
sys.displayhook = displayhook

Messes up the original variable but I guess it's handy if you can't be bothered typing 3 characters 🤷‍♂️

zealous widget
#

that might be a fun one to add to the console

#

then again, i'd probably kill it with an infinite iterator

#

maybe put a limit on there

lament ibex
#

lol true

zealous widget
#

you can subclass InteractiveConsole too

#
from code import InteractiveConsole
import re

lambda_pattern = re.compile(r'λ[a-z]+[.]')


class CustomConsole(InteractiveConsole):
    def raw_input(self, prompt=""):
        code_ = input(prompt)
        matches = re.findall(lambda_pattern, code_)
        for match in matches:
            code_ = code_.replace(match, f'lambda {", ".join(match[1:-1])}:', 1)
        return code_

cc = CustomConsole()
cc.interact()
#

just mess with the raw_input function to do whatever wait, you'd still need a hook for output

#

well, there's probably a thing for that

#

no, i think you still need sys

#

rip

zealous widget
#

something like this maybe

#
import sys
import itertools
import builtins
from itertools import tee, islice

def isgenerator(iterable):
    return hasattr(iterable,'__iter__') and not hasattr(iterable,'__len__')

def displayhook(value):
    if not isgenerator(value):
        print(repr(value))
        return

    a, b = itertools.tee(value)
    items = *islice(a, 11),
    print(*items[:10], '...' if len(items) == 11 else '')
    builtins._ = b

sys.displayhook = displayhook
lament ibex
#

ah nice I spent a while thinking about how to detect if something's a generator

zealous widget
#

does anyone know of another way to do this -- automatically add a parent's init to a child's init while also combining the signatures:

from inspect import signature
from textwrap import dedent


def parse_signature(signature):
    return str(signature)[1:-1].split(', ', 1)[1]


class Person:
    def __init__(self, name):
        self.name = name

    def __init_subclass__(cls):
        def deco(func):
            child_args = parse_signature(signature(func))
            self_args = parse_signature(signature(cls.__base__.__init__))
            all_args = f'{self_args}, {child_args}'

            temp_globals = {'func': func, 'cls':cls}
            temp_locals = {}
            wrapper = f"""
            def wrapper(self, {all_args}):
                super(cls, self).__init__({self_args})
                return func(self, {child_args})"""
            exec(dedent(wrapper), temp_globals, temp_locals)

            return temp_locals['wrapper']

        cls.__init__ = deco(cls.__init__)

class Cyborg(Person):
    def __init__(self, version):
        self.version = version
#

note how it gives the parent's __init__ variable as well

#

i'm more curious if there's a way to do this without exec, or even without inspect

stark fable
#

technically it would probably be possible to do it without needing exec or inspect if you just did a lot of stuff yourself with code objects

zealous widget
#

except they're immutable

stark fable
#

yeah i wasn't saying you would change the code objects

#

just look at the code objects and then make a new one

bitter iris
zealous widget
night quarryBOT
#
Yep.

Your reminder will arrive in 12 hours!

hollow patrol
#

`chain = Chain().print(4).print(5).iterate(x = [1, 2, 3]).print(v('x')).end().print(5)

chain.top.execute()`

#

another method for anonymous functions if you want

#

it works by using .end()

#

working on improving it, but it works so far

#

i might add __call__ to it

#

so you could do chain() over chain.top.execute()

hollow patrol
#

yep, I added __call__

night quarryBOT
grizzled cloak
#

ok. i am very confused

#

shouldnt __slots__ decrease memory usage?

#
class A(object):
    __slots__ = ("foo", "bar", "baz")
    def __init__(self, foo, bar, baz):
        self.foo = foo
        self.bar = bar
        self.baz = baz
    def __repr__(self):
        return str(sys.getsizeof(self))
class B(object):
    def __init__(self, foo, bar, baz):
        self.foo = foo
        self.bar = bar
        self.baz = baz
    def __repr__(self):
        return str(sys.getsizeof(self))
A(1,2,3)
Out[7]: 64
B(1,2,3)
Out[8]: 56```
#

why is the non slots version smaller???

edgy kelp
#

I wouldn't rely on getsizeof too much

stark fable
#

getsizeof just gets the size of the actual object, not the amount of memory usage

#

maybe the non-slots version has a reference to some other big thing

grizzled cloak
#

oh

#

so its probably still smaller in memory?

edgy kelp
#

Try getting sizes of dicts etc. It only gets the upper structures and I wouldn't use it for custom object without implementing the finder.
One way you could try it is making a whole lot of objects

grizzled cloak
#

trying that now ^^

edgy kelp
#

Should also be faster to create them

grizzled cloak
#
Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     1 1000001  23 64_000_064  34 148_278_904  79 __main__.A
     2 1000001  19 56_000_056  19 252_279_548  86 __main__.B```
#

A is with slots, b without

#

bit more than half the size

#

inspected with guppy.hpy().heap()

marsh void
#

pingy ping

#

cool

#

I am just sorta busy now :d

formal sandal
#

Oh, sorry for the ping then.

#

Anyway, if you'll want to try it out, it comes with an adapter to the pyramid web framework

marsh void
#

nice

formal sandal
#

huh?

glacial rampart
#

why this and not tokenize.Tokenizer

#

er, tokenize.tokenize

proper vault
#

saved you some code for tokenizing a string

bitter iris
#

tokenize is written in python to behave like the original tokenizer

#

it is not using same approach with the original tokenizer

#

(it is using regexps, tons of regexps)

midnight bane
#

!e ```py
def my_function():
print("hi!")

exec(f"my_function{'.call' * 2991}()")

night quarryBOT
#

@midnight bane :white_check_mark: Your eval job has completed with return code 0.

hi!
dull tartan
#

!e ;

marsh void
#

!e ```py
def my_function():
print("hi!")

exec(f"my_function{'.call' * 2993}()")

night quarryBOT
#

@marsh void :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 4, in <module>
003 | RecursionError: maximum recursion depth exceeded during compilation
marsh void
#

yup

sick hound
#

Just had someone ask me why their code doesnt work:

import pyglet
from pyglet.window import key
from pyglet.gl import glClearColor

#window stuff
window = pyglet.window.Window(800, 600, caption = 'game', fullscreen = False)
glClearColor(0,128 / 255,0 ,1)


#test
keys = key.KeyStateHandler()
if keys[key.SPACE] == True:
        print('hello')

#player stuff
class player():
    global player_image
    player_image = pyglet.resource.image('player1.png')
    global player_X
    player_X = 350
    global player_Y
    player_Y = 250


#update
def update(dt):
    window.push_handlers(keys)

pyglet.clock.schedule_interval(update, 1/120)

#i dont know stuff
@window.event
def on_draw():
    window.clear()
    player_image.blit(player_X,player_Y)

#to make this work
pyglet.app.run()
thin trout
#

You can __call__ the __call__ hmm

sick hound
#
import pyglet
from pyglet.window import key
from pyglet.gl import glClearColor

window = pyglet.window.Window(800, 600, caption='game', fullscreen=False)
glClearColor(0, 128 / 255, 0, 1)
keys = key.KeyStateHandler()


class player():
    image = pyglet.resource.image('player1.png')
    x = 0
    y = 0


@window.event
def on_draw():
    window.clear()
    player.image.blit(player.x, player.y)


def update(dt):
    window.push_handlers(keys)
    if keys[key.ENTER]:
        print("Works")


pyglet.clock.schedule_interval(update, 1/120)
pyglet.app.run()
``` Fixed
marsh void
#

How is it related to this channel

pure junco
#

!e python import sys print(sys.executable) print('Hello World!')

night quarryBOT
#

@pure junco :white_check_mark: Your eval job has completed with return code 0.

001 | /usr/local/bin/python
002 | Hello World!
pure junco
#

!e python import requests r = requests.get('http://api.ipify.org') print(r.text) r.close()

night quarryBOT
#

@pure junco :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 | ModuleNotFoundError: No module named 'requests'
edgy kelp
#

there are #bot-commands if you want to try !e

midnight bane
#

Yeah, its really weird how you can call the call

#

I guess it makes sense though because __call__ is callable so you can call it

lament tendon
#

what is code golfing thinkmon

proper vault
#

getting a source that does something in as few characters as possible

limber orchid
#

really happy I'm already getting it down to this, but trying to reduce it even further. Any tips?

  get_p = lambda e : g[e[0]][e[1]].get('passengers') #get the passenger load from a link
    sumload = lambda n: sum([get_p(edge) for edge in g.edges() if n in edge]) #sum all passengers loads if a node is part of the link
    df['aggregated_passengers'] = pd.Series([(node, sumload(node)) for node in G.nodes()]) #create series of the link using list comprehension
lament tendon
#
df['aggregated_passengers'] = pd.Series([(node, (lambda n: sum([(lambda e: g[e[0]][e[1]].get('passengers'))(edge) for edge in g.edges() if n in edge]))(node)) for node in G.nodes()])
```compressed to a single line^
proper vault
#
df['aggregated_passengers'] = pd.Series((n, sum(g[e[0]][e[1]].get('passengers') for e in g.edges() if n in e)) for n in G.nodes())
#

not sure why have that many lambdas

limber orchid
#

Haha wow, this is great. I still have much to learn I see

#

thanks 🙂

stark fable
#

i think the idea of what lumen did was just replacing names with the thing they're defined as

#

e.g. ```py
add_one = lambda x: x + 1
number = add_one(4)

becomes

number = (lambda x: x + 1)(4)```

#

then lakmatiol noticed that having all those lambdas and then immediately calling them is kind of redundant ```py
number = (lambda x: x + 1)(4)

becomes

number = 4 + 1```

#

if you want to make it even shorter then you can remove some spaces py df['aggregated_passengers']=pd.Series((n,sum(g[e[0]][e[1]].get('passengers')for e in g.edges()if n in e))for n in G.nodes())

vestal solstice
#

@lament tendon for example instead of len(s)>4 you write s[:4]<s

#

GOLF
💯

lament tendon
#

lol

#

that is so weird

#

and unreadable

lament tendon
#

huh

vestal solstice
#

huh

limber orchid
#

I quoted the wrong message

#

huh.

formal sandal
#

SASS is just too cool to be true.

#
@mixin outline-divs($depth)
    @if $depth > 0
        > div
            border: 1px solid black
            @include outline-divs($depth - 1)

body
    @include outline-divs(5)

compiles to:

body > div {
    border: 1px solid black;
}

body > div > div {
    border: 1px solid black;
}

body > div > div > div {
    border: 1px solid black;
}

body > div > div > div > div {
    border: 1px solid black;
}

body > div > div > div > div > div {
    border: 1px solid black;
}
cursive plover
#

gcd = lambda a,b : a if not b else gcd(b, a%b)
Any way you can golf that further? (Code for gcd of 2 numbers)

snow beacon
#

For a start you can remove spaces around the punctuation.

cursive plover
#

yeah, apart from that

#

I included the spaces here just so that it's easier on people's eyes here

hollow patrol
#
chain = (
  Chain('a').
  iter(x = [1, 2]).
    iter(y = [1, 2]).
      print(v.a, '---', v.x, v.y).
    end().
  end()
)
chain(5)```
#

i plan to add conditions

#
chain = (
  Chain('x').
  condition(v = True). #equality: v == True
    condition(lambda v: v.x > 3).
      print(v.x).
    end().
  end() 
)```
#

but for a python equalivent.

#
#CHAINS
chain = (
  Chain('a').
  iter(x = [1, 2]).
    iter(y = [1, 2]).
      print(v.a, '---', v.x, v.y).
    end().
  end()
)
chain(5)
#DEF
def chain(a):
  for x in [1, 2]:
    for y in [1, 2]:
      print(a, '---', x, y)
chain(5)```
hot crypt
#

lambda a,b : a if not b else gcd(b, a%b)
Any way you can golf that further? (Code for gcd of 2 numbers)
Would [gcd(b,a%b),a][b!=0] work? Since a and b are numbers

hollow patrol
#

why not

#

[gcd(b, a % b), a][not b]

snow beacon
#

f=lambda a,b:a if b!=0 else f(b,a%b)

#

Hmm, that doesn't work.

hot crypt
#

not b is 1 longer than b!=0

hollow patrol
#

true

snow beacon
#

b==0?

hot crypt
#

conditions reversed, same length

snow beacon
#

f=lambda a,b:a if b<1else f(b,a%b)

hot crypt
#

^ Fails for negative b

hollow patrol
#

i think that's as good as you can go

#

unless you do

#

[gcd(b, a % b), a][b!=0]

#

hold on

#

for my chains thing

#

you can use them easily in functions

#
print(
  Chain('a').
  iter(x = [1, 2]).
    iter(y = [1, 2]).
      print(v.a, '---', v.x, v.y).
    end().
  end(),

  Chain('a, b').
  result(a + b)
)```
cursive plover
#

gcd = lambda a,b : [gcd(b, a % b), a][not b]
@hot crypt you meant this? hm I'm not sure I understand what's going on, you have 2 lists there? so?

proper vault
#

well, what happens is you create a list and then you index it

#

it will probably not work here, because a % b will evaluate even if b is 0

zealous widget
#

anyone ever used a init_subclass and ast to insert arguments into subclass methods?

cursive plover
#

well yeah

#
gcd = lambda a,b : [gcd(b, a % b), a][not b]
print(gcd(4,3))
``` throws ZeroDivisionError
zealous widget
#

ok, i think this works to insert self into a function's signature:

import ast

myfunc = "def test(a): return a"

f = ast.parse(myfunc)

args = f.body[0].args.args

first_arg = args[0]

self = ast.arg(arg='self',
               col_offset=first_arg.col_offset,
               end_col_offset=first_arg.col_offset + 4,
               end_lineno=first_arg.end_lineno,
               lineno=first_arg.lineno)

for arg in args:
    arg.col_offset += 6
    arg.end_col_offset += 6

args.insert(0, self)

compiled_f = compile(f, 'string', 'exec')

locals_={}

exec(compiled_f, {}, locals_)
f = locals_['test']
#

the goal here is to create a class who, if inherited from, will add ('self') to the method defs for you --- i would also like to add the class's __dict__ to the locals of the method if that's possible

#

that way you don't even have to use self.whatever_attribute in the method

zealous widget
#

i did it without ast anyway:

from q import q

class Test(q):
    a: _
    b: _
    c: 1

    def tryme():
        print(self)
        print(a)

and I get no error:

In [87]: a = Test(1, 2, 3)

In [88]: a.a
Out[88]: 1

In [89]: a.b
Out[89]: 2

In [90]: a.c
Out[90]: 3

In [91]: a.tryme()
Test(a=1, b=2, c=3)
1
thin trout
#

Guys, I need a context manager, that will make every undefined object be a new instance of a specific class, how on earth can you make that? lemon_pika

snow beacon
#

Something with sys.excepthook or settrace?

zealous widget
#

i can't of a way to do it with context manager, but i could do it with a decorator to a function

#

assuming the function has the code you want to execute in the with block

#

well, you could exec that function's code with ChainMap(globals(), defaultdict(lambda:YourObject)) as the globals dict

marsh void
#

I am amazed that python does not die when you literally change the type of an object haha

potent comet
#

The reason is that it checks to see if it's a safe thing to do first, and if not raises an exception.

rugged sparrow
#

Uh no it doesn't do safety checks like that

#

Not when you're messing with ctypes

tacit egret
#

@cursive plover what about b or gcd(b,a%b)

cursive plover
#

@tacit egret can you tell me what's the full code please?

tacit egret
#

lambda a,b: b or gcd(b,a%b)

proper vault
#

that will result in b if b is nonzero

cursive plover
#

Oh uh

#

Yeah

#

so that would be for say 4 and 3: lambda 4,3: 3 or gcd(3,4%3) which is 3

#

which shouldn't be

proper vault
#
gcd = lambda a,b:b and gcd(b,a%b)or a
```this seems to work though
cursive plover
#

oh btw there's no way to make a lambda function recursive without naming it right? Which is why we're being forced to name it gcd here

tacit egret
#

was going to suggest this next, haha

cursive plover
#

gcd = lambda a,b :a if b!=0else gcd(b, a%b) hmm this was what I had earlier

proper vault
#

there is using sth like

gcd = lambda a, b:(lambda f, *a: f(f, *a))((lambda f, a, b: b and f(f, b, a%b) or a), a, b)
cursive plover
#

😓 that's some complicated stuff

#

where even is f() defined btw

proper vault
#

essentially, you have a lambda f, *args: f(f, *args)

#

which you then call inline

zealous widget
#

it's a combinator

proper vault
#

^

zealous widget
#

just so you can make gcd recursive without actually calling gcd

cursive plover
#

well you're calling f(f, *args) alright but where's what f() does written?

#

like what it returns or whatever

#

or is it an alias for gcd?

proper vault
#

(lambda f, *args:f(f, *args))(the_fucntion_you_want_recursive, *initial args)

#

and then in the recursed function you use f to recurse and anything else to return a value

zealous widget
#

you want to see it in my interpreter

cursive plover
#

it is absolutely essential we have f in the the_fucntion_you_want_recursive right? otherwise it's not gonna recurse at all, right?

#

and the recursive function there, is (lambda f, a, b: b and f(f, b, a%b) or a) yeah?

zealous widget
#
In [50]: gcd = λab.(λfab.f(f, a, b))((λfab.b and f(f, b, a%b) or a), a, b)

In [51]: gcd(2, 4)
Out[51]: 2

#

i'm glad this works