#esoteric-python
1 messages · Page 71 of 1
rip
maybe ```py
valid_python_version = (
match (amount=3)
[3, 7, :].or [3, 5, :] (True)
[:, :, :] (False)
)
would be good syntax for that
actually no, or is a keyword
darn
the | operator wouldn't work because that would become invalid syntax too
and also precedence would be a fuck too
.either
@wind maple my fork lets you put a callable in there
(which obviously isnt the same)
is there a way to override what isinstance does?
like if i implement a class, can i also define how isinstance checks work? or is that baked into the runtime
metaclass with __instancecheck__
CPython impl detail AFAIK
😦
looks like its part of the spec
pep 3119
alternatively (or additionally) you could implement fall-through of patterns
valid_python_version = (
match (amount=3)
.either[3, 7, :][3, 5, :] (True)
[:, :, :] (False)
)
import math
from match import match
from match.pattern import Not, __recall__
from whatever import _
log_safe = (
match (amount=1)
[Not[float]] (float, __recall__)
[_ <= 0] (math.nan)
[:] (math.log)
)
🤷
import math
from match import match
from match.pattern import Not, __recall__, raises
from whatever import _
log_safe = (
match (amount=2)
[Not[float], :] (float, __recall__)
[_ <= 0, False] (math.nan)
[_ <= 0, True] (raises(ValueError, "Must be a positive real number"))
[: ,:] (math.log)
)
from math import log
def log_safe(x, err=False):
if not isinstance(x, float):
return log_safe(float(x, err=err))
if x <= 0:
if err:
raise ValueError("Must be a positive real number")
return math.nan
return math.log(x)
you could probably develop some kind of compiler that optimized away redundant operations, for when the stuff inside the match [] is expensive
or you can add new syntaxes anytime you want
with hooking to tokenizer
*cpython only
What’s match?
How would I run minecraft from command line?
i've made a small change to allow for multiple patterns, but i'm not sure which format i prefer visually: ```py
valid_python_version = (
match (amount=3)
[3, 7, :] [2, 7, 16]
(True)
[:, :, :]
(False)
)
valid_python_version = (
match (amount=3)
[3, 7, :] [2, 7, 16] (True)
[:, :, :] (False)
)
valid_python_version = (
match (amount=3)
[3, 7, :]
[2, 7, 16] (True)
[:, :, :] (False)
)
they all work syntactically though
i think i like the second one the most
yea the second one looks good
@brisk zenith i like the 3rd
class AutoSuperInitMeta(type):
def __new__(cls, name, bases, dic):
self = type.__new__(cls, name, bases, dic)
if '__init__' in dic:
self.__init__ = cls.wrap_init(self.__init__, self)
def wrap_init(init, cls):
code = init.__code__
argcount = code.co_argcount+code.co_kwonlyargcount
argnames = code.co_varnames[:argcount]
def wrapper(self, **kwargs):
mykwargs = {}
for name in argnames:
if name in kwargs:
mykwargs[name] = kwargs.pop(name)
super(cls, self).__init__(**kwargs)
init(self, **mykwargs)
return wrapper
whats foo?
oh, sorry
foo was a temp function i used in the repl to remind myself how code objects worked
!e
class HasSuperInit(type):
def __init__(cls, name, bases, dct):
def superinit(self, *args, **kwargs):
super(cls, self).__init__(*args, **kwargs)
cls.superinit = superinit
class A:
def __init__(self):
self.x = 1
class B(A, metaclass=HasSuperInit):
pass
b = B()
print(b.x)
@sonic ginkgo Your eval job has completed.
1
wait hold on
how did that work, i forgot to call init
class HasSuperInit(type):
def __init__(cls, name, bases, dct):
def superinit(self, *args, **kwargs):
super(cls, self).__init__(*args, **kwargs)
cls.superinit = superinit
class A:
def __init__(self):
self.x = 1
class B(A, metaclass=HasSuperInit):
def __init__(self):
self.superinit()
b = B()
print(b.x)
thats what i meant to write
how did that first one even work o_O
if you don't define init the parent init is called first anyway
ah
(TIL)
!e
class HasSuperInit(type):
def __init__(cls, name, bases, dct):
def superinit(self, *args, **kwargs):
super(cls, self).__init__(*args, **kwargs)
cls.superinit = superinit
class A:
def __init__(self):
self.x = 1
class B(A, metaclass=HasSuperInit):
def __init__(self):
self.superinit()
b = B()
print(b.x)
@sonic ginkgo Your eval job has completed.
1
how do you tell if a function has *args/**kwargs?
in this case, i dont
no i'm asking for my thing
youd have to do what you did hacking around w/ inspect.signature
though I think it doesn't matter because they appear after all explicit arguments (even keyword-only) in varnames
yeah i'm trying to figure out how you do it without inspect
probably in co_flags
yep, 4 and 8 respectively
import inspect
def f(x, *args, y=1, **kwargs):
return
inspect.signature(f).parameters['args'].kind.name == 'VAR_POSITIONAL'
varnames is, empirically, all positional args, then all kw-only args, then *args, then **kwargs
(and then locals, obviously)
well, probably cells then locals
why in the world does a ParameterKind have a .numerator and .denominator attribute
because it's a number
ah
oh its an enum
even though floats don't
thats cause ints are a subset of rationals
rational meaning "can be represented as a ratio of integers"
so are most floats
"most" 
infinity nan
only countably
whereas you have an uncountably infinite number of irrationals between every rational
yeah but you can't represent an irrational number in a float
true, floats are basically giant integers
but logically theyre supposed to behave more like a real
i'm just surprised they don't have the properties anyway
and throw exceptions on inf/nan
im glad they dont. they shouldnt
it has as_integer_ratio()
what does?
@sonic ginkgo wow cool)
class HasSuperInit(type):
def __init__(cls, name, bases, dct):
def superinit(self, *args, **kwargs):
super(cls, self).__init__(*args, **kwargs)
cls.superinit = superinit
class A:
def __init__(self):
self.x = 1
class B(A, metaclass=HasSuperInit):
def __init__(self):
self.superinit()
b = B()
print(b.x)
Is this for init only?
If so, how to make it work for any method?
in most cases you don't always want to call the original method at all
oh weird @calm rampart, why do floats have that but ints dont?
and there's no way to automatically determine whether it's wanted or not
@sick hound no you can't make it automatically detect and call the parent method without a lot more work
again, i recommend none of this
you will come back to this code in 6 months and not have any idea what's going on
can a method pass or receive arguments implicitly (except for self)?
well, what value might it take? why can't it use a variable from an outer scope?
@brisk zenith is this the only easily implemented option in python (use a variable from an outer scope)?
i mean, as far as i can tell, yes. i don't see how it might be useful to be implicitly passed though
@brisk zenith
class A:
def __init__(self, **kwargs):
self.a = 1
class B(A):
def __init__(self, **kwargs):
self.super(**kwargs)
# ideally i want:
#self.super()
def super(self, **kwargs):
# I need to get here
# 1) method from which self.super called
# 2) kwargs
# that is in this case:
super().__init__(**kwargs)
# but in general case I need:
#super().method_I_called_from(method_I_called_from_args)
b_inst = B()
print (b_inst.a)
what exactly do you mean by implicitly passed?
arguments can have default values
oh you're still on the super thing?
))
anyway I think the thing you're proposing is not likely to be as useful as you think it is
in many cases you will want the derived method to accept different arguments from the parent class's method, especially for init
I think you could do it with frame inspection - that's how super() itself finds the self argument
@calm rampart Well this is not an advertisement, but I really want to spend a lot of time working with the kivy framework.
If you look at the source code, then almost everywhere the same _init__: it takes **kwargs and uses super.
https://github.com/kivy/kivy/search?q=__init__&unscoped_q=__init__
roughly the same thing is happening in the code of my applications..
and instead of reading the code, I read super.
In addition, I often make a mistake when I copy-paste some old method when creating a new method (if it has a lot in common) but forget to change the super (method name or arguments).
I would just like to try to radically solve this issue.
maybe now I’ve even convinced you a little)
maybe but how many methods other than __init__ do that
@calm rampart many methods. e.g. on_touch_down, on_touch_move, on_touch_up. And this is only standard ones, besides this, there are many other cases.
you could make a decorator and a metaclass/another decorator for the class (you'll need both or you'd have to go with descriptors) that does the calling of super for you (with a bit of magic help from the inspect module for getting which arguments to extract and so on) not that I recommend sth like this...
Ideally you would extend your linter to issue warnings for wrong method calls with super. but its not the way super was meant to be used, its intentionally left to the programmer to choose the method to call, more power, more responsiblity XD. they could have literally made the parser recognize unmatched method calls or even just add the appropriate method call just like how super() (with no args) works, but they didn't. you better not fight the language.
(didn't notice ppl already suggested that above)
TIL you can give functions attributes:
>>> x = lambda: None
>>> x.test = "Hello, world!"
>>> x.test
'Hello, world!'
it only works for functions written in python though
you can't attach attributes to functions that are from C modules
what's the explanation of that behavior
i was looking up empty classes and came across a bunch of useful stuff i didn't know about, like simple name spaces
BuiltinFunctionType objects don't have a dict
fair
still tryina figure out how to apply a decorator to every function that gets defined :(
a metaclass?
The metaclass is passed the class dict, so you can map that dict onto a new one with decorated functions using any number of techniques and feed it into type
Unless you mean every function in the whole program.
Maybe you could do that with sys.settrace monitoring globals()
Or, the simpler option: do the globals() check once, after you've declared all your functions.
[mem for _, mem in inspect.getmembers(MyClass) if inspect.isfunction(mem)] should give you all the user-defined functions @grave rover then all you need is to define a decorator for the class you want all its methods
or use inspect.isfunction in a metaclass with the dict passed in. you don't want to also decorate superclasses methods.
how can I add code to the end of a method using ast?
You can't just use a decorator?
@snow beacon I need to add super to the end of each method.
in order to experiment
Before
class A:
def a(self, **kwargs):
pass
After
class A:
def a(self, **kwargs):
pass
super().a(**kwargs)
from functools import wraps
class A:
def a(self, **kwargs):
pass
a = A()
@wraps(a.a)
def patched_a(self: A, **kwargs):
self.a(**kwargs)
super().a(**kwargs)
a.a = patched_a
would something like this suffice?
that super call might need a little tweaking though
not sure how it'll operate in this context
or does it specifically have to be via AST?
@tepid pulsar that doesn't make it so if I import a library all of its functions will be patched tho
I mean like ```py
register_global_func_wrapper(some_func)
def abc(...):
...
abc is now wrapped with some_func```
Define "all of the functions"
Every single function defined anywhere, or top level functions, or?
Any (non-anonymous) function defined anywhere
You can do it with ast.parse, catching "FunctionDef", although I've never used it before
@brazen geyser Is it possible to make it work with every method (that not startswith __), for example using metaclass?
@brazen geyser should your code work?
from functools import wraps
class A:
def a(self, **kwargs):
pass
a = A()
@wraps(a.a)
def patched_a(self: A, **kwargs):
self.a(**kwargs)
super().a(**kwargs)
a.a = patched_a
a.a()
Traceback (most recent call last):
File "main.py", line 15, in <module>
a.a()
TypeError: patched_a() missing 1 required positional argument: 'self'
also I don't get what does
self: A, **kwargs```
mean
my bad, i didnt test the code
you gotta use MethodType to create a new method
so like this
from types import MethodType
from functools import wraps
class A:
def test(self, **kwargs):
print('A test', kwargs)
class B(A):
def test(self, **kwargs):
print('B test', kwargs)
old_test = B.test
@wraps(B.test)
def new_test(self: B, **kwargs):
old_test(self, **kwargs)
super(B, self).test(**kwargs)
b = B()
b.test = MethodType(new_test, b)
b.test()
you could also replace B.test directly
like this:
B.test = new_test
b = B()
b.test()
as for Is it possible to make it work with every method (that not startswith __), for example using metaclass?
yea probably
you can use inspect.getmembers(B, inspect.isfunction) to get a list of all of B's user defined methods
along with their names
then you can use setattr(B, function_name, new_function) to replace it
at least thats how i think it might go
thanks I'll try this way)
@brazen geyser I am confused here
from types import MethodType
from functools import wraps
class MyMeta(type):
def __init__(cls, name, bases, dct):
super().__init__(name, bases, dct)
methods = cls.get_object_methods(cls)
for method_name in methods:
method = getattr(cls, method_name)
old_test = method
@wraps(method)
def new_test(self: cls, **kwargs):
old_test(self, **kwargs)
super(cls, self).test(**kwargs)
method = MethodType(new_test, cls)
setattr(cls, method_name, method)
def get_object_methods(cls, object):
object_methods = [method_name for method_name in dir(object)
if callable(getattr(object, method_name)) and not(method_name.startswith('__') and method_name.endswith('__'))]
return object_methods
class A:
def test(self, **kwargs):
print('A test', kwargs)
class B(A, metaclass=MyMeta):
def test(self, **kwargs):
print('B test', kwargs)
b_inst = B()
b_inst.test()
B test {}
Traceback (most recent call last):
File "main.py", line 46, in <module>
b_inst.test()
File "main.py", line 18, in new_test
super(cls, self).test(**kwargs)
TypeError: test() missing 1 required positional argument: 'self'
you dont need to use MethodType when replacing the class attributes
only for replacing bound methods on already existing instances
so setattr(cls, method_name, new_test)
im also not sure why def get_object_methods(cls, object): has the object param at all, since it's a duplicate of cls
oh really it works now? wow
@brazen geyser but if I have another method not named test how to write this line in that case? python super(cls, self).test(**kwargs)
super(cls, self).method
I need something like that.
@wraps(method)
def new_test(self: cls, **kwargs):
old_test(self, **kwargs)
super(cls, self).getattr(method_name)(**kwargs)
youll also probably have to spawn this off into another function altogether to keep method_name inside a local scope so it doesnt change
class MyMeta(type):
# ...
def new_method(cls, method_name, old_method):
@wraps(old_method)
def result(self, **kwargs):
old_method(self, **kwargs)
#super(cls, self).getattr(method_name)(**kwargs)
getattr(super(cls, self), method_name)(**kwargs)
return result
super(cls, self).getattr(method_name)(**kwargs)
Is this right
AttributeError: 'super' object has no attribute 'getattr'
derp, __getattr__
or, getattr(super(cls,self), method_name)
ah, you cant even call __getattr__ from the outside with the dunders
so yeah, getattr(super(cls,self), method_name)
from types import MethodType
from functools import wraps
class MyMeta(type):
def __init__(cls, name, bases, dct):
super().__init__(name, bases, dct)
methods = cls.get_object_methods()
for method_name in methods:
print (method_name)
method = getattr(cls, method_name)
old_test = method
@wraps(method)
def new_test(self: cls, **kwargs):
old_test(self, **kwargs)
getattr(super(cls,self), method_name)(**kwargs)
setattr(cls, method_name, new_test)
def get_object_methods(cls):
object_methods = [method_name for method_name in dir(cls)
if callable(getattr(cls, method_name)) and not(method_name.startswith('__') and method_name.endswith('__'))]
return object_methods
class A:
def test(self, **kwargs):
print('A test', kwargs)
def test1(self, **kwargs):
print('A test1', kwargs)
#class B(A): # without metaclass
class B(A, metaclass=MyMeta):
def test(self, **kwargs):
print('B test', kwargs)
def test1(self, **kwargs):
print('B test1', kwargs)
b_inst = B()
b_inst.test()
well .. seems to work)
there's also this
>>> class A:
def test(self):
pass
>>> class B(A):
pass
>>> getattr(B.__mro__[1], 'test')
<function A.test at 0x0000027D19A35D38>
>>>
so you can store a reference to the super function beforehand
therefore without needing to even call super() each time
@brazen geyser thanks a lot! I really didn’t know many things, to be honest I still do not fully understand everything that is happening here) I think I need to take a few hours to comprehend all this.
so even if I don’t need these tricks with the “super”, then in any case, this is a very useful experience.
no worries
I bet me2beats is Russian 🤔
@marsh void yep, did you understand this because of my bad english?:)
@sick hound no, because we, Russians, tend to write hello) and stuff
And your English is good, but let’s not continue since it is esoteric-python
@brisk zenith want to try and make that actually work? ^
Like make it actually print unbelievable
Without changing the comparisons
if 1 == 1:
if 1 != 1:
print("unbelievable")
``` so basically make this actually print
Ctypes should make it do-able right?
yeah i reckon it'll be quite easy
how?
same way its done here, but we replace the existing token
maybe
actually i dont think that works
class myInt(int):
def __eq__(self,*args): return True
def __ne__(self,*args):return True
myInt.__hash__ = int.__hash__
from ctypes import *
py_object.from_address(id(1)+sizeof(c_size_t)).value = myInt
if 1 == 1:
if 1 != 1:
print('unbelievable')
@brisk zenith ctypes worked tho
yup, i was thinking of doing the same sort of thing :D
except on a lower-level
i was gonna modify the tp_richcompare c function pointer in the PyLongObject type struct to make ints always return True on all comparisons
Ah that would be cool
i managed to get it work using my cpystructs helper module but i couldn't figure it out without it for some reason
i'm rewriting that module anyways
Noice that module is really cool
it was never completed and the code wasn't great, but it most definitely helped a lot with this sort of hackery even in its early stages haha
it's a bit much when i'm importing a private class from _ctypes
yeah a bit lmao
@sick hound the hash thing is because for some reason myInt would occasionally not inherit it from int ```py
Python 3.6.8 (default, Jan 14 2019, 11:02:34)
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
class myInt(int):
... def eq(self,*args):return True
... def ne(self,*args):return True
...
myInt.hash
this could cause segfaults and/or TypeError
@brisk zenith i have a challenge for you. idk if its possible but hey why not. implement an operator in python like ++
without modifying the interpreter
what determines whether __builtins__ is a dict or module at module start?
@calm rampart wdym?
like, ```
C:\Users\Random>echo print(type(builtins)) > foo.py
C:\Users\Random>py -m foo
<class 'module'>
C:\Users\Random>py
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
import foo
<class 'dict'>
it seems like it's a module in the main script (same result for py foo.py) and a dict in imported modules
It may replace it's module with it's dict using globals
apparently not... anyway, the module loader is presumably written in C and has access to references to both the module and the dict, it's just unusual it makes one choice for main script and the other choices for imported modules
Yeah that is a bit weird
which object is interp->builtins
ok it's the dict
ok, here is where it sets it for the main module
and here, i think, is where it's set for imported modules
weird
No kidding
What are some cool uses for the assignment expressions that are coming in python 3.8?
@gilded orchid some things like that
if (obj := database.get(obj)).is_valid:
do_stuff_with(obj)
More info here https://www.python.org/dev/peps/pep-0572/
reading stuff in chunks
with open(path) as file:
while chunk := file.read(1024):
#...
@brazen geyser that one is nice
make some list comprehensions nicer, e.g.
my_list = [a:= A.T**-1 for A in some_matrices if a == 1 or a == -1]
so i don't have to compute that hard thing to compute an infinite number of times
Your code won't run, though, since the conditions at the end get evaluated before the item portion at the start of the list comprehension
my_list = [a for A in some_matrices if (a := A.T**-1) == 1 or a == -1]
That will, but I'm not sure if it's more readable than an explicit multiline for-loop to avoid the costs
Guess I just need to get used to it
i really hate a whole line for assignment when the variable is a one-off
It depends on the context. I'd say I prefer adding a line if it aids readability over one-liners that take a couple of seconds to decipher in a real project
Lines don't really cost me anything, but having to figure out what a complicated one-liner does when I read code takes me time
That said, I am a fan of list comprehensions in general
i have written somn particularly foul one-liners in my time
For example, here's one for an old challenge we did here:
line_gen = (lambda t, r: map(lambda line: chr(32).join(line), list((lambda tran, text:(lambda derot:(lambda lines:list([(yield (lambda words:r.sample(list(map(lambda word: word.strip(derot[63] + derot[855]), words)), len(words)))(line.split())) for line in lines[1:]]))(derot.splitlines()))(text.translate(tran)))(str.maketrans(t.d), t.s))[1:]))(__import__("this"), __import__("random"))
(lambda x:x(x,(lambda x:[[[0]*len(x[i]) for i in range(len(x))],x])((lambda a:(lambda x,y:[[[[x[r].pop(c), x[r].insert(c,'*')] if y[0][r][c] else [x[r].pop(c), x[r].insert(c,y[1][r][c])] for c in range(1,a-1)] for r in range(1,a-1)],x][-1])([[0]*a for x in range(a)],(lambda x:[[[[[(lambda x,y:[y.append(x[1][r][c]), x[1][r].pop(c), x[1][r].insert(c,y[0]+1)])(x,[]) if x[0][l][j] else None for j in range(c-1, c+2)] for l in range(r-1, r+2)] for c in range(1,a-1)] for r in range(1,a-1)], x][-1])((lambda x:[[[[x[0][r].pop(c),x[0][r].insert(c,int.from_bytes(open('/dev/urandom','rb').read(1),'big')/10 > 20)] for c in range(1,a-1)] for r in range(1,a-1)], x][-1])([[[0]*a for x in range(a)] for x in range(2)]))))((lambda i:i if i > 2 and i < 12 else exit())(int(input('Board Size (max 9): '))+2)))))((lambda x,y,p=(lambda x:[print(' ',*range(1,len(x[0])-1),sep=' '),[[[print(r,end='') if c == 0 else [print(' ',end=''),print(['■','F'][x[0][r][c]], end='') if x[0][r][c] != 2 else print(x[1][r][c], end='')] for c in range(len(x[0])-1)],print()]for r in range(1,len(x[0])-1)],x][-1]),i=(lambda f,i:[f[0][int(i.split(',')[0])].pop(int(i.split(',')[1])),f[0][int(i.split(',')[0])].insert(int(i.split(',')[1]),{'f': 1,'c': 2}[i.split(',')[2].lower()]),[print('You Lose'),exit()] if f[1][int(i.split(',')[0])][int(i.split(',')[1])] == '*' and i.split(',')[2].lower() == 'c' else f][-1]),q=[]:[p(y),q.append(i(y,input('Type Row,Column,[(F)lag or (C)lear]: '))),x(x,q[0]) if not (lambda y,q=[],w=[]:[[[q.append(y[0][r][c] == 1 and y[1][r][c] == '*') for c in range(len(y[0][r]))] for r in range(len(y[0]))],q][-1].count(True) == [[[w.append(y[1][r][c] == '*') for c in range(len(y[1][r]))] for r in range(len(y[1]))],w][-1].count(True))(y) else print('You Flagged All The Bombs!')])) ``` @pure dew
How's this one?
Guess what it does lmao
summon the devil
Run it. But be warned it only works on Unix based systems
looks like a minesweeper game
Isn't that just minesweeper mate
Yeah it is
@torn moth that’s one line of code lol
Like a 3 days
minesweeper?
Cause I have a strategy for onelining. Some of my more exotic oneliners took way longer
wait i was scrolled up
i also have a strategy for one-lining @rugged sparrow :D
list comps ftw
'''
tryExceptRet(t,a,f,e)
t=try func, can have args
a=tuple of args for try lambda #not passed to except lambda
f=except func #can have up to three args, which will be the Exception Class, Exception Instance, and Traceback
e=tuple of Exception types to check for
#all args optional except try func
'''
tryExceptRet = lambda t,a=(),f=lambda:None, e=(Exception,),r=[]:(lambda q=type('',(*filter(lambda x:'tDe'in x.__name__,object.__subclasses__()),),{'__enter__':lambda s:0,'__exit__':lambda s,*a,c=f.__code__:[r.append(f(*a if c.co_flags == 71 else a[0:c.co_nlocals]))] if issubclass((a[0] or object),e) else 0})()(t)(*a):q if q != None else r.pop() if r else None)()``` @pure dew
noice
i don't like that so much because you're modifying the bytecode, and so it's difficult to actually say it's "one line" when it's also some other bits of code
While it's true there are other lines through the ContextDecorator, where am I modifying bytecode? Or is that also in the ContextDecorator @brisk zenith ?
is it not that bit with the f.__code__ stuff?
Nah that's to make the except lambda work with *args or arg1,arg2 #no arg 3
It lets me get the number of args and the co_flags
$ python -m timeit -s "import random" "round(random.random())"
1000000 loops, best of 5: 235 nsec per loop
$ python -m timeit -s "import random" "random.choice([0, 1])"
200000 loops, best of 5: 982 nsec per loop
$ python -m timeit -s "import random" "random.choice([True, False])"
200000 loops, best of 5: 999 nsec per loop
$ python -m timeit -s "import random" "[True, False][round(random.random())]"
1000000 loops, best of 5: 333 nsec per loop
wtf why is random() faster than choice on a tiny list
$ python -m timeit -s "import random" "[True, False][int(random.random() * len([True, False]))]"
500000 loops, best of 5: 437 nsec per loop
I don't know, but from experience I know it's the case
$ python -m timeit -s "import random" "int(random.random())"
1000000 loops, best of 5: 213 nsec per loop
$ python -m timeit -s "import random" "round(random.random())"
1000000 loops, best of 5: 238 nsec per loop
int is a little faster but can't be overoptimized for the two choice case
needs an addition/multiplication, which takes longer than round()
so round(random.random()) is the best coin flipper?
And yes, random.random() is C, but choice is not
As far as I can tell
Oh this is a great comment from the c source
note that
- 9007199254740992 == 2**53; I assume they're spelling "/2**53" as
- multiply-by-reciprocal in the (likely vain) hope that the compiler will
optimize the division away at compile-time
i wonder if numpy.choice is faster
lets find out..
$ python -m timeit -s "import numpy" "numpy.random.choice(1)"
50000 loops, best of 5: 8.48 usec per loop
christ numpy
$ python -m timeit -s "import numpy" "numpy.random.choice([False, True])"
20000 loops, best of 5: 9.93 usec per loop
numpy OP
$ python -m timeit -s "import numpy; a = numpy.array([True, False])" "numpy.random.choice(1, size=1000)"
10000 loops, best of 5: 27.6 usec per loop
Numpy's optimized for chunk-getting random it seems
cause that's 27.6ns per choice there
o i read it wrong
can you time just the parts after the import
>>> import numpy as np
>>> import timeit
>>> timeit.timeit("np.choice(np.array([True, False]))", number=10000)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/timeit.py", line 237, in timeit
return Timer(stmt, setup, timer).timeit(number)
File "/usr/lib/python2.7/timeit.py", line 202, in timeit
timing = self.inner(it, self.timer)
File "<timeit-src>", line 6, in inner
NameError: global name 'np' is not defined
oh, am i in the wrong python
i still have the same error in 3.6
odd
lemme try with setup
this works:
>>> timeit.timeit("np.random.choice(np.array([True, False]))", setup="import numpy as np", number=10000)
also it was np.random.choice and not np.choice
Is there a shorter way to do this?
from random import*
random.randint(0,1)
I tried using id() and os.urandom, but I couldn't get either of them to be shorter
shortest as in least amount of code? because Bast seemed to find the fastest was round(random.random())
Least amount of code (including imports), not fastest
if you did a starred import can't you just refer to the function as randint(0,1)
>>> from random import*
>>> randint(0,1)
1
>>> randint(0,1)
0
Oh yeah, oops
But is there a way to do it without using random, cos that's a lot of bytes in a code golf
how many times do you call the function?
>>> from random import randint as r
>>> r(0,1)
1
>>>
a bit longer import string.. not sure it would be worth it in your case
(8&id([[]]))>>3
Seems to change each time
Actually, if you don't mind a boolean, delete the second >
And the brackets.
whats id() do
Generally it's the id in memory, at least in CPython
Return the identity of an object.
This is guaranteed to be unique among simultaneously existing objects. (CPython uses the object's memory address.)```
specially nice to tell people why == and is are totally different
also that's a smart way to use it
So 8&id([[]])>3 makes a new list object, takes the third bit, and checks if it's 8 or 0
Third most significant bit, that is
can you use an empty list, or does it have to be a list with an empty list
Empty list is interned
Which means they don't create new objects each time.
At least, it seems that way in the interpreter.
how about 0-tuples
Nah, that's immutable, it probably just interns all the short ones
seems to be constant
weird, id({1}) jumps between two values for me
id([1]) seems kinda random
I think all empty sequences are.
Yes, but if you use it more than once in the same program
for _ in range(100):
print(id([[]]))```
2329381786184
2329381786696
2329381786184
2329381786696
2329381786184
2329381786696
2329381786184
2329381786696```
though some objects have constant IDs
-10 is shorter
Why it's jumping back and forth? lol
oooooooh
It's pseudorandom
pfff, we need the codegolf way to curl random.org
lol list() is an interesting one
at first it seems random
but later on it's the same behaviour as [[]]
alloc then delloc
set() is shorter
[1] shortest i think
>>> for _ in range(100):print(id([1]))
...
19745368
19745368
19745368
19745368
19745368
19745368
19745368```hmmm
set() and [1] gives fixed value for me
i was getting different values
they are fixed objects.. strange that it reuses the old memory addresses
In [79]: id([1])
Out[79]: 139721610400840
In [80]: id([1])
Out[80]: 139721610395400
In [81]: id([1])
Out[81]: 139721610385032
In [82]: id([1])
Out[82]: 139721610400712
python 3.6
no cython though
do you have to delete the ref before you make it again?
for _ in range(100):
a = [1]
print(id(a))
2395210797640
2395210798152
2395210797640
2395210798152
2395210797640
2395210798152
2395210797640
2395210798152```
lol
ha
If you were golfing, unless you have a loop, you could just specify a different digit each time you call the function.
i feel like im being fooled
!e
for _ in range(8):
a = (_,)
print(id(a))
@tropic night Your eval job has completed.
001 | 140565156275144
002 | 140565156409472
003 | 140565156275144
004 | 140565156409472
005 | 140565156275144
006 | 140565156409472
007 | 140565156275144
008 | 140565156409472
x.append() @distant wave
!e
for _ in range(8):
a = (_,)
print(id(a))
del(a)
@tropic night Your eval job has completed.
001 | 140648784765896
002 | 140648784765896
003 | 140648784765896
004 | 140648784765896
005 | 140648784765896
006 | 140648784765896
007 | 140648784765896
008 | 140648784765896
rip
so it reuses the ide when you delete it
I think you have to avoid deallocating the old object
it gets GCed but is not ready for the next iteration, hence the back and forth
!e
a = []; for _ in range(10):a+=[a];print(id(a))```
Sorry, but you may only use this command within #bot-commands.
i cri too
a=0, and then a=id(a)
Doesn't work for me
rip
I think a=(a,) works
it does work
that would be the same as adding del(a) would it not?
a = []
for _ in range(10):
a = (a,)
print(id(a))```
2345975470472
2345977149832
2345977112520
2345980053320
2345979993736
2345979993672
2345980053256
2345979993032
2345979993352
2345979993288```
lol
del a is counterproductive. We want to avoid repeating ids
In [111]: a = 0
...: for i in range(10):
...: a = id(a)
...: print(a)
10968768
139721610451984
139721610451920
139721610451984
139722060305872
139721610451952
139722060305872
139721610451952
139722060305872
139721610451952
We're fighting the garbage collector to get Python to keep allocating memory
starts repeating
yeah, thats what i meant, though not phrased good enough
is there some way we can hold a reference to it somewhere
The a=(a,) stores the old a
oh yeah
Inside the new a
!e
a = []
s = set()
for _ in range(1000000):
a = (a,)
s.add(id(a))
print(len(s))
@tropic night Your eval job has completed.
timed out or memory limit exceeded
oh..
lol
that would've been a nice eval
!e
a = []
s = set()
for _ in range(10000):
a = (a,)
s.add(id(a))
print(len(s))
@tropic night Your eval job has completed.
10000
So that works. Now to golf it
then i take my leave 😄 you guys can golf it away 😄
a=[a] is one less byte, does it work as well
Setup code is a=1, then each time you need to do a=[a] and evaluate 8&id(a)>3
With Python 3.8 assignment operators you can probably do 8&id(a:=[a])>3
i love walrus
'walrus'?
That assignment operator thing doesn't work (
https://tio.run/##K6gsycjPM7YoKPr/P9E2OpYrLb9IIVMhM0@hKDEvPVXD0EDTiktBQSHRViNRRxPEKijKzCvRsFDLTNFItLKNTozVtDPW/P8fAA) @snow beacon
try an extra set of parenthesis around it
I think it's the 8& bit
hmm, i think the scope of a before the assignment is limited too
changed to 8&id(a:=[a])>>3 and it shows 0 or 8
but removing the > will always be false
lol
oh
that's better
Looks like it stores objects with 64 bits of memory
cant wait for this walrus
I wish
I mean I do have it for local testing
but to write distributable scripts with it, welp
You could package it with the Python version
a=[]
for i in range(10):
a=[a]
print(id(a)%3%2)
mod something not divisible by 2 first, then mod 2
that's not uniform though
a=1
for i in range(10):
print(id(a:=[a])%3>0)
is that the same length as the other version
saves a byte
oh thats not uniform either, hm
id is implementation-defined anyway
x = ([1, 2], 3)
x[0] += [4, 5]
Vote
if you think this will mutate the list, or vote
if you think it will error
(try not to run in repl first)
||```py
x = ([1,2],3)
x[0] += [4,5]
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
x[0]
[1, 2, 4, 5]
x
([1, 2, 4, 5], 3) ```||
@drowsy cobalt ???
^ spoiler
||I guess I vote both since it mutates the list and errors||
The reason it happens is
||First the value of x[0] (so in this case the mutable list) is put on the top of the stack
+= is evaluated on the list object successfully, the list is mutated
The result of the previous operation is assigned to x[0], this fails as tuples are immutable
FWIW I've never ever seen this in real code. Moral of the story is tuples are immutable but their contents are still just as mutable as they were before||
||```python
a = []
b = (a, "<- mutable?")
b
([], '<- mutable?')
a.append("yes")
b
(['yes'], '<- mutable?')
could it be convenient to have this syntax?
class A:
def a(x, y = x):
print (y)
A().a(1)
#--->
#1
(not sure if I choose the right channel)
eh i can see some situations, especially if it can be any expression involving previous arguments
but it's at odds with the whole way python default arguments work
the usual solution is
def a(x, y = None):
if y is None:
y = x
but it is not so readable imo
the only times i've had to do that, I've had enough of them to make it worthwhile to use kwargs
interesting @drowsy cobalt if i do += it will raise error but assign anyway
.append() will just append and mutate the list inside tuple
@brazen geyser
don’t see a way how to do this with decorator, could you just give a hint?
well, it would be super jank
and youd need some way to specify y=x using a special value
maybe a class
then inside the decorator, you return a wrapper that checks the args/kwargs for values of this type and replace them
and use inspect to figure out the values associated with positional args
iirc there's getargspec as one option
overall your signatures would look something like this:
@magic_decorator_goes_here
def test(x, y=PreviousArgument('x')):
pass
or maybe OtherArgument since order wont matter as youll have all the values at once anyway
very much not worth the effort/overhead
but could be a fun exercise
@brazen geyser thanks. yea, I'll think if I need to do it at all
Okay, I made this: https://gist.github.com/dzil123/ce01158e30eca73bd0c82d2e487424be
I put in checks to simplify the actual algorithm, meaning you can't have Args that point to other Args
Also, there's a bug in inspect.BoundArguments where it doesn't keep keep track of which argument were originally args or kwargs
So this will probably fail on functions with *args or **kwargs in their signature
noice
@jade dust omg, cool! thanks for sharing)
constants doesn't exists in python?
Opinions on elvis operator and deratives and if they belong in python?
i.e. ?:, ?., ? :, etc
!e ```python
my_list = []
print(my_list or "hello_world")
my_list = [1, 2, 3]
print(my_list or "hello_world")
@formal sandal Your eval job has completed.
001 | hello_world
002 | [1, 2, 3]
http://docs.hylang.org/en/stable/ for anyone who hasn't seen it yet
i always liked how lisp looked, but not as much as i like how python looks
This hylang looks quite terrifying
that's parsed as not not (None is None)
and None is None, so not not True is not False is True
ah, got it)
or operates in a different way than would an elvis operator if it existed, elvis operator is all about "None-awareness", or null-safety. imo the only use case that I find it really useful is for default args, instead of doing val if val is not None else some_default you'd do val ?? some_default. I don't know how I feel about it really kinda excited kinda don't see much use for it in a dynamic lang, In Kotlin its a highly praised feature, but its also supported by the compiler to provide smart casts and whatsnot, maybe that will be the case for python too because of type hinting support. btw here is the pep for it, its deferred currently https://www.python.org/dev/peps/pep-0505/
don't get me wrong I am all in for an elvis operator, just don't see much use for it in my code 🤷 I'd rarely use things like null safe member access.
Not entirely esoteric but I'm wondering how python assigns tuples and people who understand python a bit deeper seem to be around here
Got this test code, but getting various outputs on different interpreters
print((1,) is (1,))
print(([],) is ([],))
a=(1,)
b=(1,)
print(a is b)
([],) and ([],) will always be different because they create new lists
yeah those two are the only ones I'm sure about
(1,) and (1,) seem to be separate values in python 2, and constants in python 3, but whether or not they're the same constant depends on the interpreter
actually, nevermind, it looks like they're always different?
I get True for the first one and False for the third one
in python 3.7 they're the same constant
for the third one, what happens depends on if you do it all at once or as lines in an interactive interpreter/REPL
or at least it does in 3.7
before 3.7 they're always different constants anyway
in python 3.7, if you do them as separate lines, they get compiled separately and different constants are generated
but if you do them in the same line they're the same constant
it looks like it keeps them in some sort of a cache that gets deleted shortly affter or something like that
not exactly a cache, python code gets compiled into a code object and that code object has a list of constants in it
getting same ids once in a while when I spam id on it, but that could also be just python putting it into the same place
(1,) is (1,) gets compiled into one code object, and the (1,) only needs to be one constant
but if you do it as separate code objects, they have separate lists of constants
it's like this example ```py
x = 257; x is 257
True
x is 257
False```
if you do 257 twice in the same code object, you get the same 257
but if you do it once and then again in another code object, you get a different 257
at least an empty tuple is always the same thing, from what I can see
makes sense that that would be stored somewhere, like None
yep, an empty tuple is always the same thing, which means you can change it into something different and break stuff
>>> ()
SystemError: ..\Objects\tupleobject.c:138: bad argument to internal function```
well actually now doing anything breaks
mutating an empty tuple is a really bad idea
it's trying to check the size of an empty tuple
Hylang is neat, I've played around with it
Hylang is like python but no
Not related to python, but... I added decent OOP to Lua ```lua
class "B" {
__ctr = function(self, val)
self.a = val
end
}
class "A" : extends "B" {
__ctr = function(self, val)
super(self):__ctr(val)
end,
help = function(self)
print(self.a)
end
}
x = A(10)
x:help() -- => 10```
apparently function calls are interesting in lua: lua func("abc") func "abc" func [[abc]] -- [[ ... ]] are multiline strings in lua are all the same, similarly: ```lua
func({a: 1})
func {a: 1}
then I use the fact that you can add metamethods to objects (called magic functions / operator overloads in python) to make them callable and stuff
next update I'm adding to this is a __meta field that defines the metatable it has
im tempted to call python / pyd from lua, how possible is that lol
I can never get into lua
They both have a fairly simple interface in C
@crystal mica make sure to look at https://github.com/bastibe/lunatic-python if you wanna do more with calling python from lua or the other way round
thank you
yeah but it never had class statements or inheritance or anything
thats what I added :D
Does Brainfuck have an API for calling Python functions yet?
it does have classes prototypes
not class statements, but (close to) classes at least https://www.lua.org/pil/16.1.html
and inheritance https://www.lua.org/pil/16.2.html
that's the hackiest inheritance I've ever seen and also makes regular instances too bloated
though @brazen geyser if you wanna help out with this project, let me know, I can DM the source
it's more or less the same system as js before ES6
and afaik the ES6 stuff is basically syntactic sugar anyway
sure id be keen to take a look, but im not too keen on working with lua in general 😅
for me it's one of those necessary evils for specific circumstances
also we're veering off topic 
Speaking of Lua, does anyone know a way to get Python list indices to start at 1?
You can make a custom dict subclass that does that for you
I mean normal lists themselves. [1,2,3][1] would be 1
You'd have to patch python
!e ```python
class CustomList(list):
def init(self, lst, start=0):
super().init(lst)
self.start = start
def __getitem__(self, index):
return super().__getitem__(index - self.start)
def __setitem__(self, index, value):
super().__setitem__(index - self.start, value)
A = CustomList([7, 8, 9, 10, 11], start=1)
print(A[1])
print(A[2])
print(A[3])
@formal sandal Your eval job has completed.
001 | 7
002 | 8
003 | 9
But A[0] will return the last element, which is weird.
well, easy to raise an index error if it's 0
If the array starts at 7, it's weird that 6 points to the last element.
arrays start at 2
is that weirder than the array starting at 7?
Well, for example, Pascal supports custom array index ranges (b: array [50..100] of Integer;). You might want to reproduce this feature.
if index < self.start: raise IndexError
problem fixed 😛
What if your want 0 to be a error but not -1? If start is not 0
if index in range(0, self.start): raise IndexError(index)
if 0 <= index < self.start: raise IndexError(index)
👍
try implementing excel's INDEX function
index to (index-self.start) % self.__len__() for the full periodic boundary condition experience
what if you made the list indexes start at the end of the list
so wat[0] is the last element of wat, and wat[1] is an IndexError

guys, i've done a bad thing.
what have you done
a function and a class method inside of a function inside of a class method
doesn't sound too bad
# QuantumGate.pauli_x() right now would give AttributeError
@QuantumGate.register()
def pauli_x():
return [
[0, 1],
[1, 0]
]
# but now it doesn't.
x = QuantumGate.pauli_x()
it gives nice results though
@classmethod
def register(cls, name: str = None):
if name is not None and not name.isidentifier():
raise ValueError("Quantum gate name must be a valid identifier")
def decorator(func):
nonlocal name
if name is None:
name = func.__name__
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
if not isinstance(result, cls):
result = cls(result)
return result
@classmethod
def method(_, *args, **kwargs):
return wrapper(*args, **kwargs)
setattr(cls, name, wrapper)
return wrapper
return decorator
wait i forgot one thing there we go
of course, it'll be used for defining gates dynamically based on the args and stuff.
actually i made it a bit better.
What's golfing? Real life golfing or python golfing?
🤔
well this is a python server, so I would say: python golfing
@formal sandal you could make it take an iterable instead of two digits to make it more like regular for loops
Maybe it's also a good idea to make these loops 'lazy'.
So that I can store them and call on demand.
Unfortunately, __bool__ must return either True or False, so I have to ditch the fancy return values.
Maybe it would make sense to store the last fancy return value.
you dont even need the lambda in there for that one
True.
does anyone mind doing some independent timeits for me? trying to see if cv2.filter2D is faster than scipy.ndimage.convolve
Is it possible to rewrite the add function for numbers?
i believe so, but it would be tricky and very very very unstable
I don't care I just want the python console to say 1+1
3
oh, well in that case you can overwrite the value of 2 in memory with 3
!e ```py
import ctypes
ctypes.memmove(id(3), id(2), int.sizeof(3))
print(1 + 1 == 3)
@brisk zenith Your eval job has completed.
True
overwriting int.__add__ is significantly more difficult though
Hi what is a functions __closure__ attribute for?
I tried it and it said that the add func is read only
from ctypes import *
class myInt(int):
def __add__(self,other):
if self == 1 and other == 1:
return 3
else:return super().__add__(other)
py_object.from_address(id(1)+sizeof(c_size_t)).value = myInt
print(1+1==3)```
@sick hound ^ this would work too
i think at least
@whole kiln it shows you the variables that a closure can access which aren't in its local scope but aren't in the global scope, i believe: ```py
In [5]: def func(string):
...: def closure():
...: print(string)
...: return closure
...:
In [6]: x = func("hello, world!")
In [7]: x()
hello, world!
In [8]: x.closure
Out[8]: (<cell at 0x7f1d541ac948: str object at 0x7f1d542c4330>,)
In [9]: x.closure[0].cell_contents # this would be the string variable in the func function
Out[9]: 'hello, world!'
I thought it was something like that but I tried defining local variables in the parent function and they didn't show up
it's not just local variables in the parent function, it's variables in the parent function that the function with the closure accesses
ah so it has to actually use them
makes sense
In [4]: def function(name):
...: greeting = "hello "
...: def greet(amount):
...: for _ in range(amount):
...: print(greeting + name)
...: return greet
...:
In [5]: f = function("mark")
In [6]: f(5)
hello mark
hello mark
hello mark
hello mark
hello mark
In [7]: f.__closure__
Out[7]:
(<cell at 0x7f0abcbfb1f8: str object at 0x7f0abcc696c0>,
<cell at 0x7f0abcbfbb28: str object at 0x7f0abffe6ab0>)
In [8]: f.__closure__[0].cell_contents
Out[8]: 'hello '
In [9]: f.__closure__[1].cell_contents
Out[9]: 'mark'
In [10]: # notice the `amount` isn't there (obviously, because it changes for each call to the closure)
thanks
when i write this code, and python execute it, i'm giggle
__slots__ = ['data'].extend(list(data.keys()))
why that line of code didn't throw any error, and didn't return anything?
@unkempt cloak because extend call doesnt return the list it self, it mutates an existing list
['data', *data.keys()]
is what you are looking for i believe
np
@rugged sparrow That was what I meant. You don't have to include punctuation or numbers in the rhyme scheme, but ideally every line of code would rhyme with another.
I love how if yout RT googling for how to replace the string class in python
All the search results say you can't
Just casual lurking in this chat had like ten different ways of doing it
still looking for a way to define a global function wrapper that applies itself to every function defined after it
is there a way somebody would beable to redefine the keywords like "if" and "pass" ?
cuz i want to make a module that just fucks around and destroys python, like redefining false to truent and true to falsnt and messes up calculations
ik
but can i change the keywords?
i mean in that specific script, not globally on my pc
Well, you could write your own interpreter...
>>> ctypes.memmove(id(True), id(False), int.__sizeof__(True))
1555948208
>>> True
True
>>> False
False
>>> True==False
True
>>>
Why do true and false still show up as true/false despite the fact that I did a memmove?
I thought it'd make it so True returned False, but it doesn't?
oh i just read something about that i think
hmm cant find it
@sick hound that's in python 2 where True and False are just names
@gilded orchid if you check int(True) it's 0, but I guess the stringification of bools is based on their id
so if u can swap true and false
could u swap while and if
no
and for and import
no
darn
True and False aren't keywords at all in python 2
im talking about python3
you can't swap true and false in python 3
you can change their values but that's just because they're objects
the actual keywords aren't affected
what does this code do:
from ctypes import *
class myInt(int):
def __add__(self,other):
if self == 1 and other == 1:
return 3
else:return super().__add__(other)
py_object.from_address(id(1)+sizeof(c_size_t)).value = myInt
print(1+1==3)
it makes it so that 1+1==3
it changes 1 to have a type of myInt
but how what gets changed?
oh
>>> type(1)
<class '__main__.myInt'>```
can i do that for all ints at once?
instead of doing that in a for loop till forever?
well no, only the ints from -5 to 255 (iirc) are cached, so those are the only ones you can change
oh
but you could change the actual int type with ctypes and that would affect all of them
how?
I don't know, we're not some kind of cpython structure expert
i tried rewriting int.add and it said its read only
yes, you can't just assign to it
omg
i think i got it in vanilla python without ctypes
leme type it out
it probably is possible to overwrite the entire int type but i doubt it would be reasonably stable
@sick hound that won't work
it doesn't
as far as i know
that doesn't change actual integers
actually it doesn't change anything, it raises a NameError
!e ```py
class myInt(int):
def add(self,other):
return self+other+1
int = myInt
print(type(1))```
@brisk zenith Your eval job has completed.
<class 'int'>
>>> class myInt(int):
def __add__(self,other):
return self+other+1
>>> int=myInt
>>> 4+5
9
>>> myInt(5)+myInt(3)
Traceback (most recent call last):
File "<pyshell#80>", line 1, in <module>
myInt(5)+myInt(3)
File "<pyshell#77>", line 3, in __add__
return self+other+1
File "<pyshell#77>", line 3, in __add__
return self+other+1
File "<pyshell#77>", line 3, in __add__
return self+other+1
[Previous line repeated 990 more times]
RecursionError: maximum recursion depth exceeded
because every integer points to the integer class in memory, they do not point to the int variable
unless you overwrite the int class in memory, they will remain unchanged
this didnt work and didnt make a error
you probably want to take a look at the forbiddenfruit module
well you changed int into myInt
so you're doing myInt.__add__ = myInt.__add__
no error
and you can't change actual builtin types like that anyway
forbiddenfruit lets you overwrite built-in functions and methods without too much hassle
ah darn
overwriting int.__add__ in memory is certainly possible with just ctypes though. i'll give it a go in a few minutes.
why cant i install forbinnenfruit module?
probably because you don't have Microsoft Visual C++ 14.0
oh i did something
python crashed by adding
@sick hound you just changed the base class of 1 to your __add__ function
of course its gonna crash
ye i noticed
yea
i assume you used the code to change adding on one that i put up earlier?
ye
from ctypes import *
class myInt(int):
def __add__(self, other):
return "meh, i dont really feel like doing calculation right now..."
for i in range(-5, 255):
py_object.from_address(id(i)+sizeof(c_size_t)).value = myInt
without the super
makes sense
now what if i want to also make the number 256 do this?
what is ()
an empty tuple
its cached
and used in the C code of python
Python 3.7.3 (default, Mar 27 2019, 22:11:17)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from ctypes import *
>>> py_object.from_address(id(())+sizeof(c_size_t)).value = None
>>>
SystemError: /tmp/build/80754af9/python_1553721932202/work/Objects/tupleobject.c:141: bad argument to internal function
>>> 1 + 1
SystemError: /tmp/build/80754af9/python_1553721932202/work/Objects/tupleobject.c:141: bad argument to internal function
>>> exit()
SystemError: /tmp/build/80754af9/python_1553721932202/work/Objects/tupleobject.c:141: bad argument to internal function
>>> ```
!e ```py
import ctypes
int.add is defined as a binaryfunc type in C
binaryfunc = ctypes.CFUNCTYPE(
ctypes.py_object, ctypes.py_object, ctypes.py_object
)
this is the pointer to the int's number methods
int_num_ptr = ctypes.c_void_p.from_address(id(int) + 96)
we don't need to add anything to the int's number methods
address because int.add is the first in the struct
int_add_ptr = ctypes.c_void_p.from_address(int_num_ptr.value)
convert the original int.add into a callable function.
this is to prevent recursion errors in the new function
int_add_func = ctypes.cast(int_add_ptr, binaryfunc)
@binaryfunc
def new_int_add(self, other):
return int_add_func(int_add_func(self, other), 1)
convert our new function into a pointer and overwrite the
original int.add pointer with the new one
new_add_ptr = ctypes.cast(new_int_add, ctypes.c_void_p)
int_add_ptr.value = new_add_ptr.value
print(5 + 6)
print(500 + 500)
print(0 + 0)
@brisk zenith Your eval job has completed.
001 | 11
002 | 1000
003 | 0
huh it didn't work here. must be because the bot is on 3.6 or something
@sick hound @sick hound that code there works for python 3.7 and 3.8 though
@rugged sparrow just counted how many bytes ahead to *tp_as_number it would be here: https://github.com/python/cpython/blob/master/Include/cpython/object.h#L177
@sick hound maybe. i'll see if i can sort the code out and make it work more
👌 thanks
ye im on 3.7.3
oh hmm
okay, so it works if you run it in the shell
but not in the code
i wonder why that may be
thats weird
oh wait
because the values in the code are optimised
in the bytecode
right, makes sense
can u fix it?
sort of. the code is still working, but python's bytecode optimiser can't be prevented like that
hold on, in the code it causes a segfault now
okay yeah i'm not sure how to sort it out for running in the code itself
but it works flawlessly in the shell haha
why would it be different there?
is it because there is some time between the commands/
?
nope its not
i'm not sure why it segfaults in the code.
i do have something that works in code though:
test = ["this", "is", "a", "list"]
print(test[1]) # outputs 'this'
test = "lists start at one".split()
print(test[1:3]) # ['lists', 'start']
works for slices too
!e ```py
import ctypes
binaryfunc = ctypes.CFUNCTYPE(ctypes.py_object, ctypes.py_object, ctypes.py_object)
mapping = ctypes.c_void_p.from_address(id(list) + 112)
original_ptr = ctypes.c_void_p.from_address(mapping.value + 8)
original_method = ctypes.cast(original_ptr, binaryfunc)
@binaryfunc
def new_method(self, item):
if isinstance(item, int):
item = item - 1
elif isinstance(item, slice):
item = slice(
item.start - 1,
item.stop - 1,
item.step
)
return original_method(self, item)
new_method_ptr = ctypes.cast(new_method, ctypes.c_void_p)
original_ptr.value = new_method_ptr.value
test = "lists start at one".split()
print(test[1])
print(test[2:4])
@brisk zenith Your eval job has completed.
001 | lists
002 | ['start', 'at']
this one works consistently haha
change all the - 1s in the function to - whatever
how does it work? globals?
i thought it wouldn't
why??
lemme take a look
import ctypes
binaryfunc = ctypes.CFUNCTYPE(ctypes.py_object, ctypes.py_object, ctypes.py_object)
mapping = ctypes.c_void_p.from_address(id(list) + 112)
original_ptr = ctypes.c_void_p.from_address(mapping.value + 8)
original_method = ctypes.cast(original_ptr, binaryfunc)
def change_list_start(index):
@binaryfunc
def new_method(self, item):
if isinstance(item, int):
item = item - 1
elif isinstance(item, slice):
item = slice(
item.start - 1,
item.stop - 1,
item.step
)
return original_method(self, item)
new_method_ptr = ctypes.cast(new_method, ctypes.c_void_p)
original_ptr.value = new_method_ptr.value
this works for me
wait hold on
i forgot to change the index inside
give me a moment
okay so if you replace those, it works
got it
you have to change it back to 0 before python closes if you want to avoid segfaults btw
ah
euhm
it says my function isnt defined
import ctypes
binaryfunc = ctypes.CFUNCTYPE(ctypes.py_object, ctypes.py_object, ctypes.py_object)
mapping = ctypes.c_void_p.from_address(id(list) + 112)
original_ptr = ctypes.c_void_p.from_address(mapping.value + 8)
original_method = ctypes.cast(original_ptr, binaryfunc)
def arraysStartAt(index):
@binaryfunc
def new_method(self, item):
if isinstance(item, int):
item = item - index
elif isinstance(item, slice):
item = slice(item.start - index,item.stop - index,item.step)
return original_method(self, item)
new_method_ptr = ctypes.cast(new_method, ctypes.c_void_p)
original_ptr.value = new_method_ptr.value
is that all of your code?
you have to do module.arraysStartAt(...).. that's how modules work
possibly.
it's been attempted a bunch of times before, i can't remember if any were successful.
(they probably were)
i'm not gonna try it right now though, i'm busy at the moment
sure
ima try to rewrite the round function so the numbers are just not rounded
so 50.4 --> 50.00000000000000000000000000001
hah
this one is just a simple redefinition of the round function
lol i found this
@snow beacon yes we now can
from ctypes import *
binaryfunc = ctypes.CFUNCTYPE(ctypes.py_object, ctypes.py_object, ctypes.py_object)
mapping = ctypes.c_void_p.from_address(id(list) + 112)
original_ptr = ctypes.c_void_p.from_address(mapping.value + 8)
original_method = ctypes.cast(original_ptr, binaryfunc)
def arraysStartAt(index):
@binaryfunc
def new_method(self, item):
if isinstance(item, int):
item = item - index
elif isinstance(item, slice):
item = slice(item.start - index,item.stop - index,item.step)
return original_method(self, item)
new_method_ptr = ctypes.cast(new_method, ctypes.c_void_p)
original_ptr.value = new_method_ptr.value
use the arraysStartAt function
and make sure to import ctypes
(cough i wrote most of that tyvm lmao)
@sick hound yea you can but that requires defining an encoding because you are going to change the parser
Lol
Hi I need to convert a string like this
{'x': 300} + {'x': 0} & {'y': 300} & {'y': 0}
into this (one) object
A (x = 300) + A (x= 0) & A (y= 300) & A (y= 0)
another example
string:
({'x': 300} + {'x': 0} & {'y': 300}) + {'y': 0}
object:
SomeObject == (A (x = 300) + A (x = 0) & A (y = 300)) + A (y = 0)```
And I need to get (return) this new object
How to do this?
I know these dict keys are always strings;
and values are numbers or strings
Is it reasonable to implement this with ast.parse or something like that?
I just started to delve into ast, but it looks like I need a plan of key actions (if using ast is
suitable in this case).
@sick hound so basically every dict becomes: A(key=value)
@polar plover
yes (if I understand you correctly). but there can be several such pairs in the dictionary {'x': 300, 'y': 0} etc
@brisk zenith oh
I thought questions on ast is better to ask here, am I wrong
well, ast is a perfectly normal module to use in python, nothing funky about it really.
@polar plover yes
@sick hound #help-kiwi looks free, we can move there if you want.
Sorry, but you may only use this command within #bot-commands.
@grave rover that just occurred to me, idk if you've done it before but I wonder if you can modify object so class Abc: which inherits from it, will have new stuff in it? WHen I tried to modify it directly I got a TypeError: can't set attributes of built-in/extension type 'object'
@crystal mica what are you trying to edit?
object
you know howpy class Abc: pass then Abc is automatically inherited from object class?
yea
it's equivalent to py class Abc(object): pass
I want to, say, do this before I define Abc
object.yes = lambda: print("Yes")```
so I can dopy abc = Abc() abc.yes()
one sec
i wanna try something that might work
so i managed to add object.yes
but it isnt inheriting
ah
cause everything actually inherits from type
not object
oh i modded it in memory

Python 3.7.3 (default, Mar 27 2019, 22:11:17)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class myType:pass
...
>>> myType.yes = lambda *s:print('yes')
>>> myType.__call__ = type.__call__
>>> from ctypes import *
>>> py_object.from_address(id(type)+sizeof(c_size_t)).value = myType
>>> class foo:pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor '__call__' for 'type' objects doesn't apply to 'myType' object
>>> ``` and replacing type doesnt work right
it didnt work for me either
this is so weird
I have to actually call class Abc(type): for it to work
what the hell is creating it
Hmm, i have an idea
wait whats working now?
import builtins
class MyType:
pass
MyType.yes = lambda *s: print('Yes')
builtins.type = MyType
class Abc(type):
pass
abc = Abc()
abc.yes()
But this is the same as just extending
ah i know why that broke it
import builtins
class MyType(type):
pass
MyType.yes = lambda *s: print('Yes')
builtins.type = MyType
class Abc:
pass
abc = Abc()
abc.yes()```
this might work
Traceback (most recent call last):
File "e:\Projects\hi3-beta-bot\snippets.py", line 17, in <module>
abc.yes()
AttributeError: 'Abc' object has no attribute 'yes'```
I tried that before I had to put type into Abc
Weird i know
ah ik why
cause your just redefining the visible type var. while class declarations are getting it from mem
@crystal mica have you tried our Lord and Savior gyukutai forbiddenfruit?
o
More like see if I can do without it
I think due to implementation, the original type got loaded into memory
Oh also here's a fun thing to try:
Dereference None
so subclassing it wont take effect unless I specify it to inherit from type again, after subclassed
without specifying inheritance, it'll just inherit from the original that's in the memory
which explains
But then how did forbiddenfruit do it lol
modifying the memory directly?
yes

That's how forbiddenfruit practically works, yeah
i've got until my friend replies to a message to piss about with this idea
so, let's see then
!e ```py
import ctypes
obj_dict = ctypes.py_object.from_address(id(object.dict) + 16).value
obj_dict["hello"] = 123
class Test:
pass
x = Test()
print(x.hello)
@brisk zenith Your eval job has completed.
123
@crystal mica @grave rover
just modify the mappingproxy's internal dict, easy
anyways gotta go bye
practicality beats purity
Thank you @brisk zenith it made me curious for the past 2 hours lol
👌
I didnt think of modifying only the __dict__
PyObject_HEAD is 2 pointers
so 16 bytes on 64 bit
so just skip those 16 bytes to reach the actual dict itself
(because mappingproxy itself doesn't allow for assignment)
anyways yes bye
"cause everything actually inherits from type
not object" that's... false
>>> ''.__call__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__call__'
>>> type.__call__
<slot wrapper '__call__' of 'type' objects>
>>> isinstance('', type)
False
>>> isinstance('', object)
True```
@sick hound yah that was cause of a typo by me ```py
''.class
<class 'str'>
''.class.class
<class 'type'>
''.class.base
<class 'object'>
I only checked __class__ not __base__
not everything inherits from type, but type will always be in the type hierarchy
Because type is the type of object
and well, really every class
class Foo:
...
```is really just cool syntax for
```py
Foo = type(
'Foo',
(object,),
{...}
)```
Haha, I see ctypes is really what's used a lot here
it's easier to abuse a language when you don't conform to spec and abuse the implementation
Yep 👍
@define_method(str)
def to_spongebob(self):
methods = [str.lower, str.upper]
new_string = ""
for index, char in enumerate(self):
new_string += methods[index % 2](char)
return new_string
print("arrays start at one".to_spongebob())
# outputs "aRrAyS StArT At oNe"
i extended the object attr overwriting to make it nicer :D
doesn't work for magic methods because i cba with those yet. but maybe soon lmao
at least, not for builtin types
probably because they are read only.
that's not the problem
it's that the magic methods of the builtin types aren't stored in __dict__ like regular attributes and methods
instead, they're defined in special C structs
and while it is very possible to overwrite that behaviour (i did it yesterday)
it can be quite tedious
oh, ignore me then
haha it's no problem.
but usually if something in python is "read-only", it is simply "read-only until import ctypes" 😉
bf interpreter in 188 chars 😃 any way i can improve it? py t=d=0;p,m="",[0]*1000 for i in input():j="]+[-><.,".find(i);p+=" "*t+"0 m[d]+=1 while+m[d]: m[d]-=1 d+=1 d-=1 print(end=chr(m[d])) m[d]=ord(input())".split()[j]+"\n";t-=(j<3)*(1-j) exec(p)
