#esoteric-python
1 messages · Page 31 of 1
This is actually pretty new, was working fine in 3.9 as far as I recall correctly
Really doubt that. I think its even in Python2
Python really wants to keep track of which variables are local or not
Ye I just checked, it is an error even as far back as Python 2.7.18 (and probably much further back than that)
Then I messed something up
this is trying to update a global in a function. you should avoid that in any case.
definitely don't use .__iadd__(), though this is esopy, so all the rules are out the window
It is relatively common to see people do .append to a non-local list. I don't think there is anything wrong with that
i don't know what you mean by "relatively common". Modifying globals from within functions is rare.
I'm talking about Python implementations of algorithms and data structures. I would say it is a relatively common to see people do .append to non-local lists there.
A basic example would be building graphs
For example this is a natural way to build directed graphs with capacities (used for max-flow)
V = []
C = []
F = []
def add_edge(u, v, cap, rcap = 0):
V.append(v)
V.append(u)
C.append(cap)
C.append(rcap)
maybe we are talking about different things: small self-contained examples vs production code.
I'm definitely the small self-contained examples kind of guy
ok, that explains it.
my production code is exclusively global variables using interior mutability, also dunders
well there's a reason
global A
exists
makes a note to avoid Olivia's code :)
although if the functional exact equivalent has to add this in order to do whatever you're doing then whatever you're doing is probably not the best idea for good code
shit like this is why i don't enjoy python as much as other languages
the scope definition of certain things is wonky at best
python often tries to implement some things, which prohibit unwished behaviour. Same as sum(Iterable[str], begin="")
So it would work, but is a bad practice and so python says nuh uh
!e just as bad and not prevented :)
from functools import *
x = ["foo", "bar", "bat"]
print(reduce(str.__add__, x))
@restive void :white_check_mark: Your 3.11 eval job has completed with return code 0.
foobarbat
!e this is what I call the f'in hell
import time
_f = time.sleep
_f_ = int
f = _f_(f"5")
_f(_f_(_f_(_f_(f"{f'{_f_(f)}'}"))))
@true basalt :warning: Your 3.11 eval job has completed with return code 0.
[No output]
!e
A = [0,0,0,0]
x = A[x] = 3
print(A)```
@mint rain :white_check_mark: Your 3.11 eval job has completed with return code 0.
[0, 0, 0, 3]
Wait..what? Why it does not raise an error?
this is why i love python
only learned this trick bc i saw it somewhere up in this channel
x[i] = i idk when ill use it tho
Even chatgpt is confused) Looks like Mandela effect to me
Oh, I wouldn't be so sure:)
!e
A = [0,0,0,0,0,0,0,0]
x = A[x] = 3
print(A)```
@turbid dragon :white_check_mark: Your 3.11 eval job has completed with return code 0.
[0, 0, 0, 3, 0, 0, 0, 0]
ahhh
Guys, does anybody know a way how to override getting attribute in super class (when calling super().attribute?
I tried
class Meta(type):
def __getattr__(cls, key):
print('meta getattribute', key)
return None
class Parent(metaclass=Meta):
def __getattr__(cls, key):
print('parent getattribute', key)
return None
class Child(Parent):
def foo(self):
super().foo()
child = Child()
child.foo()
But I get AttributeError: 'super' object has no attribute 'foo'
is this to solve a real problem, or to do esoteric things?
It is real. I want to have a cooperative parent class (aka root) which I always can include as a last Mixin, so if a sibling calls super().something() the code will not crash
hmm, i'm not sure how to do that.
how can I space words in python
import re
text = "hellobrotherhowareyou"
# Split the string into words based on camelCase or PascalCase conventions
split_text = re.findall(r'[A-Za-z][a-z]*', text)
# Join the words with a space between them
spaced_text = " ".join(split_text)
print(spaced_text)
``` I asked an ai but it just printed "hellobrotherhowareyou"
read the comment it included for you. Is that what you wanted?
also, who is to say what are words? These are both reasonable answers: "hello brother how are you" and "hello bro the rho ware you"
!e
(hgjntyr5bu6f56htgr79b8nyfj65htg79bn8jryf:=lambda:(u7oiyghtvbu89hybg7ijo:={},bhjnm_kg:=3,EeeeeeeeeEeeeeeeeeeEeeeeeeeeeeEeeeeeeeeeeeeeeeEeeeeeeeeeeeEeeeeeeeeeEeeeeeeeeEeeeeeeeee:=5,Htgjryu5f6i:="fizz",V5c67bgFsuxizjtd3475Vvc:="buzz",u7oiyghtvbu89hybg7ijo.__setitem__(bhjnm_kg, Htgjryu5f6i),u7oiyghtvbu89hybg7ijo.__setitem__(EeeeeeeeeEeeeeeeeeeEeeeeeeeeeeEeeeeeeeeeeeeeeeEeeeeeeeeeeeEeeeeeeeeeEeeeeeeeeEeeeeeeeee, V5c67bgFsuxizjtd3475Vvc),func_func_func_for_func_funcfuncfunc_vbcgdfxhe4:=lambda S7c4ALBz8WjVBNse5raIrfKzyrGwiDXAWjUmuwsG: ''.join([u7oiyghtvbu89hybg7ijo[DdzlL7BsfRlW0TqER0HV5JDd3j7uu750AefzOB2k] for DdzlL7BsfRlW0TqER0HV5JDd3j7uu750AefzOB2k in u7oiyghtvbu89hybg7ijo if not(S7c4ALBz8WjVBNse5raIrfKzyrGwiDXAWjUmuwsG%DdzlL7BsfRlW0TqER0HV5JDd3j7uu750AefzOB2k)]) or str(S7c4ALBz8WjVBNse5raIrfKzyrGwiDXAWjUmuwsG),list(map(print, map(func_func_func_for_func_funcfuncfunc_vbcgdfxhe4, range(1, 101)))),None)[-1])()
@karmic pumice :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | 1
002 | 2
003 | fizz
004 | 4
005 | buzz
006 | fizz
007 | 7
008 | 8
009 | fizz
010 | buzz
011 | 11
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/F5OP6MVIZRMK5CC2RG4WRCO3QU
time.sleep(5)
your regex looks for an uppercase letter, then any amount of lowercase letters
so HelloBrotherHowAreYou would be processed correctly
splitting a string just based on words is hard if not impossible to do without ai
we as humans have previous experience with words and, more importantly, misspelling of words, which is why you can read hellobroterhowru
how do you tell a computer to read that
just taking a wordlist and using that to split the string also wouldnt work properly, since certain words in that wordlist may appear in the string you want to split, where it contextually wouldnt make sense
eg hireggie might be recognized as "hire ggie"
that's the entire point of even using ai, letting the computer figure out how to do it for us
so ai might be your best bet here, but it'd still be hard to train and use a neural net in the first place
The task is also fundamentally impossible to do unambiguously, AI or not. There are many strings that can be split in several legitimate word lists.
E.g. "nappythonghost" could be nap-python-ghost or nappy-thong-host.
also the regex from the ai's answer would not do that, the corect one would be: '[A-Z][a-z]*' (i think)
The one they use would work as well, and it could then also split someCamelCaseWords
o really? man regex is confusing
It's because * is greedy by default. If it was *? you'd be right
(but then it wouldn't correctly get the words)
!e
def wrapper(*args, **kwargs):
return None
def root():
class MetaRoot(type):
def new(cls, *args, **kwargs):
if args:
for c in args[1][:-1]:
methods = [m for m in c.dict if not m.startswith('')]
for m in methods:
setattr(args[1][-1], m, wrapper)
return super().__new(cls, *args, **kwargs)
return MetaRoot('Root', (), {})
class Parent:
pass
class Child:
def foo(self):
return super().foo()
class Mixed(Child, Parent, root()):
pass
m = Mixed()
print(m.foo())
The only way I have found till now is this
UDP: strange, in works in python 3.10 on my local
@sonic birch :x: Your 3.11 eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "/home/main.py", line 23, in <module>
003 | print(m.foo())
004 | ^^^^^^^
005 | File "/home/main.py", line 19, in foo
006 | return super().foo()
007 | ^^^^^^^^^^^
008 | AttributeError: 'super' object has no attribute 'foo'
what on earth
if you're feeling adventurous, could try replacing super 🙃
something like this to start off with
!e
import builtins
import sys
def patched_super():
caller_locals = sys._getframe().f_back.f_locals
self = caller_locals['self']
cls: typing.Type = caller_locals['__class__']
parent = cls.mro()[1]
parent_getattr = parent.__getattr__
class Proxy:
def __getattribute__(proxu_self, item):
return parent_getattr(self, item)
return Proxy()
builtins.super = patched_super
class Parent:
def __getattr__(self, item):
print('parent getattr', item)
return None
class Child(Parent):
def foo(self):
super().foo()
child = Child()
child.foo()
@brazen geyser :x: Your 3.11 eval job has completed with return code 1.
001 | parent getattr foo
002 | Traceback (most recent call last):
003 | File "/home/main.py", line 30, in <module>
004 | child.foo()
005 | File "/home/main.py", line 26, in foo
006 | super().foo()
007 | TypeError: 'NoneType' object is not callable
Make sure to really call the patched super super though or it will not work ;)
You suggest overridinng built-in's super? Looks not safe for other parts of project where this behaviour is not needed
!e
def wrapper(*args, **kwargs):
return None
def root():
class MetaRoot(type):
def __new__(cls, *args, **kwargs):
print(args)
if args:
for c in args[1][:-1]:
methods = [m for m in c.__dict__ if not m.startswith('_')]
for m in methods:
setattr(args[1][-1], m, wrapper)
return super().__new__(cls, *args, **kwargs)
return MetaRoot('Root', (), {})
class Parent:
pass
class Child:
def foo(self):
return super().foo()
class Mixed(Child, Parent, root()):
pass
m = Mixed()
print(m.foo())
Fixed!
@sonic birch :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | ('Root', (), {})
002 | ('Mixed', (<class '__main__.Child'>, <class '__main__.Parent'>, <class '__main__.Root'>), {'__module__': '__main__', '__qualname__': 'Mixed'})
003 | None
!e
from ctypes import (
py_object as PyObject_p,
c_int as int32_t,
c_ssize_t as Py_ssize_t,
sizeof as sizeof,
)
true = True
false = False
true_v = int32_t.from_address(
id(true) + sizeof(Py_ssize_t * 2) + sizeof(PyObject_p)
)
false_v = int32_t.from_address(
id(false) + sizeof(Py_ssize_t * 2) + sizeof(PyObject_p)
)
print(f"""\
before change:
{true_v = }
{false_v = }
""")
true_v.value = 0
false_v.value = 1
print(f"""\
after change:
{true_v = }
{false_v = }
""")
print(f"""\
True: {+true}
False: {+false}
""")
@versed eagle :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | before change:
002 | true_v = c_int(1)
003 | false_v = c_int(0)
004 |
005 | after change:
006 | true_v = c_int(0)
007 | false_v = c_int(1)
008 |
009 | True: 0
010 | False: 0
why doesnt the value of false change also?
!e booleans are a subclass of int, so they have a ob_size field as well. You would need to change that (ignoring the fact that internally python checks bools by identity and not value)
from ctypes import *
class Boolean(Structure):
_fields_ = [
('ob_refcnt', c_ssize_t),
('ob_type', py_object),
('ob_size', c_ssize_t),
('bool_val', c_int)
]
def __repr__(self):
ob_refcnt = self.ob_refcnt
ob_type = self.ob_type
ob_size = self.ob_size
bool_val = self.bool_val
return f'Boolean({ob_refcnt=}, {ob_type=}, {ob_size=}, {bool_val=})'
T_struct = Boolean.from_address(id(True))
F_struct = Boolean.from_address(id(False))
print(f'{T_struct = }')
print(f'{F_struct = }')
T_struct.bool_val = 0
F_struct.ob_size = 1
F_struct.bool_val = 1
true, false = True, False
print(f"""\
True: {+true}
False: {+false}
""")
@rugged sparrow :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | T_struct = Boolean(ob_refcnt=56, ob_type=<class 'bool'>, ob_size=1, bool_val=1)
002 | F_struct = Boolean(ob_refcnt=79, ob_type=<class 'bool'>, ob_size=0, bool_val=0)
003 | True: 0
004 | False: 1
i know they're checked by identity and not value
that's why i used + to convert it to an int for printing and whatnot
why does the size need to be changed though
im not increasing it past 2**32 -1
if ob_size is zero, there is assumed to be no numerical data to calculate the value.
there are several shortcuts for zero (and False) that use ob_size being zero as a flag
Is there a clear academic distinction between the terms "parameters" and "arguments"?
We have function "parameters," but "keyword arguments", *args, and **kwargs
This doc uses both terms
https://docs.python.org/3/reference/compound_stmts.html#function-definitions
Is it a parameter in the function declaration, and an argument at the call-site?
For a parameter with a default value, the corresponding argument may be omitted from a call, in which case the parameter’s default value is substituted.
A parameter is a variable in a function definition. It is a placeholder and hence does not have a concrete value. An argument is a value passed during function invocation.
answered my own question
@dry mirage have you had any issues updating einspect's hooking capability to 3.12+?
i think my setattr trick is broken
i think all of my C extensions are gonna break in 3.12
that's not good
should've listened to godlygeek
i figured it out, setattr expects normal dict locations and now the internal types have their dicts stored in a different location
all of my bytecode things too
oh yea those are gonna break hard
you mean the TPFLAGS_IMMUTABLETYPE unlock?
thought that still worked last I tried 
there is some funky stuff involving type dicts now
the managed instance dictionary?
yea
i think?
in my testing at one point it manifested a second instance dict for int
one that had my hooks and one that it had before hand
setattr when tp_dict is null seems to manifest a dict, even if the type has a managed dict stored in the interpreter state
I had to do some logic for it for the einspect << move to actually move the instance dict as well https://github.com/ionite34/einspect/blob/main/src/einspect/structs/py_object.py#L248
src/einspect/structs/py_object.py line 248
def instance_dict(self) -> ptr[PyObject[dict, Any, Any]] | None:```
i just fixed mine to clear out the manifested dict so that the class state remained consistent
probably not the best solve but itll work
wonder if it affects c extension types as well, might be an upstream bug in setattr
it shouldn't since the only reason these types were broken is because they have cached dicts that are shared across interpreters
oh yeah definitely super unsafe. and potentially a fun #esoteric-python adventure. :)
https://github.com/python/cpython/blob/main/Objects/typeobject.c#L224-L229 this is where the issue begins to manifest
Objects/typeobject.c lines 224 to 229
if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
PyInterpreterState *interp = _PyInterpreterState_GET();
static_builtin_state *state = _PyStaticType_GetState(interp, self);
assert(state != NULL);
return state->tp_dict;
}```
since its an internal type flag _Py_TPFLAGS_STATIC_BUILTIN i don't think its a bug in setattr
i dont understand lol
>>> (lambda:(lambda t:t(None,f).run())(t:=__import__("threading").Thread),t(None,f).run())()
<stdin>:1: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma?
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 't' is not defined
>>>
in what place is it not defined
wait
i think i realised what was wrong
, has higher priority
so you need to put () around lambda's code
I'm trying to implement __setattr__ for a class that also uses getters and setters using the property class with the following implementation:
def __setattr__(self, name: str, value):
if isinstance(value, property) or callable(value):
super().__setattr__(name, value)
else:
getattr(self, "__dynamic_set_"+name)(self, self, value)
The __dynamic_set_ function is a predefined setter function that is used in conjunction with the property() class. The issue is that when i set the variable with setattr and i print said variable, the output will always be <property object at 0x*********>.
The getattr portion works perfectly fine in another portion of the script. What on earth am I doing wrong here?
a little bit unrelated but why do you pass self twice into the dynamic set?
can you provide more context
like, an example usecase
and what you want it to do vs. what it does
I'm trying to implement a class that will keep track of certain modified variables. Basically: You add a property using the following function def __add_tracked_property(self, property_type, property_name, property_value=None), and it automagically creates the variable, including the property() statement in order to add a setter that will keep track of modified variables.
The specific usecase is a generic API client that will self-populate it's variables. In order to save on bandwidth/database usage, I only want to send variables that have been modified without bothering the end-user/programmer with keeping track of everything
Because of the dynamic nature of it all, I still need access to setattr without overriding the property() instance.
call .__set__ on the property instance
directly
at least, thats what it sounds like you want
So basically replace the getattr line with getattr(self, name).__set__(self, value)?
if its a property
yeah
property objects have __set__ and __get__ for managing themselves
def __setattr__(self, name: str, value):
if hasattr(self, name) and isinstance(getattr(self, name), property):
getattr(self, name).__set__(self, value)
else:
super().__setattr__(name, value)
More like this then?
Because that does not work either, and i still get just the <property object at 0x****> when i print
you still havent explained to me what you actually want to do
.
.
As stated before, i want to be able to use the property class in conjunction with setattr.
If I assign a setter for a certain variable, and use setattr(obj, thatcertainvariable, somevalue), it will override the property that was just assigned, and replace it with the actual value
I want to be able to use setattr on all variables, property or normal variable
the idea behind the class isn't the most relevant; what i need to know is
- what the intended behaviour of your function is
- what it actually does
- an example usecase of this, so i can see how the function is being invoked
Hang on, debugging atm. Something is not quite right
Not twice, but three times! 1st is bounded by method, two more are passed as arguments
we don't know that its a bound method!
could be a static or class method ;)
That one is a bit weird, i know. Give me a minute 😛 Aparently the setter is not being registered somehow
Somehow in a refactor, it broke. Not sure why -_-
So the setter was never called. I'll post a full code example in a minute, with the reasoning behind it 😛
Riiiight..... I'm just kinda running in circles 😛
class DynamicVariableMixin():
'''
Used to be able to store and keep track of dynamic variables
'''
_updated_vars=None
_dynamic_variables = {}
def __add_method__(self, property_type, property_name):
def set_attribute(self, obj, property_value, **kwargs):
print("Setting")
try:
if property_type == type(property_value):
self._dynamic_variables[property_name] = property_value
else:
raise TypeError
finally:
pass
def get_attribute(self, *args, **kwargs):
return self._dynamic_variables[property_name]
setattr(self.__class__, '__dynamic_set_'+ property_name, set_attribute)
setattr(self.__class__, '__dynamic_get_'+ property_name, get_attribute)
setattr(self.__class__, property_name,
property(
getattr(self, '__dynamic_get_'+ property_name),
getattr(self, '__dynamic_set_'+ property_name)
)
)
def __add_tracked_property__(self, property_type, property_name):
self.__add_method__(property_type, property_name)
This works, only on a class level (which i dont want because of obvious reasons). When i remove the .__class__ from setattr in order to set the getter/setter, it completely breaks and no longer uses the getter/setter
Implementation example:
class Test(DynamicVariableMixin):
a = "Hello"
t1 = Test()
t2 = Test()
t1.__add_tracked_property__(str, "myvariable")
t1.myvariable = "Hello!"
print(t2.myvariable)
t2.myvariable currently resolves without any issue to "Hello!", which shouldn't happen.
Why the convoluted mess? I'm declaring some classes dynamically using input from an API. Object properties are set dynamically using the API response, and kept track of using the class above (WIP of course).
This is so the end-user/programmer does not have to fiddle with keeping track of modified properties of said object/instance when saving (patching) back to the API
Why are you even setring __dynamic_set/get attributes? You are not using them
!e ```py
n = 15
s = f'<{n}>'
while True:
# print(f'{s} [{len(s)}]')
if '|0' in s:
s = s.replace('|0', '0||||||||||', 1)
elif '.>' in s:
s = s.replace('.>', '>', 1)
elif '.|' in s:
s = s.replace('.|', '-.', 1)
elif '0-' in s:
s = s.replace('0-', '1', 1)
elif '1-' in s:
s = s.replace('1-', '2', 1)
elif '2-' in s:
s = s.replace('2-', '3', 1)
elif '3-' in s:
s = s.replace('3-', '4', 1)
elif '4-' in s:
s = s.replace('4-', '5', 1)
elif '5-' in s:
s = s.replace('5-', '6', 1)
elif '6-' in s:
s = s.replace('6-', '7', 1)
elif '7-' in s:
s = s.replace('7-', '8', 1)
elif '8-' in s:
s = s.replace('8-', '9', 1)
elif '9-' in s:
s = s.replace('9-', '-0', 1)
elif '<-' in s:
s = s.replace('<-', '<1', 1)
if '-' not in s:
break
elif '9' in s:
s = s.replace('9', '8|', 1)
elif '8' in s:
s = s.replace('8', '7|', 1)
elif '7' in s:
s = s.replace('7', '6|', 1)
elif '6' in s:
s = s.replace('6', '5|', 1)
elif '5' in s:
s = s.replace('5', '4|', 1)
elif '4' in s:
s = s.replace('4', '3|', 1)
elif '3' in s:
s = s.replace('3', '2|', 1)
elif '2' in s:
s = s.replace('2', '1|', 1)
elif '1' in s:
s = s.replace('1', '0|', 1)
elif '00|' in s:
s = s.replace('00|', '0|', 1)
elif '0|' in s:
s = s.replace('0|', '0.||', 1)
else:
assert 0
n = int(s[1:-1])
print(n) # 16
@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.
16
Markov algo that does x+1
It isnot the best markov algo for this task, it can be a lot simpler (so it is kinda esoteric 😝)
(and it is bugged for some numbers)
(strictly speaking it is not a markov algo because of custom termination behaviour, but im too lazy to fix it)
They are used when setting property, using another setattr call
You are setting these values and immediately using them, which is equivalent to not setting them at all
Right. Corrected that with
setattr(self.__class__, property_name,
property(
get_attribute,
set_attribute
)
)
Only issue now is that with the code above, object t2 still has the myvariable attribute due to the self.__class__ being used in setattr. If i remove the __class__, the property is somehow being overwritten when i assign a new value. The Setting in set_attribute never gets printed
What does that do?
adds one to n
Exactly
Why Not n += 1
Because it is wrong channel for n+=1
True
!e ```py
def foo():
for a in [1,2,3]:
print(a)
for a in "abc":
print(a)
def trace(fr, ev, arg):
if fr.f_lineno == 3: fr.f_lineno = 5
return trace
import sys
sys.settrace(trace)
foo()
@proper vault :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | 1
002 | 2
003 | 3
Works in 3.9. Before it would complain about being unable to jump inside of a loop?
if fr.f_lineno == 3: fr.f_lineno = 5
ValueError: can't jump into the middle of a block
ye
Funnily it still does this sometimes
!e first a variant to show a bit more what's going on:
def foo():
for a in [1,2,3]:
print(a, "is a number")
for a in None:
print(a, "is a None?")
def trace(fr, ev, arg):
if fr.f_lineno == 3:
fr.f_lineno = 5
fr.f_trace = None
return trace
import sys
sys.settrace(trace)
foo()
@restive void :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | 1 is a None?
002 | 2 is a None?
003 | 3 is a None?
yeah, the entire block stack must match to allow the jump, or you must be jumping out of a block
Block stack?
block stack as in nested blocks, where a block is a for loop, with handler, etc
!e if the first loop has a break it seems to, well, break:
def foo():
for a in [1,2,3]:
print(a, "is a number")
break
for a in None:
print(a, "is a None?")
def trace(fr, ev, arg):
if fr.f_lineno == 3:
fr.f_lineno = 6
fr.f_trace = None
return trace
import sys
sys.settrace(trace)
foo()
@restive void :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | 1 is a None?
002 | 2 is a None?
003 | 3 is a None?
huh. At least on 3.9 it does, whereas the previous code works
IG no one really checks debugger jumps for backwards compat
or even debuggers in general tbh
There are tests
ye, they get updated every version to match the behaviour of the new version
the code for checking jumps is about here ish https://github.com/python/cpython/blob/3.10/Objects/frameobject.c#L124
Objects/frameobject.c line 124
markblocks(PyCodeObject *code_obj, int len)```
or well, the interesting part
(That reminds me, I should add a link to my talk on our internal company wiki now that the videos were released)
you did a talk?
Yeah, back in May, at PyCon Italia; about debuggers (live-coding a tiny one): https://www.youtube.com/watch?v=Cl6U9VoPn_M
noice
!e
def weird(l):
return max(list(filter(lambda x: x % 2 != 0, (sum(n) for n in zip(*l)))) or [0])
print(weird([[1, 2, 3], [7, 8, 9]]))
print(weird([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
print(weird([[1, 2, 3], [4, 5, 6], [7, 8, 9], [9, 10, 11]]))
@calm cove :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | 0
002 | 15
003 | 29
This finds the largest odd sum of integer values of a column in a 2d list. The tricky part was figuring out how to do the check for the case of no uneven number and then use [0] instead. My initial approach of
intermediary = filter(lambda x: x % 2 != 0, (sum(n) for n in zip(*l)))
list(intermediary) if list(intermediary) != [] else [0]
or anything similar to that did not work as the call list() on the filter object, which is an iterator consumes it. And because you can't assign variables in a lambda function, I had to use
list(intermediary) or [0]
because bool(list(intermediary)) is False in the case that intermediary is empty. So then [0] is used
!e
def weird(A):
return max((sum(col) for col in zip(*A) if sum(col) % 2), default = 0)
print(weird([[1, 2, 3], [7, 8, 9]]))
print(weird([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
print(weird([[1, 2, 3], [4, 5, 6], [7, 8, 9], [9, 10, 11]]))
I would have probably just done something like this ^.
@distant salmon :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | 0
002 | 15
003 | 29
is there a way to build this list using a list comprehension? maybe using the walrus operator?
new_lst = []
prev = 0
for i in lst:
new_lst.append(i + prev)
prev = i
>>> lst
[1, 1, 4, 1, 6, 1, 1, 3, 1, 3, 1, 4]
>>> new_lst
[1, 2, 5, 5, 7, 7, 2, 4, 4, 4, 4, 5]
Bruh
!e ```py
l = [1,1,4,1,6,1,1,3,1,3,1,4]
l2 = [*map(int.add, l, l[1:]+[0])]
print(l2)
@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.
[2, 5, 5, 7, 7, 2, 4, 4, 4, 4, 5, 4]
Almost
!e ```py
l = [1,1,4,1,6,1,1,3,1,3,1,4]
l2 = [*map(int.add, l, [0]+l[:-1])]
print(l2)
@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.
[1, 2, 5, 5, 7, 7, 2, 4, 4, 4, 4, 5]
Fixed
wait maybe itertools has something
oh nice
do you think there is a more eficcient solution? that maybe avoids copying the list?
Yeah, itertools.tee can dupe list iterator, then you can prepend 0 to one of them and iterate over using map
Idk how map behaves on inputs of unequal length
!d map
map(function, iterable, *iterables)```
Return an iterator that applies *function* to every item of *iterable*, yielding the results. If additional *iterables* arguments are passed, *function* must take that many arguments and is applied to the items from all iterables in parallel. With multiple iterables, the iterator stops when the shortest iterable is exhausted. For cases where the function inputs are already arranged into argument tuples, see [`itertools.starmap()`](https://docs.python.org/3/library/itertools.html#itertools.starmap).
Strange that it didn't also get a strict kwarg
there is itertools.pairwise but the default element for the first pair is the same element (and you cant override it apparently)
!e ```py
import itertools as it
l = [1,1,4,1,6,1,1,3,1,3,1,4]
l2 = [*map(int.add, (i:=it.tee(l))[0], it.chain([0], i[1]))]
print(l2)
@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.
[1, 2, 5, 5, 7, 7, 2, 4, 4, 4, 4, 5]
Nice
!e
from itertools import*
l = [1,1,4,1,6,1,1,3,1,3,1,4]
l2 = [*map(sum, pairwise([0]+l))]
print(l2)
@restive void :white_check_mark: Your 3.11 eval job has completed with return code 0.
[1, 2, 5, 5, 7, 7, 2, 4, 4, 4, 4, 5]
@half escarp :white_check_mark: Your 3.11 eval job has completed with return code 0.
[2, 5, 5, 7, 7, 2, 4, 4, 4, 4, 5]
Oh, i though about starmap'ping tuples into int.add, but completely forgot about sum 😄
If you care about speed then probably just do something like this
!e
l = [1,1,4,1,6,1,1,3,1,3,1,4]
l2 = l[:]
for i in range(1, len(l)):
l2[i] += l[i - 1]
print(l2)
@distant salmon :white_check_mark: Your 3.11 eval job has completed with return code 0.
[1, 2, 5, 5, 7, 7, 2, 4, 4, 4, 4, 5]
if we're we micro-optimising, make the first one a tuple instead of a list because the tuple can be loaded as a const
then again, if we're micro-optimising, a generator or comprehension might be better than duplicating the list and then adding to it
ill go benchmark stuff once im on my computer
If we are micro-optimizing, just print the result as string because it is known beforehand
shush
lmao
if we're micro-optimising then we should use smaller variable names and less whitespace to minimise file-read and parsing times /j
Just dont do anything and imagine correct result being printed
if we precalculate and preprint the result, then wait a really long time before benchmarking it, we can have a negative runtime (endtime will be before starttime so when calculating runtime endtime-starttime will be below 0)
the longer you wait, the more performant your program is
The way I look at python is that anything in Python is slow apart from the built in stuff.
Copying a list is one of those built in operations that runs blazingly fast
However, anything involving generators is Python code and will run rather slow
I've also never seen a performance gain from using tuples over lists. I would be really surprised if that could actually make it faster.
I guess iterating over tuple can be a bit (tiny tiny bit) faster than iteration over list
Because tuple stores data in the object itself, but list allocates new memory and uses pointer to reach it
So less memory jumps => less time
!e ```py
from dis import dis
dis('x in [1,2,3]')
dis('x in {1,2,3}')
@languid hare :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | 0 0 RESUME 0
002 |
003 | 1 2 LOAD_NAME 0 (x)
004 | 4 LOAD_CONST 0 ((1, 2, 3))
005 | 6 CONTAINS_OP 0
006 | 8 RETURN_VALUE
007 | 0 0 RESUME 0
008 |
009 | 1 2 LOAD_NAME 0 (x)
010 | 4 LOAD_CONST 0 (frozenset({1, 2, 3}))
011 | 6 CONTAINS_OP 0
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/7M4V7PH5M5NCV5TLYIN6MOTZK4
Peepholes optimized these checks to not construct new list/set at runtime, so there is no difference in using literal tuples or literal lists
But in other cases if your list is known at compile time, you can use tuple instead
that's adding to a list
a list might actually iterate faster than a tuple and i still have no idea why
Does a tuple really store "data in the object itself"?
if you consider the data allocated together as a whole with the object, yes
there's one less level of indirection
they're still like converted into direct memory offsets anyway aren't they?
unless the pointer has to be loaded or something i think
AFAIR (could be wrong though) the tuple still only consists of an array of pointers. But that array is stored at the memory location of the tuple, whereas a list stores a pointer to an array somewhere else that has pointers to the actual objects (because it can be resized)
Ah ok
tuples can be LOAD_CONSTed
for i in input():d="cv"[i in"aeiouyAEIOUY"];print(end=(i,(d,d.upper())[i.isupper()])[i.isalpha()])
is it still possible to reduce length of this?
for i in input():print(end=(i,chr(b"CV"[i in"aeiouyAEIOUY"]|ord(i)&32))[i.isalpha()])
lol, thats crazy, thx
Is pre-run time normally part of benchmarking?
I think no
...this might be the wrong place to ask but this is Esoteric so here goes. I want to smash a portion of my animation and physics math AIO in a submodule named Colliction, the Color, Collision, and Projection Collection... is this too left brained?
basically it handles math functions between two tuples each less than length 4 with a factory approach
colliction is great, consider also adding another word into the mix
most of the words I would want to end in ion I would assume, but I definitwly havent actually thought of that, lol
I'm not an engineer, but I've been thinking about it for a while, and I think it could be a good educational and supplemental module
do you know what the other word is?
Consider making all the words start with "col"
infeasible, this is essentially piece-meal math functions from core and core adjacent libraries, literally the biggest problem is naming things because like, half of it might be a vector and I have numpy so what if it just supports rich comparison?
why isnt it just a tuple?
@fleet bridge I'm trying to keep semi-natural names for things so that I can use Structural Pattern Matching to make it semi-lingual
I prebake normals and my code instantly doubles in speed.
my new milestone in oneliners!
(lambda data: (Path('analysis.txt').write_text('\n'.join(f"{char} {frequency:.3f}" for frequency, chars in sorted(((frequency, sorted(map(lambda char: char[0], filter(lambda info: info[1] == frequency, data.items())), key=ord)) for frequency in set(data.values())), key=lambda group: group[0], reverse=True) for char in chars))))((lambda total_length: {letter: occurrences / total_length for letter, occurrences in __import__('collections').Counter(s).items()})(len(s := ''.join(filter(lambda c: c in __import__('string').ascii_lowercase, map(str.lower, (Path := __import__('pathlib').Path)('text.txt').read_text()))))))
and without a single ; (or even :) hehe
prob there is a way to make that shorter (aside from shortening variable names obv and removing unnecessary spaces)
(There's loads of :)
...
:= dont count
and in strings too
ah wait
There are lambda: too
lambdas'
lambda info: ...
...
yea
i forgot about existence of those
lets just uhh....
ignore('lambda') :)
One small codegolf I can see is to change the sorted(..., reverse=True) to sorted(...)[::-1]
But that would add more :

hm, indeed
but like
the original code was separated into 3-4 function calls
(functions were oneliners)
so like
lets say i only did "thin" LTO
Here is one more codegolf
c in __import__('string').ascii_lowercase
can be changed to
'`'<c<'{'
It is also possible to do ```py
'a'<=c<='z'
(Path := __import__('pathlib').Path)('text.txt').read_text() -> open('text.txt').read()
or, if its guaranteed that there's only one line in the file, *open('text.txt')
actually
why do you map str.lower
Big news! Development of hoopy is back!!!
i don't know what that is but yay!
oo you're doing codec stuff
✨
you can put the bootstrap in a .pth file and then run python3 main_hoopy.py directly
''.join(filter(lambda c: c in __import__('string').ascii_lowercase,map(str.lower, (Path := __import__('pathlib').Path)('text.txt').read_text())))
->
"".join(filter(lambda c:'`'<c<'{',open('text.txt').read().lower()))
# if the file only has 1 line, str.lower(*open('text.txt')) is shorter
I know, it is also cross incompatible and fragile
wdym by [cross incompatible]
there is no universal way to do it on install across platforms
ah
you can account for the most common use cases though
you should be able to get the correct directories via sysconfig
That's funny
sysconfig.get_path("platlib")
I guess the interpreter has to know about them
I'll probably make it an opt-in feature for the library then
there is not
hm, interesting
i actually kinda just wanted to make use of pathlib... for no reason really
because i was doing that after .splitlines() ._.
ah
where
!e
from fishhook import hook
@hook(object)
def __matmul__(self, f):
return f(self)
x = 2
sq = lambda x: x**2
x @= sq
print(x)
@humble blade :white_check_mark: Your 3.11 eval job has completed with return code 0.
4
heh
!e
from fishhook import hook
@hook(object)
def __matmul__(self, f):
return f(self)
x = 2
x @= 3 .__rpow__
print(x) # 2**3 == 8
@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.
8
I like that
!e ```py
from fishhook import *
@hook(object)
def matmul(self, func):
return func(self)
print(123 @ str @ (lambda l:map(int, l)) @ list)
print(3456 @ str @ (lambda l:map(int, l)) @ list)```
@rugged sparrow :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | [1, 2, 3]
002 | [3, 4, 5, 6]
i did it with modified cpython ```pycon
.\cpython-main\PCbuild\amd64\python_d.exe
Python 3.13.0a0 (main, Aug 15 2023, 12:02:56) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.x = 2
x @= 5 .radd
x
7
i just realized this is piping
Diving into the CPython source code can feel daunting. Whether you want to start contributing or just want to get a better understanding of Python by exploring its source code, it’s often difficult to know where to start or what you’re missing.
In my talk, I will show you around the CPython source code by implementing a new operator, a pipe ope...
ok so for some reason i couldn't have tp_as_number populated in object
and it was supposed to originally be called a "decorator operator" but i just realized it's basically a pipe operator only now
nevertheless "decorator operator" sounds cooler and rhymes better
did it cause a segfault when making subclasses?
if so you hit the same bug that is the reason for fishhook's patch_object function
*somewhere
it segfaulted while building
so i couldn't even get python to run with it
most likely the same bug
python assumes a lot of things about object when calculating method resolution and slots inheritence, and if object has one of its tp_as_* structs populated it attempts to look at its base (which normally is NULL) which causes the crash
where does it do that?
Objects/typeobject.c lines 6848 to 6851
if (type->tp_as_number != NULL && base->tp_as_number != NULL) {
basebase = base->tp_base;
if (basebase->tp_as_number == NULL)
basebase = NULL;```
basebase is never checked against being NULL
you also probably need to add the check to all of the tp_as_* sections
should it be PR'd to cpython or have you already done that?
it doesn't need to be fixed, its a correct assumption
ok then
it only breaks when you try and apply custom operations to object
yea its simple when you know where the issue is, when i was first adding support to fishhook for hooking the base object type i spent so many hours tracking down the root cause of the crash
and then more working out how to patch around the issue while maintaining stability
entering real esoteric territory now
i like that even more 👍
you seriously named version 3.13.0a0 
That's just the current version of CPython on main
huh, when did they start 3.13 dev?
Ever since feature-freezing 3.12 I'd imagine
since 3.12 had beta
well
they also did that with 3.11 beta and 3.12 dev
didn't know about it
i could make it python 4.0.0 tbh
hold on
yay ```pycon
.\cpython-main\PCbuild\amd64\python.exe
Python 4.0.0 (main, Aug 15 2023, 14:40:15) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

nah
i suppose that version has JIT, no GIL, strong 💪 typing mode, better typing system than typescript and faster than java, and has an ability to act as a systems language, am i right?
why would we want strong typing
Can anyone explain why it should work?
that doesnt work does it?
Yes, it does 
til wtf
First print is '3', second is '<class type>'
second isnt hard to explain, its just returning the class type
I tried to find more info about classes, but I dont find anything helpfull. Maybe I should try find more info about scopes
i cant behave the firsts behaviour im really not sure why it loads a global there
i get where the naming is coming from though
!e
_Animal__type = 3
class Animal():
def get_type_first(self):
return __type
def get_type_second(self):
return type
anim = Animal()
print(anim.get_type_first())
print(anim.get_type_second())
@distant salmon :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | 3
002 | <class 'type'>
its because of name mangling
i didnt realise it was as simple as a find and replace sorta thing for mangled names
Thanks a lot, I missed it when I read this first time
to be done
fix like quite a lot of bugs before even running?
Don't fall for it!
The Zen of Python must not have been invented yet because this feature is confusing, not obvious, implicit, and much more. Private name mangling in Python converts variable usages like __var into _ClassName__var at compile time and there's no warning it's happening until you run into the trap.
― mCoding with James Murphy (ht...
Good video about mangling tricks
TIL __A__.__x gets mangled to __A__._A____x
!e ```py
@lambda x: globals().update(ᅠ=x)or x
class ᅠ:
def init(_, x):
_.__x = x
print(ᅠ(...)._ᅠ____x)
@quartz wave :white_check_mark: Your 3.11 eval job has completed with return code 0.
Ellipsis
@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.
4448
!charinfo 4448
\u0034 : DIGIT FOUR - 4
\u0034 : DIGIT FOUR - 4
\u0034 : DIGIT FOUR - 4
\u0038 : DIGIT EIGHT - 8
\u0034\u0034\u0034\u0038
!charinfo ᅠ
\uffa0 : HALFWIDTH HANGUL FILLER - ᅠ
Idk
what
GOD i love python's class system
genuinely, how can you make something this convoluted
this is more a name mangling thing than anything actually related to "core" OOP
>>> from dis import dis
>>> dis(r"""
... class __A__:
... def __init__(_):
... import __a.b
... """)
...
Disassembly of <code object __init__ at 0x0000016667C8F050, file "<dis>", line 3>:
3 0 RESUME 0
4 2 LOAD_CONST 1 (0)
4 LOAD_CONST 0 (None)
6 IMPORT_NAME 0 (__a.b)
8 STORE_FAST 1 (_A____a)
10 RETURN_CONST 0 (None)
``` `__a.b` is imported in class `__A__` but the result gets stored into `_A____a`
_A____adoes not contain the class name (__A__)__a.bis left unmangled when importing, but it is stored into a mangled name (_A____a) anyway
hello I have this anti bad word system something like this
badwords = ["badword", "bad"]
message = "bad"
if badwords in message.lower():
print("true")
but people can bypass it by doing "badbad" how can I fix it
The Scunthorpe problem is the unintentional blocking of online content by a spam filter or search engine because their text contains a string (or substring) of letters that appear to have an obscene or otherwise unacceptable meaning. Names, abbreviations, and technical terms are most often cited as being affected by the issue.
The problem arises...
oh.
Ehm isnt that if statement the wrong way around?
!e
badwords = ["badword", "bad"]
message = "bad"
if badwords in message.lower():
print("true")
@distant salmon :x: Your 3.11 eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "/home/main.py", line 4, in <module>
003 | if badwords in message.lower():
004 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
005 | TypeError: 'in <string>' requires string as left operand, not list
Ye it is. You should have
!e
badwords = ["badword", "bad"]
message = "bad"
if message.lower() in badwords:
print("true")
@distant salmon :white_check_mark: Your 3.11 eval job has completed with return code 0.
true
That's will catch only messages that are bad entirely
"very bad badword!" will not be captured
!e
badwords = ["badword", "bad"]
message = "bad".lower()
for bw in badwords:
if bw in message:
print("it is bad")
@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.
it is bad
for anyone who missed ```pycon
.\cpython-main\PCbuild\amd64\python.exe
Python 4.0.0 (main, Aug 17 2023, 12:01:58) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.5 |> 2 ** $
32
$
File "<stdin>", line 1
$
^
SyntaxError: template not in righthand side of pipe operation
piping and substitution
fun
def counter():
x = 0
def add():
nonlocal x
x += 1
return x
return add
add = counter()
print(add()) # 1
print(add()) # 2
very nice
intron=''''''
exon='''
intron = input() or intron
print(f"{intron=:'^{len(intron)+6}}")
print(f"{exon=:'^{len(exon)+6}}")
print("exec(exon)")
'''
exec(exon)
is it an actual thing in 3.12/3.13?
my username "Spaceginner" is banned on roblox :(
prob due to last 6 letters
or reference to alcohol ("gin")
Hello
hi
Did you release the modified version anywhere?
not really
Pretty sure \x is used for string representations, while 0x is for hexadecimal nums
intron = input() or intron
print(f"{intron=:'^{len(intron)+6}}")
print(f"{exon=:'^{len(exon)+6}}")
print("exec(exon)")
``` a little more clarity of the exon
discord highlighter is having problems
It is always having problems
It's not really convoluted, just the result of hidden behaviour.
Like structurally it's really simple. Animal is just a normal class with no special features that make it different from any other class. Structurally the example is no different from:
!e
global_var = 3
class Animal():
def foo(self):
return global_var
def bar(self):
return dict
anim = Animal()
print(anim.foo())
print(anim.bar())
@dense mango :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | 3
002 | <class 'dict'>
All I've done here is change some names, the structure is identical.
It's just that Python has some surprising rules about renaming stuff that starts with a __ in class scope.
It has nothing to do with the type system
When you type __example inside a class MyClass: ..., Python sees __MyClass_example
So there just happens to be a global (module-level) variable with that name
Attribute lookups are inconsistent for types and non-types.
Suppose X is a class and x is an instance of X, and X.a is some descriptor object in X dict. Both X.a and x.a will execute descriptor protocol, but x.b will not (assuming it is a descriptor object in instance dict)
I expect X.a and x.b to behave in the same way
There's no attribute lookup involved in that example. The only attribute lookup is the method calls.
it is not related to your example, it is just my thoughts
__Animal_type and type are not attributes of Animal
Oh my mistake, I thought you were replying to me
I'm sorry that i interrupted you
Name mangling is also inconsistent
!e ```py
class X: __a=1
class X: __a=1
class _X: __a=1
print(vars(X))
print(vars(X))
print(vars(_X))
@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | {'__module__': '__main__', '_X__a': 1, '__dict__': <attribute '__dict__' of 'X' objects>, '__weakref__': <attribute '__weakref__' of 'X' objects>, '__doc__': None}
002 | {'__module__': '__main__', '_X___a': 1, '__dict__': <attribute '__dict__' of '_X_' objects>, '__weakref__': <attribute '__weakref__' of '_X_' objects>, '__doc__': None}
003 | {'__module__': '__main__', '_X__a': 1, '__dict__': <attribute '__dict__' of '_X' objects>, '__weakref__': <attribute '__weakref__' of '_X' objects>, '__doc__': None}
First and third mangled names are the same, if you look closely
Yep
Because it lstrip's underscores from class name
I think it would be nice if descriptors worked the same when the descriptor is in the class dict vs the instance dict.
!e ```py
x=type('',(),dict(init=lambda self:setattr(self,'dict',globals())))()
print(x.x is x)
a = 1
x.b = 2
print(x.a + b)
@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | True
002 | 3
Here x is an object that provides convenient way to use global vars through attributes on x.
Idk if it is useful, but it is definitely interesting
!e ```py
X=type('',(dict,),dict(init=lambda self,*a,**b:setattr(self,'dict',self)))
x = X(a=1, b=2)
print(x)
x[3] = x['a'] + x.b
print(x)
Sadly dict initialization is broken here
!e ```py
X=type('',(dict,),dict(init=lambda self,*a,**b:[setattr(self,'dict',self),dict.init(self,*a,**b)][0]))
x = X(a=1, b=2)
print(x)
x[3] = x['a'] + x.b
print(x)
@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | {'a': 1, 'b': 2}
002 | {'a': 1, 'b': 2, 3: 3}
!e copying from ot0: Lifetimes in Python!
import sys
import threading
from time import sleep
from typing import Annotated, get_origin, get_args
from collections import namedtuple
timeout = namedtuple("timeout", "s")
def deleter(seconds, name, scope):
sleep(seconds)
exec(f"del {name}", scope.f_globals, scope.f_locals)
class A:
def __init__(self):
self.d = {}
def __setitem__(self, name, val):
origin = get_origin(val)
if origin is Annotated:
*_, deadline = get_args(val)
if isinstance(deadline, timeout):
frame = sys._getframe(1)
threading.Thread(
target=deleter,
args=(deadline.s, name, frame)
).start()
self.d[name] = val
def __getitem__(self, item):
return self.d[item]
__annotations__ = A()
x: Annotated[int, timeout(1)] = 23
print(x)
sleep(2)
print(x)
@restive void :x: Your 3.11 eval job has completed with return code 1.
001 | 23
002 | Traceback (most recent call last):
003 | File "/home/main.py", line 34, in <module>
004 | print(x)
005 | ^
006 | NameError: name 'x' is not defined
I just wrote this one-line image to ascii text converter:
(lambda u,r,n:(lambda i,k:(lambda j:[print("".join([" ░▒▓█"[int((1-j.getpixel((x,y))/255)*4)]for x in r(k*2)]))for y in r(k)])(i.open(u("sys").argv[1]).convert("L").resize((k*2,k),1)))(u("PIL.Image",n,n,("PIL")),u("os").get_terminal_size().lines))(__import__,range,None)
what do you guys think?
!e
import ast
with open(__file__) as source_file:
source = iter(ast.parse(source_file.read()).body)
def givex():
for node in source:
if isinstance(node, ast.Assign):
if node.value.func.id != "givex":
continue
if not isinstance(node.targets[0], ast.Tuple):
continue
return range(len(node.targets[0].elts))
return (0,)
a, b = givex()
c, d, e, f = givex()
print(a, b)
print(c, d, e, f)
@wheat river :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | 0 1
002 | 0 1 2 3
wouldnt it be return 0 at the end
since x, = givex() would be covered by the tuple case
otherwise x = givex() would be x = (0,)
Yea ur right
codon (python implementation) has pipe operator:
https://docs.exaloop.io/codon/advanced/pipelines
cool
Wait, "get pixel"? Is that from a module or something?
Ohhhhhhhhhhhhh. "PIL"
I need to look into that. I've always wanted to do that.
The closest I got to messing with graphics is using features in pygame.
Nice work.
ideas for cpython
make faster
make slower
no
make reprs better, so they more frequently return same value when eval'ed:
# functions/lambdas:
>>> f = lambda x: lambda y: x + y
>>> f(1)
<lambda <lambda>@<lambda> x=1>
>>> f
<lambda>
>>>
>>> def g(x):
... def h(y):
... return x + y
... return h
...
>>> g
g
>>> g(1)
<function g@h x=1>
# methods/bound methods:
>>> list.append
list.append
>>> [].append
[].append
>>> {1:2}.keys.__call__
{1: 2}.keys.__call__
# descriptors:
>>> object.__dict__['__class__']
<slot object.__class__>
>>> type.__dict__['__bases__']
<slot type.__bases__>
# modules:
>>> import math; math
math
>>> import os.path
>>> os.path
ntpath
# types/instances:
>>> int
int
>>> class Meta(type): ...
...
>>> class X(metaclass=Meta): ...
...
>>> X
<Meta 'X'>
>>> X()
<<Meta 'X'> at 0x001A1ECC61A50>
>>>
>>> class Y: ...
...
>>> Y
Y
>>> Y()
<Y at 0x001A1ECD88690>
# properties/classmethods/staticmethods:
>>> @property
... def x(): ...
...
>>> @x.setter
... def x(): ...
...
>>> @x.deleter
... def x(): ...
...
>>> x
property(fget=x, fset=x, fdel=x)
>>>
>>> classmethod(lambda: ...)
classmethod(<lambda>)
make
<lambda <lambda>@<lambda> x=1>
>>> f
<lambda>``` cursed
>>> object.__dict__
mappingproxy({ '__new__': object.__new__,
'__repr__': sitecustomize._@__repr__,
'__hash__': object.__hash__,
'__str__': object.__str__,
'__getattribute__': object.__getattribute__,
'__setattr__': object.__setattr__,
'__delattr__': object.__delattr__,
'__lt__': object.__lt__,
'__le__': object.__le__,
'__eq__': object.__eq__,
'__ne__': object.__ne__,
'__gt__': object.__gt__,
'__ge__': object.__ge__,
'__init__': object.__init__,
'__reduce_ex__': object.__reduce_ex__,
'__reduce__': object.__reduce__,
'__getstate__': object.__getstate__,
'__subclasshook__': object.__subclasshook__,
'__init_subclass__': object.__init_subclass__,
'__format__': object.__format__,
'__sizeof__': object.__sizeof__,
'__dir__': object.__dir__,
'__class__': <slot object.__class__>,
'__doc__': 'The base class of the class hierarchy.\n'
'\n'
'When called, it accepts no arguments and returns a new featureless\n'
'instance that has no instance attributes and cannot be given any.\n'})
>>> lambda: ...
<function <lambda> at 0x0000028278EDF4C0>
``` isnt any better
this isnt html tho dude
eh sure
what do you suggest?
i have impl for all of this using fishhook, do you want it?
yea
!paste
If your code is too long to fit in a codeblock in Discord, you can paste your code here:
https://paste.pythondiscord.com/
After pasting your code, save it by clicking the Paste! button in the bottom left, or by pressing CTRL + S. After doing that, you will be navigated to the new paste's page. Copy the URL and post it here so others can see it.
also do this in your cpython fork: ```py
del builtins.quit
del builtins.exit
del builtins.copyright
del builtins.credits
del builtins.license
these things are very anoying
why
because of this mess ```py
builtins.dict
{ 'name': 'builtins',
...,
'open': io.open,
'quit': Use quit() or Ctrl-Z plus Return to exit,
'exit': Use exit() or Ctrl-Z plus Return to exit,
'copyright': Copyright (c) 2001-2022 Python Software Foundation.
All Rights Reserved.
Copyright (c) 2000 BeOpen.com.
All Rights Reserved.
Copyright (c) 1995-2001 Corporation for National Research Initiatives.
All Rights Reserved.
Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
All Rights Reserved.,
'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
for supporting Python development. See www.python.org for more information.,
'license': Type license() to see the full license text,
'help': Type help() for interactive help, or help(object) for help about object.}
eh maybe
x? syntax for repl is pretty cool
it runs help(x)
>>> int?
Help on class int in module builtins:
class int(object)
| int([x]) -> integer
| int(x, base=10) -> integer
...
(in my repl it also works if i type >>> ?i???n????????????t?)
@quartz wave can your inline module inline functions?
my old 3.10 impl couldnt do it
i have 3.11 code that can do that
i don't think i did that
where clauses for comprehensions
e.g.
items = [
(partition[0], partition[2])
for item in list_of_strings
where partition = item.partition('.')
]
for partition in [item.partition('.')]
well yeah obviously there's other ways to do it
it would be neat to have though
everytime you write for a in [b], you are making your code more incomprehensible
i might just make where a = x equivalent to for a in [x]
on that note, I read for a in [b] is optimised into a normal assignment, is that actually a thing?
part 1 done ```pycon
.\cpython-main\PCbuild\amd64\python.exe
Python 3.13.0a0 (heads/main-dirty:ef67ea5, Aug 19 2023, 22:20:40) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.f = lambda x: lambda y: x + y
f(1)
<lambda <lambda>@<lambda> x=1>
f
<lambda>
def g(x):
... def h(y): return x + y
... return h
...
g
g
g(1)
<function g@h x=1>
yep
i'm gonna continue development on monday since i can't use the pc on sundays
Nice!
Do you want my function inlining code? (It is awful, as usual)
Implement tagged breaks/continues in your cpython
(And optionally goto)
goto would be nice
Implement goto from one function to another
Also consider creating some object for ecery target. And we should be able to get this object, pass it to goto statement and jump to place where goto object was defined
def f():
label a
print("a")
return
label b
print("b")
print(f.a) # <goto to file "..." at line 123>
goto f.a # jumls to label a in f, prints a
goto [f.a, f.b][random.randint(0,1)] # haha
Make implicit __result__ variable that holds function return value
return (and implicit return at the end) actually does return __result__
return x does __result__ = x; return __result__
__result__ initial value is None
Make return and raise not statements, but expressions syntactically. They doesn't return anything because it doesn't make sense, but you can use them in expressions.
And assert too*
we need manual memory management
while malloc(1):
...
what if python made the gc async
!e ```py
def f():
try:f()
except:f()
f()
@fleet bridge :warning: Your 3.11 eval job timed out or ran out of memory.
[No output]
This
should crash
What if it made everything async?
await print('hello world')
Wait no
await print(await 'hello world')
Fixed
Wait no
await (await print)(await 'hello world')
Fixed
why arent you awaiting the await smh?
await async await def await function(await a, await b):
...
Bruh had to change
https://paste.pythondiscord.com/6BSQ function overloading
Had to make it support stuff like tuple[int|str]|list[list]]
Also why is typing.Optional like 3 different types in different scenarios
what does it do when it gets multiple overloads that are possible?
ooo you have like a scoring system to check how closely it matches the desired type
Demerit points like driving
It just picks the latest one that fits
I thought about making it prefer more strict arguments, but that wouldnt make sense
Since the user would be responsible for making different functions, why make two functions that have the same argument types even for overloading?
anything that can be passed to a function which takes an int can in theory be passed to a function which takes typing.Any
but if the user passes an int, they probably want it to use the int one
wdym
that's really hard
2nd one partially implemented ```pycon
.\cpython-main\PCbuild\amd64\python.exe
Python 3.13.0a0 (heads/main-dirty:ef67ea5, Aug 19 2023, 22:20:40) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.[].append
[].append
list.append
<method 'append' of 'list' objects>
min.call
min.call
[].getitem
[].getitem
{1: 2}.keys
{1: 2}.keys
{1: 2}.keys.call
{1: 2}.keys.call
nice
2nd one fully implemented, 3rd one fully implemented, 4th one fully implemented, 5th one partially implemented ```pycon
.\cpython-main\PCbuild\amd64\python.exe
Python 3.13.0a0 (heads/main-dirty:ef67ea5, Aug 19 2023, 22:20:40) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.list.append
list.append
object.dict['class']
<slot object.class>
type.dict['bases']
<slot type.bases>
import math; math
math
import os.path
os.path
ntpath
int
int
class Meta(type): ...
...
class X(metaclass=Meta): ...
...
X
<Meta 'X'>
X()
<<Meta 'X'> at 0x00000258CA58BE60>
class Y: ...
...
Y
Y
Y()
<Y at 0x00000258CA58BE60>
classmethod(lambda: ...)
classmethod(<lambda>)
5th one fully implemented ```pycon
.\cpython-main\PCbuild\amd64\python.exe
Python 3.13.0a0 (heads/main-dirty:ef67ea5, Aug 19 2023, 22:20:40) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.@property
... def x(): ...
...
@x.setter
... def x(): ...
...
@x.deleter
... def x(): ...
...
x
property(fget=x, fset=x, fdel=x)
classmethod(lambda: ...)
classmethod(<lambda>)
class A(classmethod): ...
...
A(lambda: ...)
A(<lambda>)
- additional in the file ```pycon
.\cpython-main\PCbuild\amd64\python.exe
Python 3.13.0a0 (heads/main-dirty:ef67ea5, Aug 19 2023, 22:20:40) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.import struct
struct.Struct('d')
_struct.Struct(b'd')
i already have goto in scopes but goto with arbitrary labels across scopes is gonna be a bit hard
im trying to write that rn
in fact really difficult
especially doing that with the current goto implementation i have rn
anyway i pushed the changes into my cpython repo
i'm gonna do frozendict
My idea for implementation is using sys.settrace to basically do a delayed jump and watch until execution is inside of the target function, then call the target function yourself after setting whatever global signals what the trace function should look for
my problem is i already have a working goto implementation
and the names are separate from variable names so things like these are possible ```py
a = 5
label a
a *= 2
if a < 100:
goto a
print(a)
and they translate into jumps and jump offsets instead of objects/instructions
Ah mine is a native version, so labels and jumps look like label .a and goto .func.label
shouldn't int be <type 'int'> then?
since type is the metaclass
idk ask @fleet bridge
it's a little painful and tedious but i did it
That would be redundant, since every class is an instance pf type.
My goal was to make reprs that more frequently evaluate to the same object
i think this works ```pycon
.\cpython-main\PCbuild\amd64\python_d.exe
Python 3.13.0a0 (heads/main-dirty:4d56f51, Aug 21 2023, 13:11:15) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.[x for x in [1, 2, 3] where x = x + 3]
[4, 5, 6]
what is this for
Other langs have that feature, so why not?
#esoteric-python message (read below)
just a calculator: for vars in [[int(input("Number 1: ")),input("+, -, * or /? "),int(input("Number 2: "))]]: print(vars[0]+vars[2] if vars[1] == "+" else vars[0]-vars[2] if vars[1] == "-" else vars[0]*vars[2] if vars[1] == "*" else vars[0]/vars[2] if vars[1] == "/" else print('Error'))
I=input
a=int(I((i:='Number %d: ')%1))
print(eval('%d%s%d'%(a,o,int(I(i%2))))if(o:=I('+, -, * or /? '))in{*'+-*/'}else'Error')
Number 1: 6
+, -, * or /? -
Number 2: 7
6666666
fixed
Number 1: 6
+, -, * or /? -
Number 2: 7
42
SyntaxError: '(' was never closed
fixed it a 3rd time
Number 1: 1
+, -, * or /? /
Number 2: 0
Traceback (most recent call last):
ZeroDivisionError: division by zero
works fine
Number 1: 5.5
Traceback (most recent call last):
ValueError: invalid literal for int() with base 10: '5.5'
works just like the original
so dat is basically this:
operand_a = int(input("Number 1: "))
operation = input("+, -, * or /? ")
operand_b = int(input("Number 2: "))
match operation:
case "+":
print(operand_a + operand_b)
case "-":
print(operand_a - operand_b)
case "*":
print(operand_a * operand_b)
case "/":
print(operand_a / operand_b)
case _:
print('Error')
yep
:D
squeezed into 1 line
that smile makes me so happy!

hugs :)
ye i like em
same

i should try "reverse engineering" more one-liners tbh
quite an interesting task
really?
are you sure?
yes.
i'll cook up a challenge then
lol
@polar plover SHOW HIM YOUR 1 LINER
i reverse-one-linered that i think
import pygame as pg
import pygame.locals
import sys # bonus! for exit purposes
from random import randint as ri
sc = pg.display.set_mode((600, 600))
cl = pg.time.Clock()
sp = pg.Vector2(10, 10)
sb = []
di = pg.Vector2(10, 0)
def nf():
global fo
fo = pg.Vector2(ri(0, 59) * 10, ri(0, 59) * 10)
while True:
sb.append(pg.Vector2(sp))
sb.pop(0)
sp += di
if sp in sb or not (0 <= sp.x <= 600 and 0 <= sp.y <= 600):
sb.clear()
sp.update(10, 10)
if sp == fo:
sb.insert(0, pg.Vector2(-10, -10))
nf()
sc.fill((0, 0, 0))
pg.draw.rect(sc, (255, 0, 0), (fo.x, fo.y, 10, 10))
pg.draw.rect(sc, (255, 255, 255), (sp.x, sp.y, 10, 10))
for p in sb:
pg.draw.rect(sc, (255, 255, 255), (p.x, p.y, 10, 10))
for ev in pg.event.get():
if ev.type == pg.locals.QUIT:
sys.exit(0) # 1 / 0
elif ev.type == pg.locals.KEYDOWN:
if ev.key == pg.locals.K_w: di.update(0, -10)
elif ev.key == pg.locals.K_s: di.update(0, 10)
elif ev.key == pg.locals.K_a: di.update(-10, 0)
elif ev.key == pg.locals.K_d: di.update(10, 0)
pg.display.update()
cl.tick(10)
this one? ```py
(pg:=import("pygame"),import("pygame.locals"),ri:=import("random").randint,sc:=pg.display.set_mode((600, 600)),cl:=pg.time.Clock(),sp:=pg.Vector2(10,10),sb:=[],di:=pg.Vector2(10,0),nf:=lambda:globals().update(fo=pg.Vector2(ri(0,59)*10,ri(0,59)*10)),nf(),[(sb.append(pg.Vector2(sp)),sb.pop(0),sp.iadd(di),(sb.clear(),sp.update(10,10))if(sp in sb or not(0<=sp.x<=600and 0<=sp.y<=600))else None,(sb.insert(0,pg.Vector2(-10,-10)),nf())if sp==fo else None,sc.fill((0,0,0)),pg.draw.rect(sc,(255,0,0),(fo.x,fo.y,10,10)),pg.draw.rect(sc,(255,255,255),(sp.x,sp.y,10,10)),[pg.draw.rect(sc,(255,255,255),(p.x,p.y,10,10))for p in sb],[((1/0)if ev.type==pg.locals.QUIT else di.update({pg.locals.K_w:(0,-10),pg.locals.K_s:(0,10),pg.locals.K_a:(-10,0),pg.locals.K_d:(10,0)}.get(ev.key,di))if ev.type==pg.locals.KEYDOWN else None)for ev in pg.event.get()],pg.display.update(),cl.tick(10),)for _ in iter(int,1)])
yep
that one
__builtins__.__getattribute__((_:=__name__.__class__.__class__.__doc__.__getitem__((___:=(_:=__name__.__getitem__((__:=__name__.__class__().__len__()))).__add__(_).__len__())).__add__((_____:=(_____:=__name__.__ne__(__name__).__invert__()).__neg__().__truediv__(_____.__add__(_____).__neg__()).__rpow__(_____).__class__).__doc__.__getitem__((______:=__name__.__eq__(__name__).__pos__()))).__add__(__name__.__len__().__class__.__doc__.__getitem__(__)).__add__(__name__.__len__().__class__.__doc__.__getitem__(______)).__add__(__name__.__class__.__class__.__doc__.__getitem__(__))))(___________ if(___________:=(________:=__builtins__.__getattribute__((_______:=__name__.__len__().__class__.__doc__.__getitem__(__).__add__(__name__.__len__().__class__.__doc__.__getitem__(______)).__add__(__name__.__class__.__class__.__doc__.__getitem__(___)).__add__(__name__.__len__().__class__.__module__.__getitem__(______)).__add__(__name__.__class__.__class__.__doc__.__getitem__(__))))()).__mul__(__________:=__builtins__.__getattribute__((_________:=__name__.__len__().__class__.__doc__.__getitem__(__).__add__(__name__.__len__().__class__.__doc__.__getitem__(______)).__add__(__name__.__class__.__class__.__doc__.__getitem__(__))))(__builtins__.__getattribute__(_______)())))!=(_________________:=__builtins__.__getattribute__(__builtins__.__dir__().__getitem__((____________:=(_____________:=(____________:=__name__.__getitem__(__)).__add__(____________).__add__(____________).__len__()).__mul__((________________:=(______________:=___.__mul__(___)).__mul__(_____________).__add__((_______________:=___.__mul__(___).__invert__().__neg__()))))))))else __________.__rmul__(________))
try that
obfuscator detected
@stark granite try this too
wow
wtf does it do?
wow
try providing some inputs
it should be pretty quick once you figure it out
this one is snake
is it a calculator?
no it's simpler than one
multiplicator?
I like vivax, cool friend
missing a call
yep
why tf does it need __doc__ and __len__ and __rmul__ (just as well __add__)?
wait i gotta understand wtf does it do
Does this count as esoteric ```py
def inject(clazz, otherclazz=None):
if otherclazz==None:
for name, obj in globals().copy().items():
if isinstance(obj, type) and not issubclass(obj, clazz):
try:
for method in getMethods(clazz):
setattr(obj, method, getattr(clazz,method))
for variable in getVariables(clazz):
setattr(obj, variable, getattr(clazz,variable))
globals()[name] = obj
print(obj.name)
except Exception as e:
print(e)
else:
obj = globals()[otherclass.name]
for method in getMethods(clazz):
setattr(obj, method, getattr(clazz,method))
for variable in getVariables(clazz):
setattr(obj, variable, getattr(clazz,variable))
globals()[otherclass.name] = obj
Because I doubt alot of people would understand it 😂
The methods also work to get self and the class they are in even though the are instances of another classes method
Not quite IMO. It's unholy, don't get me wrong, but still not cursed enough to be truly esoteric.
globals()[name] = obj this is unnecessary; you're modifying the other class(es) in-place
327 ```py
def a(c,o):
for v in dir(c):
if v not in dir(type)and(callable(x:=getattr(c,v))or"weakref"!=v):setattr(o,v,x)
def inject(c,o):
if o==None:
for x in globals().values():
if isinstance(x,type)and not issubclass(x,c):
try:a(c,x),print(x.name)
except Exception as e:print(e)
else:a(c,globals()[o.name])
Mines is somewhat readable still, but that is on a whole other level 💀
321 ```py
def a(c,o):
for v in dir(c):
if v not in dir(type)and(callable(x:=getattr(c,v))or"weakref"!=v):setattr(o,v,x)
def inject(c,o):
if o==None:
for x in globals().values():
if isinstance(x,type)&~issubclass(x,c):
try:a(c,x),print(x.name)
except Exception as e:print(e)
else:a(c,globals()[o.name])
309 ```py
def a(c,o):
for v in{*dir(c)}-{*dir(type)}:
if callable(x:=getattr(c,v))or"weakref"!=v:setattr(o,v,x)
def inject(c,o,g=globals()):
if o==None:
for x in g.values():
if isinstance(x,type)&~issubclass(x,c):
try:a(c,x),print(x.name)
except Exception as e:print(e)
else:a(c,g[o.name])
What are you using to do this?
mind
306 might continue tmr ```py
def a(c,o):
for v in{*dir(c)}-{*dir(type)}:
if callable(x:=getattr(c,v))or"weakref"!=v:setattr(o,v,x)
def inject(c,o,g=globals()):
if o==None:
for x in g:
if isinstance(x:=g[x],type)&~issubclass(x,c):
try:a(c,x),print(x.name)
except Exception as e:print(e)
else:a(c,g[o.name])
shouldnt you compare o to None using is instead of ==?
Takes more bytes
This is not exactly idiomatic code anyways
yes i know
actually what is the reason behind using is instead of ==?
!e
import numpy as np
x = np.array([1, 2, 3])
print(x is None)
print(None == x)
print(x == None)
@languid hare :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | False
002 | [False False False]
003 | [False False False]
there is no guarantee the == works how you expect it to
of course, for builtins they're much more well behaved, but you shouldn't rely on it
huh
ok
@fleet bridge native goto that can jump into a new function scope
it uses sys.settrace
basically just sets a trace function to perform the jump as soon as execution enters a frame with a specific code object, then calls the function
That's smart
rn the function jump doesnt share a its jump code with the normal goto code, im trying to generalize rn
https://paste.pythondiscord.com/MF5A now with a more shared code base and dynamic goto's for function labels
identity vs equality
301 ```py
def a(c,o):[setattr(o,v,x)for v in{*dir(c)}-{*dir(type)}if callable(x:=getattr(c,v))or"weakref"!=v]
def inject(c,o,g=globals()):
if o==None:
for x in g:
if isinstance(x:=g[x],type)&~issubclass(x,c):
try:a(c,x),print(x.name)
except Exception as e:print(e)
else:a(c,g[o.name])
def a(c,o):[setattr(o,v,x)for v in{*dir(c)}-{*dir(type)}if callable(x:=getattr(c,v))or"__weakref__"!=v]
def inject(c,o,g=globals()):
if o!=None:return a(c,g[o.__name__])
for x in g:
if isinstance(x:=g[x],type)&~issubclass(x,c):
try:a(c,x),print(x.__name__)
except Exception as e:print(e)```
297
def a(c,o):[setattr(o,v,x)for v in{*dir(c)}-{*dir(type)}if callable(x:=getattr(c,v))or"__weakref__"!=v]
def inject(c,o,g=vars()):
if o!=None:return a(c,g[o.__name__])
for x in g:
if isinstance(x:=g[x],type)&~issubclass(x,c):
try:a(c,x),print(x.__name__)
except Exception as e:print(e)```
294
this only works if the function is defined at global scope though
292, if you assume .__weakref__ will never be callable (which is almost always a reasonable assumption)
def a(c,o):[setattr(o,v,x)for v in{*dir(c)}-{*dir(type)}-{"__weakref__"}if callable(x:=getattr(c,v))]
def inject(c,o,g=vars()):
if o!=None:return a(c,g[o.__name__])
for x in g:
if isinstance(x:=g[x],type)&~issubclass(x,c):
try:a(c,x),print(x.__name__)
except Exception as e:print(e)```
thats all i can think of for now
might try to make it shorter tomorrow
wait actually
def a(c,o):[setattr(o,v,x)for v in{*dir(c)}-{*dir(type),"__weakref__"}if callable(x:=getattr(c,v))]
def inject(c,o,g=vars()):
if o!=None:return a(c,g[o.__name__])
for x in g:
if isinstance(x:=g[x],type)&~issubclass(x,c):
try:a(c,x),print(x.__name__)
except Exception as e:print(e)```
290
ok now im done for today
no more ideas
that'll not include the things that aren't callable
it's either callable or not callable and is not .__weakref__
so 273 ```py
def a(c,o):[setattr(o,v,getattr(c,v))for v in{*dir(c)}-{*dir(type),"weakref"}]
def inject(c,o,g=vars()):
if o!=None:return a(c,g[o.name])
for x in g:
if isinstance(x:=g[x],type)&~issubclass(x,c):
try:a(c,x),print(x.name)
except Exception as e:print(e)
ok gn
gn
can use exec() for a possible improvement
268 ```py
def inject(c,o,g=vars()):
def a(o):[setattr(o,v,getattr(c,v))for v in{*dir(c)}-{*dir(type),"weakref"}]
if o!=None:return a(g[o.name])
for x in g:
if isinstance(x:=g[x],type)&~issubclass(x,c):
try:a(x),print(x.name)
except Exception as e:print(e)
266 ```py
def inject(c,o,g=vars()):
def a(o):[setattr(o,v,getattr(c,v))for v in{*dir(c)}-{*dir(type),"weakref"}]
if o!=None:a(g[o.name]);g=[]
for x in g:
if isinstance(x:=g[x],type)&~issubclass(x,c):
try:a(x),print(x.name)
except Exception as e:print(e)
I hardly ever use is, except for testing/debugging.
you are supposed tho
okay but now make it work with ctx managers
Like jump into a context manager block?
You could implement that by jumping to the beginning of the setup line, then installing a handler to jump to the specific label inside the ctx manager block as soon as execution enters the block
Hah, that's some gimped goto
had to still execute the ctx manager to maintain stack levels, but was able to jump around upon entry
Eh, that's way too well-behaved... Where's the fun if it actually sets up the resource :D
Trace functions don't let you jump into a context manager though, right?
Yeah, you jump in front of it, and then immediately jump within it, right?
yup
but i implemented it in such a way that also allows jumps into and out of for loops
(Reminds me of the weird hack I had to pull with dont)
Nice, I'm always impressed by your stunts :)
I like the oxymoron of a resource respecting goto
it seemed like a neat and cursed way of handling goto
Do you set up/tear down the trace function stuff before and after each jump?
Jumping out of a with block will skip it's exit, right?
Alternative syntax idea:
goto(my_label)
my_label: # (half-width hangul filler)
Ah, I guess goto(my_label) doesn't work if the tf isn't active yet (unless the label has been declared already). And it would make it more complicated inside functions.. too bad
yea, i played around with a few syntaxes, and keyword .label was the easiest one to scan bytecode for (LOAD_NAME | LOAD_GLOBAL + LOAD_ATTR)
The label I think is doable now that I think about it. It's just a SETUP_ANNOTATIONS at the beginning, and then somewhere a LOAD_NAME, LOAD_NAME ("__annotations__"), LOAD_CONST, STORE_SUBSCR.
And technically the goto(my_label) is also doable by hooking into globals/builtins __missing__ (or equivalent).
the issue is it gets stripped away inside functions
!e ```py
import dis
def foo():
label: here
dis.dis(foo)```
@rugged sparrow :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | 2 0 RESUME 0
002 | 2 LOAD_CONST 0 (None)
003 | 4 RETURN_VALUE
Even if you turn off all optimizations?
im pretty sure they are always stripped
any suggestions for syntax for function jumps with args (rn i have goto .function.with_args(...).label or goto *function.with_args(...).label)
i like this one but its tricky because rn that would just call the function right there
it would work for goto .function(...).label but would not for goto *function(...).label (which is my syntax for dynamic jumps)
How would I modify on a part of a built-in classes methods body
Or any classes methods body
Cant find anything for this anywhere
Can't you just create a new type that inherits from builin one?
!e like this? ```py
from fishhook import hook, orig
@hook(list)
def sub(self, other):
new = self.copy()
for item in other:
if item in new:
new.remove(item)
return new
print([1,2,3] - [1])```
@rugged sparrow :white_check_mark: Your 3.11 eval job has completed with return code 0.
[2, 3]
Exactly💀
But I wouldn't want to rewrite the entire body only part of it like changing the bytecode of the return value etc
can you show me a psudocode example?
i belive you can override any method you want like that, but I have not tested it:
MyClass.my_method = lambda self: completely_different_function()
you can do that for classes defined in python, not classes defined in C
fishhook lets you do it for C classes as well
Original```
class myClass:
def say(self,d):
print(d)
if d == 10:
return "yes"
else:
return "no"
Modified
class myClass:
def say(self,d):
print(d)
if d == 10:
return 10 <- changed value and not the whole body
else:
return "no"
That's actually cool
^ in that specific example, you could swap out the constant value "yes" with 10
Can you give me a example?
!e ```py
class myClass:
def say(self,d):
print(d)
if d == 10:
return "yes"
else:
return "no"
orig_consts = list(myClass.say.code.co_consts)
orig_consts[orig_consts.index("yes")] = 10
myClass.say.code = myClass.say.code.replace(co_consts=tuple(orig_consts))
m = myClass()
print(m.say(10))```
@rugged sparrow :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | 10
002 | 10
.code is a thing? 💀 that's so much easier than what I was thinking
But does it work for built-in classes?
!e ```py
class X:
def foo(self):
print('foo')
from fishhook import hook
@hook(X)
def foo(self):
print('bar')
X().foo()
@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.
bar
builtin classes are defined in C, you will need to use a tool like ctypes, fishhook or einspect to mess with them
in theory orig should even work in that case
tbh i don't remember if i tested orig with python classes
Yeah that's what I thought that's why I asked in #c-extensions and then they told me to go here 😐
!e ```py
class X:
def foo(self):
print('foo')
from fishhook import hook, orig
@hook(X)
def foo(self):
print('bar')
orig(self)
X().foo()
@fleet bridge :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | bar
002 | foo
cool
it works
sweet
ah you are trying to write mixins
seems every few months or so someone is in here trying to write python mixins lol
i have an implementation for 3.10 somewhere
Nah I am really gonna do it
but so much changes with the bytecode every version it is very difficult to handle every situation
and mixins for builtin classes, do you mean like assembly patching?
Possibly
ah yea, that stuff gets very finiky very fast
i am working on fishhook.asm currently to make assembly patching way easier, (currently it only supports complete hooking of C functions on x86 intel)
is there any fishhook documentation?
i would like to see examples of how to use fishhook.asm.hook
i was avoiding writing docs for it, since i plan on changing it a ton when i make it more generalized, tbh only added that first version so i could use it for hacky stuff here
can you just drop some examples somewhere?
!e ```py
from ctypes import *
from fishhook.asm import hook
@hook(pythonapi.PyDict_SetDefault, restype=py_object, argtypes=[py_object, py_object, py_object])
def setdefault(self, key, value):
if key == 'MAGICVAL':
return self
return pythonapi.PyDict_SetDefault(self, key, value)
pythonapi.PyUnicode_InternFromString.restype = py_object
interned = pythonapi.PyUnicode_InternFromString(b'MAGICVAL')
setdefault.unhook()
print(interned)```
@rugged sparrow :white_check_mark: Your 3.11 eval job has completed with return code 0.
{'type': 'type', 'AttributeError': 'AttributeError', '__qualname__': '__qualname__', 'obj': 'obj', 'update': 'update', '__dict__': '__dict__', 'getattr': 'getattr', 'setattr': 'setattr', 'hasattr': 'hasattr', '__doc__': '__doc__', '__name__': '__name__', '__module__': '__module__', 'replace': 'replace', 'old': 'old', 'new': 'new', 'sys': 'sys', 'name': 'name', '_DeadlockError': '_DeadlockError', 'waiters': 'waiters', 'count': 'count', 'owner': 'owner', 'wakeup': 'wakeup', 'lock': 'lock', 'allocate_lock': 'allocate_lock', '_thread': '_thread', 'self': 'self', 'add': 'add', 'get': 'get', '_blocking_on': '_blocking_on', 'set': 'set', 'get_ident': 'get_ident', 'seen': 'seen', 'tid': 'tid', 'me': 'me', 'release': 'release', 'acquire': 'acquire', 'has_deadlock': 'has_deadlock', 'RuntimeError': 'RuntimeError', 'id': 'id', 'format': 'format', '__repr__': '__repr__', '__init__': '__init__', '_ModuleLock': '_ModuleLock', '_DummyModuleLock': '_DummyModuleLock', '_lock': '_lock', '_name': '_name',
... (truncated - too long)
Full output: https://paste.pythondiscord.com/DVSANU65G53QEDR4OSQUBBHXZU
heres an example i made to grab the interned dict
it doesnt work with every function, some are optimized in ways that bypass the things it patches
i also would like to see type annotations in fishhook
are they planned in the future?
do you need any help? i think im pretty good at this, i can help you
honestly, i would love help with that, I have never realy felt the need to add type hints to any of my projects
also i really need to write a full docs for fishhook, there are a few features that are not documented at all (like fishhook.asm and @hook(cls1 | cls2))
if you want to make pull requests, be my guest, i look thru and merge them
- is it ok to run
blackon your code? import typing,import typing as torfrom typing import ...?
also, which python versions are supported by fishhook?
python_requires='>=3.8', i see...
sure you can run black, and for the typing import i don't have a preference
yea i first wrote fishhook for 3.8 so i wanted to retain support
Isn't _code_.co_code the bytecode of the function?
it is
i discovered bug in fishhook
if you use same wrapper for two methods with different names, it will overwrite wrong method
from fishhook import hook, orig
class X:
def foo(self):
print('foo@1')
def bar(self):
print('bar@1')
h = hook(X)
@h
def foo(self):
print('foo@2')
orig(self)
@h
def bar(self):
print('bar@2')
orig(self)
x = X()
x.foo()
print()
x.bar()
yea that makes sense, the wrapper returned by hook has some internal state stuff
that tutorial is quite out of date, just a warning
https://github.com/chilaxan/fishhook/blob/master/fishhook/fishhook.py#L321 this line is the reason, the first use of the wrapper sets name so code.co_name is never regrabbed from the second function object
fishhook/fishhook.py line 321
name = name or code.co_name```
yes, i know
i discovered this bug by looking at this exact line
fishhook is actually very hard to type-annotate...
especially stuff like @hook.cls
Yea it has some weird code to facilitate the nicer syntax
Working on the better fishhook.asm using keystone and capstone for disassembly and reassembly
whens the mypy plugin happening?
import dis
import types
def my_function(x):
if x > 0:
return x * 2
else:
return x
original_code = my_function.__code__
new_instructions = []
instructions = list(dis.get_instructions(original_code))
before_instr = None
newopcode = dis.opmap["BUILD_TUPLE"]
for instr in instructions:
if before_instr is not None and before_instr.opcode == dis.opmap["LOAD_CONST"] and instr.opcode == dis.opmap['RETURN_VALUE']:
new_instr = dis.Instruction(
opcode=newopcode,
opname=dis.opname[newopcode],
arg=0,
argval=None,
argrepr="()",
offset=instr.offset,
starts_line=instr.starts_line,
is_jump_target=instr.is_jump_target
)
new_instructions.append(new_instr)
else:
new_instructions.append(instr)
before_instr = instr
modified_code = types.CodeType(
original_code.co_argcount,
original_code.co_kwonlyargcount,
original_code.co_nlocals,
original_code.co_stacksize,
original_code.co_flags,
b''.join(instr.opcode.to_bytes(1,"little") for instr in new_instructions),
original_code.co_consts,
original_code.co_names,
original_code.co_varnames,
original_code.co_filename,
original_code.co_name,
original_code.co_firstlineno,
original_code.co_lnotab,
original_code.co_freevars,
original_code.co_cellvars
)
modified_function = types.FunctionType(modified_code, globals())
result = modified_function(3)
print(result)
``` don't know what's wrong
#bot-commands message
^ Error here
Thats on 3.11 but on 3.6.6 its Traceback (most recent call last): File "/storage/emulated/0/qpython/projects3/mixins/.last_tmp.py", line 134, in <module> result = modified_function(3) File "/storage/emulated/0/qpython/projects3/mixins/.last_tmp.py", line 80, in my_function if x > 0: IndexError: tuple index out of range
This way I can actually append a whole methods body to the instructions
Ah all of your jump targets are going to need to be recomputed if you are changing the length of the byte code
Honestly, it looks pretty good until you get to hook, then you can tell very quickly that fishhook does not like typing
ok ..
#esoteric-python message here is a 3.10 mixin implementation I wrote a while back
Oh wait the paste got wiped
old pastes do that :(
I'll go find the source
Annotating build_orig (and everything inside) is painful, because there is a lot of magic happening, so we should slap Any almost everywhere
Yea that makes sense, build_orig does a ton of weird stuff to try and ensure it works in any situation
I think annotating only public api (and some easy non-public functions) makes more sense, than annotating everything
So the most painful part is hook.* things
No idea how I would do that 💀
At this point I'ma just use fishhook for mixins and use that for the modifying logic
i found the source but it doesnt even work on 3.10 anymore rip
Alright so when I do something like if x==z: print() that's a jump correct? And the jump target is print correct?
Cuz idk
um
this doesn't possibly skip a return does it?
Guys, I have a question, is it possible to get the media list on the last call of the function when the number of calls is unknown?
import random
media = []
def containing_function():
media.append('PHOTO')
print(media)
for _ in range(random.randint(1, 5)):
containing_function()
it does skip a return
import dis
import types
def my_function(x):
if x > 0:
return x * 2
else:
return x
original_code = my_function.__code__
new_instructions = []
instructions = list(dis.get_instructions(original_code))
before_instr = None
newopcode = dis.opmap["BUILD_TUPLE"]
for instr in instructions:
if before_instr is not None and before_instr.opcode == dis.opmap["LOAD_CONST"] and instr.opcode == dis.opmap['RETURN_VALUE']:
new_instr = dis.Instruction(
opcode=newopcode,
opname=dis.opname[newopcode],
arg=0,
argval=None,
argrepr="()",
offset=instr.offset,
starts_line=instr.starts_line,
is_jump_target=instr.is_jump_target
)
new_instructions.append(new_instr)
new_instructions.append(instr)
before_instr = instr
modified_code = types.CodeType(
original_code.co_argcount,
original_code.co_kwonlyargcount,
original_code.co_nlocals,
original_code.co_stacksize,
original_code.co_flags,
b''.join(instr.opcode.to_bytes(1,"little")+(instr.arg.to_bytes(1,"little") if instr.arg is not None else b"\0") for instr in new_instructions),
original_code.co_consts,
original_code.co_names,
original_code.co_varnames,
original_code.co_filename,
original_code.co_name,
original_code.co_firstlineno,
original_code.co_lnotab,
original_code.co_freevars,
original_code.co_cellvars
)
``` should work for 3.6 now
It shouldn't
it does
tested out the working thing before i changed this part ```diff
new_instructions.append(new_instr)
- else:
-
new_instructions.append(instr)
- new_instructions.append(instr)
jump offsets aren't affected for this specific case
Ok what if I added more than just a different return value? Does that change it? Like what if I change the return to another if-return
6
For 3
So doesn't
here's the modified code from above ```pycon
5 0 LOAD_FAST 0 (x)
2 LOAD_CONST 1 (0)
4 COMPARE_OP 4 (>)
6 POP_JUMP_IF_FALSE 16
6 8 LOAD_FAST 0 (x)
10 LOAD_CONST 2 (2)
12 BINARY_MULTIPLY
14 RETURN_VALUE
8 >> 16 LOAD_FAST 0 (x)
18 RETURN_VALUE
20 LOAD_CONST 0 (None)
22 BUILD_TUPLE 0
24 RETURN_VALUE
``` if the highlighted LOAD_FAST 0 (x) moves from position 16 by instruction addition/removal, the argument to POP_JUMP_IF_FALSE must be changed
what should be the output?
()
nothing jumps to the final BUILD_TUPLE and RETURN_VALUE
💀
which is the only place that contains LOAD_CONST + RETURN_VALUE
@fleet bridge a lot of operating systems don't let me map READ/WRITE/EXEC memory anymore, i can only do pairs of READ/WRITE or READ/EXEC. normally that would be fine, but since i have to remap entire memory regions to write in new assembly, sometimes there are functions in the same region that need to get called while the region is not marked executable. (i think im going to have to write my entire mprotect(R/W), writeASM, mprotect(R/X) in assembly
i might have to use slightly different syntax to implement dynamic goto/label in cpython
are you doing computed goto?
maybe
jumping in and out of anything that needs init code is hard
#esoteric-python message I got it working up here
Do you want my source?
that's with tracing and stuff
True but it's something to start with right?
golf: https://leetcode.com/problems/longest-common-prefix/description/
my best so far ||return "".join(x for x,in __import__("itertools").takewhile(lambda g:len(g)==1,map(set,zip(*strs))))||
base 136 ||```py
class Solution:longestCommonPrefix=lambda _,s:"".join(x for x,in import("itertools").takewhile(lambda g:len(g)==1,map(set,zip(*s))))
136 -> 116 has an issue ||```py
class Solution:longestCommonPrefix=lambda _,s:s[0][:next((i for i,x in enumerate([*zip(*s),(1,2)])if~-len({*x})),0)]
136 -> 112 turns out it was not an issue ||```py
class Solution:longestCommonPrefix=lambda _,s:s[0][:next(i for i,x in enumerate([*zip(*s),(1,2)])if~-len({*x}))]
whats the (1, 2) for
112 -> 110 good point, replaced it with a better one ||```py
class Solution:longestCommonPrefix=lambda _,s:s[0][:next(i for i,x in enumerate([*zip(s),s0])if~-len({*x}))]
it's a stopper
oh yeah
110 -> 108 s*0 -> () + next() -> listcomp[0] ||```py
class Solution:longestCommonPrefix=lambda _,s:s[0][:[i for i,x in enumerate([*zip(*s),()])if~-len({*x})][0]]
preventing out-of-range things
what case does it fail for without it
list of strings are empty
s[0] would fail for that anyway
hmm true
oh wait if a single string is empty
hmm yea
it's when the string of minimum length gets consumed whole
i.e. all the other strings start with it
a right
@quartz wave 97
class Solution:longestCommonPrefix=lambda _,s:s[0][:[1==len({*x})for x in[*zip(*s),()]].index(0)]
:(
Cant you:
- mark memory as W/E
- change code
- mark as R/E
- execute code
Can't have a segment be Writeable and Executable at the same time
So I'm gonna write my writeASM stub in assembly
The problem with doing that in python is that I have to mark an entire 16k page, so if another function is in that page and is called during the patch when the page isn't executable I get a bus error
I see
Yeah, doing that in asm now makes sense to me
Is it possible to have object that is not an instance of object?
x = ...
assert not isinstance(x, object)
Via memory tricks you can make a new base type
Then I think the resulting objects would not be instances of object
What is the least amount of hacks you have to do to achieve that result?
class X(object): ...
x = X()
X.__base__ = X # memory trick requred
assert not isinstance(x, object)
Im not sure that this will work
Probably you also should modify bases, mro and something else mro-related
This will always be funny to me: ```py
class M(type): ...
...
class X(M, metaclass=M): ...
...
X.class = X
X is type(X) is X.class
True
isinstance(X, X)
True
issubclass(X, X)
True
doesnt python have the GIL
yea, thats why using direct asm would work
i wonder if it would be possible for lambda to operate on a whole list at once
Like map a lambda across the list?
85 cw problem [pdsn base](#python-discussion message) ```py
minimum_number=m=lambda n:not(t:=sum(n))>1==all(t%i for i in range(2,t))and-~m(n+[1])
84 ```py
minimum_number=m=lambda n:not~-(t:=sum(n))*all(t%i for i in range(2,t))and-~m(n+[1])
still 84 but performance boost ```py
minimum_number=m=lambda n:not~-(t:=sum(n))*all(t%i for i in range(2,t))and-~m([t+1])
how do I join this cult
81 but with a performance degradation
minimum_number=m=lambda n:(all(sum(n)%i for i in range(2,sum(n)))or 2+m(n+[1]))-1
79 ```py
minimum_number=m=lambda n:~-all(sum(n)%i for i in range(2,sum(n)))and-~m(n+[1])
whatcha golfing
.
wait where r you checking prime
the major part of the program ```py
all(sum(n)%i for i in range(2,sum(n)))
oh thats the prime check
/run
