#internals-and-peps
1 messages Ā· Page 150 of 1
Ok
find a list of the top packages of pypi and look at their sources, anything in the first 10k or so should be good
eh, not really to be honest
some libraries are just terribly written
so you get into the recursive task of figuring what to like and what not to
And most will have their weird quirks that aren't really something you should be doing
yeah, for example pydantic has some cursed metaprogramming code with metaclasses
From what I've seen recently, starlette has pretty good code.
speaking of starlette, i only recently learned that aiohttp has a webserver too
yeah
if you're not using ASGI, you have to implement an entire HTTP server from scratch š
Any tutorial on how to develop a co-training machine learning algorithm
I was looking into namespace packages and what to publish it with and flit only super recently got support for it lmao
expression[expr_ty] (memo):
| invalid_expression
| invalid_legacy_expression
| a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }
| 'try' a=expression 'except' e=expression 'with' b=expression { _PyAST_Try(a, _PyAST_ExceptHandler(e, NULL, b, NULL), NULL, NULL) }
| disjunction
| lambdef
I'm hoping that my addition (the line starting with 'try') will have the effect of adding inline exception handling.
No, it had the effect of ruining the build.
I figured it had something to do with EXTRA but I'm trying to figure out what that's even for
I see. That explains why _PyAST_* functions had more arguments than it was getting.
why?
@unkempt rock it would appear that expression is the wrong type for the AST functions.
right
that just ruins my day
Guido has stated a few times that he doesn't want inline exception handling, so I'm under no delusion that this is a pointful endeavor.
please do this survey
i've deleted the survey, it's not in english and it's not relevant, and even if it were it wouldn't be allowed. please see #rules for more details. thank you!
what in the holy hell is this fuckery
APPARENTLY, modules can have their classes reassigned
this means, that call methods can be implemented for modules
!e ```py
import sys
try:
sys()
except Exception as e:
print(e)
import types
class CallableModule(types.ModuleType):
@staticmethod
def call():
print("you've called the sys module!")
sys.class = CallableModule
sys()
can't say this isn't cursed, but its apparently a thing and somewhere I presume there's an official way to do this, likely with import hooks or something with importlib.
@white nexus :white_check_mark: Your eval job has completed with return code 0.
001 | 'module' object is not callable
002 | you've called the sys module!
wait until you learn that you can swap out the code that a function executes by changing _co__.something I can't remember off the top of my head
both of those abuses are terribly useful when you want to hot reload code
I wrote a decorator for myself that would watch over the file it was in for changes and reload the class/function when it detected any
Existing instances of the classes would be converted to the "new" class so things would mostly work as expected
i'm half tempted to write a dpy cog extension thing which would reload the extension corresponding to the file that was edited
although wouldn't need to use that ig since it implements its own code loading
f.__code__.replace(co_code=...)
thank you
so when i was deling modules, modifying the file, and reimporting it, i could've just done the hot reloading with __code__.replace?
!d importlib.reload
importlib.reload(module)```
Reload a previously imported *module*. The argument must be a module object, so it must have been successfully imported before. This is useful if you have edited the module source file using an external editor and want to try out the new version without leaving the Python interpreter. The return value is the module object (which can be different if re-importing causes a different object to be placed in [`sys.modules`](https://docs.python.org/3/library/sys.html#sys.modules "sys.modules")).
When [`reload()`](https://docs.python.org/3/library/importlib.html#importlib.reload "importlib.reload") is executed:
maybe?
huh neat - didn't know about that at the time (was very new to python)
The slightly less "evil" method is to simply replace the module in sys.modules, since the import procedure explicitly looks it up again from there to allow this sort of thing. But the __class__ assignment is very much supported - you're only normally allowed to set the class on Python-defined classes, ModuleType has a special-case exception to allow this since it's rather useful.
Before __getattr__() was available as a function hook, this used to be done often for things like lazy-loading or depreciations.
Thereās something very satisfying about writing @__import__(ā¦)
I love this kind of trickery so much
believe it or not, there's a module that does that
!pip modcall this is how I found that out
if getattr(obj, "__module__", None) is None and getattr(thing, "__module__", None) is None:
i want none-aware operators :(((
that looks like a job for hasattr
not if __module__ actually is defined as None š
for one of the two
it's the dark alley of python code
where nobody looks and if crimes happen, they go annoticed
so sentinels?
hu?
how would sentinels solve this problem? if anything, they would make it more complicated than necessary..
heh
side note I want that sentinels pep
me too, but i don't think it would do away with none-aware operators, specifically in this case
i'm applying decorators to everything programmatically, so i'm trying to avoid infinite recursion and other problems involving decorating imported things by checking the __module__ boundary between the parent and child objects
sometimes things don't have a __module__ attribute and sometimes it's set to None, possibly resulting in scenarios where we can't tell if imported or not
yeah if it's stuff in a module generally importlib reload does the trick
there's edge cases where you want to recursively reload a module dependency tree from the bottom up which can be irritating
at that point the hot reloading becomes useful
what hot reloading?
recursively reloading things doesn't sound very wise
this
ah
and changing existing classes' _class_
not sure if that's wise either
definitely not wise and I wouldn't do it in production
it's for faster development when you don't want to close and reopen the application for whatever reason
but you still want to iterate on the code
as a trivial example say your python code has a long startup time because it has to read a lot of state from disk
you could close and reopen it but it would waste a bunch of time for nothing
in justuse we restrict the reloading to function-only modules, that works well
module-wise
i think restricting hot reloading to pure functions is the only reasonable thing, anything with state is cursed
yeah agreed
it only worked for me because I wouldn't do anything that would break the reloading system
also, i wouldn't use importlib.reload, its implementation is naive to say the least
a long time ago i experimented with reload() when it was still builtin, it was hard to get things in order
recently i looked at its implementation as inspiration for justuse and i was baffled to see code like this in the stdlib
no love went into this
class type(object)``````py
class type(name, bases, dict, **kwds)```
With one argument, return the type of an *object*. The return value is a type object and generally the same object as returned by [`object.__class__`](https://docs.python.org/3/library/stdtypes.html#instance.__class__ "instance.__class__").
The [`isinstance()`](https://docs.python.org/3/library/functions.html#isinstance "isinstance") built-in function is recommended for testing the type of an object, because it takes subclasses into account.
this is very overloaded
very overloaded? there are only two ways of calling it
Same as list, less than dict or range or int...
well, it gets the type of an object (implemented in c), its the type of all classes, and it can be subclassed to make a metaclass, which feels like a lot over what other objects do
object has about as many meanings. It can be called to create a new object, it is the type of all objects, and it can be subclassed to make new types.
The second and third are directly related
For the first, ig i wouldnt mind having a separate typeof function
its the type of all classes, and it can be subclassed to make a metaclass
I mean, those two properties are linked
Yeah
typeof could have made sense, but I'm personally fine with the overloading here
What I want to do is getting the prices of some characters. I tried it with BautifulSoup & also with Selenium. However both dont work. BautifulSoup doesnt work because the website is using react and js. Selenium doesnt work because when I try to launch the website with a chrome webdriver I need to add my metamask wallet (everytime I launch the programm). Is there any way to get the information out of the website?
er
did these get removed?
Note
Support for generator-based coroutines is deprecated and is scheduled for removal in Python 3.10.
well only one way to know
!e ```py
import asyncio
@asyncio.coroutine
def old_style_coroutine():
yield from asyncio.sleep(1)
@white nexus :white_check_mark: Your eval job has completed with return code 0.
<string>:3: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
is there a way to detect if the implementation uses a GIL? or is there an operation that is made thread safe with a GIL that i can check against a locked implementation of that operation instead?
an interesting question. What would you do with it? (I think the answer is "no")
I have an atomics thing that can use transactions, but the transactions suck under contention - if thereās a GIL I can use them because thereās guaranteed to be no contention
(Well at least for threading, doesnāt hold for processing)
I don't think the GIL will prevent contention in your objects, will it?
In Python <=3.9, just incrementing an int from multiple threads will lose updates
@red solar ^^
The atomic stuff is in C, so I keep the GIL there (my bad should have mentioned that)
This got changed in 3.10?
maybe in 3.11? a slight change in the bytecode made the multi-thread int example work without locks
Python 3.10 runs this code without non-deterministic race condition results: https://t.co/wUyIh3sSbU
But why? Itās not guaranteed, but what changed to make it work?
huh, ok that's pretty cool
seems like I have encountered errors callimg type() with certain objects before
that have non-type metaclasses, iirc.. is that possible? could user code run when type is called
I don't think that's possible.. IIRC type just returns the type stored in the PyObject struct.
according to the C code, it just does this:
return Py_NewRef(((PyObject*) args[0])->ob_type);
exactly that. I guess the question would be, if something can subclass type and override its __call__ ?
*the above code also has a condition that metatype == (PyObject *)&PyType_Type)
one way that comes to mind is: measure the real time elapsed when running a function doing some non-gil-releasing things in 1 thread. then repeat this with 2 threads simultaneously. if the real time elapsed in the second run is ~twice the first one then there's probably a gil.
Huh, didnāt think of that š thanks
Can someone help me in doing the Josephus Problem?
another way could be to measure the ratio between cpu time and real time, which is a way to measure the parallelization of a process in general. if you have n cpu threads, and cpu time elapsed is ~n times higher than real time that means the workload of the process is effectively spread across all cpu threads
ok, I'm ptetty convimced about this, but is there any difference between that and this?
object.__getattribute__(obj, "__class__")
so is there anything equivalent to what type(arg) does (in C), in pure python?
__builtins__.__import__('sys')._getframe(0).f_globals.__setitem__(
'__custom__',
object.__class__.__class__('x', (), {
'__init__': __builtins__.__import__('sys')._getframe(0).f_globals.__setitem__(
"lines",
(x.strip() for x in __builtins__.__import__('sys').stdin)
),
'__call__': __builtins__.__import__('sys').stdout.write(str(i for i in lines))
})
)
__custom__.__init__
__custom__.__call__
<generator object <genexpr> at 0x000001CB2A751E00>
I'm trying to recreate lambda but for some reason when I try to call __init__ and __call__ it throws an error saying an int object is not callable. How would I go on about this? I need to let __init__ accept arguments, tried to do that using sys.stdin
Ping me on reply
@unkempt rock #esoteric-python
Oh sry
@grave joltQuick question, I still dont understand what esoteric means? Does it mean messy code?
In this context, it means using Python in very non-traditional ways, for the purposes of art or entertainment
Ah alright I see, thanks
It means without C
Ctypes probably also counts as C-code
Only that one, because the rest don't help in what greyblue92 is trying to accomplish
Yes
!e There is:
@lambda x:x()
class x:
__class__ = 23
print(type(x))
print(object.__getattribute__(x, "__class__"))
@quick snow :white_check_mark: Your eval job has completed with return code 0.
001 | <class '__main__.x'>
002 | 23
And I believe no, not without using either type or ctypes somehow.
how would you do it with ctypes
I tried with object.__getattribute__ and it absolutely called a property I had defined named __class__, but youra doesn't
What's wrong with using type, exactly?
I don't think it can invoke any user-defined code under normal circumstances, and you can cache builtins.type somewhere if you want to be absolutely sure no one replaced it
I guess there's some magic that could replace modify type.__code__type in place, but at that point, if they want to alter it so desperately, just let them
lol I just saw the number of builtin dunders
Hi, I am doing a node graph where I procedurally generate nodes based on a user defined execute method's .__annotations__ dictionary. This works wonderfully with inputs, only one slight problem, I can't figure out a way of supporting multiple return types? Currently a return type is specified the default python with the -> type syntax, this works quite well for nodes that only require a single output, but when I want to return something more complex, it becomes a little annoying. My system currently names the function inputs based on the __annotations__ variable names, I would like this to persist and work similarly on the return type system.
Are there some type, that supports typeing, that lets the user define keys and types exactly as when specifying function parameters?
Example of current syntax:
class StringConstantNode(KSNodeItem):
_title: str = "Sting Constant"
def execute(self) -> str:
return "String1234"
class PrintString(KSNodeItem):
_title: str = "Print String"
def execute(self, string: str, boolean: bool) -> None:
print(string)
This would be the ideal syntax:
def execute(self, string: str, boolean: bool) -> (outputString: str, outputInt: int):
...
Or more realistically:
def execute(self, string: str, boolean: bool) -> MyDynamicNodeReturnType(outputString: str, outputInt: int):
...
This could possibly be done with typing.TypeVar and a Tuple type class, but I am not sure how to go about it...
@tame imp You should ask in #type-hinting
Ah, sorry, didn't notice that channel.
What discussion has there been around "type hinting" for exceptions?
def some_func(a: int) -> int, Raises[KeyError]:
...
Like that?
I think I'd prefer a decorator
a decorator for metadata about what a function might do offends my functional programming sensibilities.
While Raises does make it clear what it means, in general, I'd assume that a tuple of return types represents the actual return value tuple
that's what the tuple[...] annotation is for.
there was some talk about it here: #type-hinting message
it is kinda weird to put it in a comma after the return type. what happens if you just want to have a Raises but no return type?
I'm aware of that, yeah, but intuitively I'd expect that to specify the return tuple
but I agree with numerlor here:
hinting exceptions is a bit weird as there are some that can be raised anywhere as normal behaviour and then there's also an API that'd allow you to do that for any exception
Either None, Raises or special case Raises I guess?
!e
import typing
typing.NoReturn[None]
print('worked')
@boreal umbra :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 2, in <module>
003 | File "/usr/local/lib/python3.10/typing.py", line 309, in inner
004 | return func(*args, **kwds)
005 | File "/usr/local/lib/python3.10/typing.py", line 400, in __getitem__
006 | return self._getitem(self, parameters)
007 | File "/usr/local/lib/python3.10/typing.py", line 436, in NoReturn
008 | raise TypeError(f"{self} is not subscriptable")
009 | TypeError: typing.NoReturn is not subscriptable
Well then
I don't know if type-hinting exceptions would make all that much sense, since it would be really hard to account for every possible exception that a function could raise and hinting all of those just wouldn't be viable. Just hinting that it could raise any arbitrary exception is also just ridiculous as that would be the case with every fucntion, while there may be some exceptions that are "expected" to be raised, that doesn't man other exceptions will absolutely never occur and so type-hinting them is just odd imo
even just something like KeyboardInterrupt could be raised in any arbitrary function at any point and I don't suppose it would make sense to type-hint that
I don't think anyone's suggesting that we should annotate for KeyboardInterrupt
it could be like java's checked exceptions
Doesn't NoReturn mean it never returns?
As in always raises
You'd use None for void functions
NoReturn could also mean that the function has a while True loop, or something.
I was only checking to see if NoReturn is subscriptable.
Yeah, that too
yeah, obviously, but the point is that if a function contains even just print(x) where x is taken from parameters, you would have to expect TypeError too
or a sys.exit
etc.
I'm not sure what I'd expect subscripted NoReturn to mean
the point is that it wouldn't be managable, so I'd assume you'd only want to type-hint the "expected exceptions", but then again, that's kind of weird imo
do linters pick up on things like :raises E: in docstrings
I'd prefer Union[int, Raises[Exc]] if anything. Doing int, Raises[Exc] is quite odd
If you go to the effort of including all the exception types in the type hint, maybe use error values?
like Rust or Haskell already do
or go
we don't talk about that here
no, considering there's no actual raises type-hint anyway. Type-Hinting currently doesn't handle exceptions at all
yeah but docstrings are independent of typehints
if you find docstrings with :something: syntax, you should encourage the author to use more modern syntax
hmm, i thought its used for documentation generating tools like sphinx
i think sphinx uses that, yeah. google's syntax is way cooler though
what's the more modern format?
google or numpy style, which sphinx now supports natively
what does that mean, only works for PyCharm?
Blue probably meant that other IDEs donāt parse the docstrings in the same way
and casual decorator styles will often mangle the real metadata in the process (even though the whole point is basically to enrich the metadata)
I much prefer the long version of the docstring (Google). Lumping the special docstring keywords and names and descriptions together just looks like a mess, that wasn't really written to be human-friendly-first.
This kind is also nice for functions that are mostly self explanatory, that the stdlib also uses in placea:
"""
wait4(pid, options) -> (pid, status, rusage)
Wait for completion of a given child process.
"""
the stdlib sometimes embeds the signature into the docstring because there's no way to set __annotations__ on a function implemented in C.
When I hover over that docstring in Visual Studio Code there is absolutely no special rendering or effect in my editor. It is also a much less readable than Google style or, hell, Sphinx's RST.
ah, that makes sense
it's nice to have the names of the return tuple elements too
yes, #changelog
Is there a reason why you can't subclass function? I understand not being able to subclass bool and NoneType, but why not function?
for its descriptor protocol,
though i'm moreso curious about why you can't subclass function
make methods easily maybe?
^
it would also be nice to be able to access the function that populates a class scope
the descriptor protocol is the __get__, __set__, and __delete__ dunders iirc
oh and __set_name__
wdym?
It's how property works. It allows you to run code when an attribute is get and set primarily
like where FunctionType stems from?
The code inside the function
either a call to compile, or the .co_code attribute of an existing function, or something.
Yep, the bytecode instrs are found in
function.__code__.co_code iirc
(in bytes I think)
sounds like I did mean .__code__ then - since we want the code object, not the bytes of the bytecode
also quick question:
#bot-commands message
anyone know why __closure__ is None here? I feel like I made a really silly mistake but I can't figure out what it is
@surreal sun __closure__ only captures the variables that the function actually uses
ahh no wonder
silly mistake lol
so, function implements a descriptor protocol that when you do something like
instance.function, it'll call function.__get__(args go here cause I forgot what the args here), and then it's like "oh it's a bound method! let me add self" and then self is bounded to the method for when it's called (assuming it's an instance method_
!e
def f():
x, y, z = 1, 2, 3
def g():
x, y
return g
print(f().__closure__)
@grave jolt :white_check_mark: Your eval job has completed with return code 0.
(<cell at 0x7f1bc022d690: int object at 0x7f1bc02ec0f0>, <cell at 0x7f1bc022d660: int object at 0x7f1bc02ec110>)
__get__ and __set__ mostly
the issue with this (which I have run into) is where to get the values of the other parameters to FunctionType
| function(code, globals, name=None, argdefs=None, closure=None) ... | code | a code object | globals | the globals dictionary | name | a string that overrides the name from the code object | argdefs | a tuple that specifies the default argument values | closure | a tuple that supplies the bindings for free variables
that works for very simple functions
huh is the channel purpose still the same?
Yep, just a rename
there was some concern that the old name was misleading, and so we're trialing this name to see if it helps or hurts the number of on-topic conversations that happen here
is it possible to dissasemble the code in a module object?
like if i have a file that just contains print(1), how could i disassemble that code
Like with the ast module?
by the time the module has been imported, the code has already been executed and thrown away. That is: the creation of a module object involves executing some code inside a new namespace. Once that code has been executed, it's never needed again, and there's no way to retrieve the original code by just knowing the contents of the namespace
so instead of importing the module, you'd need to open the file, read it, compile the code that you read, and then disassemble that compiled code.
try this: import colorsys, dis; dis.dis(colorsys)
(colorsys is just a pure-python module)
in the case of a module that just contains print(1), though, that won't work.
or, won't help, rather.
true
!e Why is the last line false here
py class A: pass a = A() print(type(a) is A) print(type(a).__dict__ is A.__dict__)
@unkempt rock :white_check_mark: Your eval job has completed with return code 0.
001 | True
002 | False
!e ```py
class A: pass
print(A.dict is A.dict)
@raven ridge :white_check_mark: Your eval job has completed with return code 0.
False
wtf
madness
must be that __dict__ is returning a new dict, instead of a reference to an existing one.
well maybe not if it's a property or something
it is proxy
i found this answer https://stackoverflow.com/questions/32720492/why-is-a-class-dict-a-mappingproxy, which sounds reasonable I guess
the proxy doesn't allow setting
which allows enforcement for all keys to be strings for the class __dict__
which allows for optimization, since looking up the class attributes is a common usecase (looking up methods for example)
interesting, but that does only dissasemble the methods
so i'd have to open the file for readnig
is it possible to get the path of a module for reading?
__file__, though that might find a .pyc instead
wait, nevermind 
all of those is checks will be False, because it always returns a distinct instance.
does pyc contain the "root" code too, or only methods?
what is all this for?
decompiling code of a module
yes, but why?
i may or may not use that in several places to get the file
curiosity i guess
if it's just for curiosity, then you don't need a way to find the code for a module - just open any .py file on your computer.
@unkempt rock :white_check_mark: Your eval job has completed with return code 0.
True
aha
@unkempt rock :white_check_mark: Your eval job has completed with return code 0.
001 | True
002 | True
is it possible to write / update the slots of a class after it's been defined ? (using python code)
Making another subclass that does only this is completely out of the question?
Because that's quite frankly what you're supposed to do afaik.
__file__ is routinely None, in my experience
and/or it's set to something useless like <module> or <frozen blah blah>
Since more and more of the stdlib is getting frozen , it's also my preference that frozen modules should still come with the .py source somewhere, and provide that in __file__ / __spec__.origin, so that tracebacks can be shown with source, imo, even if they're frozen. I have my python modified so it gives a teal path instead of <_frozen_bootstrap> etc., and it is helpful when things go wrong, especially during imports. I think there was some movement towards this but I don't know the current trajectiry
looking at pythons I have installed, none of them have a file called _bootstrap_external.py :(
more of the stdlib is getting frozen?
what does that mean?
it's where the contents of the module are stored in binary form ,so it's quicker to import saving parse time during startup)
baked into the python binaries
quote from Guido:
Builtin modules (such as sys or time) don't have a
__file__attribute either, and nobody has ever complained about this (that I know of). I wonder how far our backwards compatibility guarantee should go -- would this mean we cannot turn any stdlib module written in Python into one written in C (or Rust :-)?
side note: I thought the magic constants like <_frozen_bootstrap> could be changed in linecache or traceback, back to real paths, to make source available but I ended up having to make modifications to C code in importlib
I wonder how you even understand the import machinery of Python
It's so confusing lol
ah fair
did you just read source code to understand it?
Or PEPs, etc
both, but mostly the importlib documentation and PEPs are enough (along with git commit history, there's a surprising amount of detail there)
For example
git log Python/import.c
this is pretty helpful info
oh wow
they have nice git commit messages
mine are usually something along the lines of "changes to [x files] because i forgot what exactly i changed"
yeah, haha, same - "hopefully fix X"
and then just to realize that you never fixed X and just created more errors 
c'est la vie..
you should see the first commit for git
or as I've taken to calling it, the information manager from hell
Git Source Code Mirror - This is a publish-only repository but pull requests can be turned into patches to the mailing list via GitGitGadget (https://gitgitgadget.github.io/). Please follow Documen...
This is a descriptor that emulates what @staticmethod does, but how can it be used as a decorator when there is no __call__ to return a function to put in foo's place? 
!e ```py
class StaticMethod:
def init(self, func):
self.func = func
def __get__(self, instance, owner):
return self.func
class A:
@StaticMethod
def foo():
print('foo!')
A.foo()```
@unkempt rock :white_check_mark: Your eval job has completed with return code 0.
foo!
The __get__ is doing something fancy
I still don't fully understand descriptors
Wdym on tha tlast part?
It doesnt put the function back in its place, A.foo is the StaticMethod object itself
accessing that object using attributes from both the class and the instance hence calls dunder get
!e
If this makes it easier to understand:
say we have a class that implements __get__, just as a starter:
class Foo:
def __get__(self, instance, owner):
print(f"Called from the {owner} class with an instance of {instance}")
return 1
# Let's make an instance of Foo in a class
class Test:
foo = Foo()
print(Test.foo + 1)
@surreal sun :white_check_mark: Your eval job has completed with return code 0.
001 | Called from the <class '__main__.Test'> class with an instance of None
002 | 2
we need @classproperty already.
So sick of not being able to give docstrings to class attributes
exactlyyy
also let me know if you want me to explain __set__ too
Right, so it works as a decorator normally does like foo = StaticMethod(foodefinition) making foo the descriptor, and when gotten returns the original func
yep!
I see 
infact, that's how instance methods work in python
the function class implements a descriptor protocol
it'll see if it was got from an instance, and if it isn't a class/staticmethod, it'll bake in the instance into the self parameter iirc
well it deosn't have to be self but it conventionally is self
Its positionally passed in as the first argument, yep
(technically the function class doesnt watch out for class/static methods, those types handle the attribute access themselves)
ahh yea
!e
one thing that shows this is how self isn't baked in when I call it from the class itself, so I could literally do anything with it lol
class Foo:
def instance_method(self):
print(type(self)) # this should be <class __main__.Foo>.. right?
foo = Foo()
foo.instance_method() # phew, it is what I expected it to be
Foo.instance_method(2) # wait what?
@surreal sun :white_check_mark: Your eval job has completed with return code 0.
001 | <class '__main__.Foo'>
002 | <class 'int'>
What are some real use cases of descriptors? (considering @property/staticmethod/classmethod/etc are already built in)
methods
!e
providing an 'interface' to the user so they see something else if that makes sense? like for example, if I wanted to have an attribute that's dynamic in the sense that it points to a class like the following:
class MyNum:
def __get__(self, instance, owner):
return 1
class Test:
my_num = MyNum()
print(Test.my_num)
Test.my_num is a class but it looks like an integer to the user
@surreal sun :white_check_mark: Your eval job has completed with return code 0.
1
a @classproperty basically?
well you could do that with descriptors ye
Though I guess you can do that like this py class Test: @classmethod @property def my_num(cls): return 1 print(Test.my_num)
iirc this doesn't work, but let me prove myself wrong
!e
class Test:
@classmethod
@property
def my_num(cls):
return 1
print(Test.my_num)
@surreal sun :white_check_mark: Your eval job has completed with return code 0.
1
i was in fact wrong lol
So why use descriptors when it's built in 
even if it's built in it still relies on the descriptor protocol nonetheless
without descriptor protocol thesewouldn't work
they rely on the __get__, __set__and__delete__ methods
yeah yeah 
ohh did i miss the joke haha
Nah, I'm just being cheeky. I'm sure they're useful
ahh
yeah honestly descriptors are just mostly cool because they look like black magic and can be used forsomeblack magic
ton of fun
Metaclasses fall under that umbrella as well for me

Yeah exactlyy they're so much fun
thank you ā¤ļø
this reminded me
!d unittest.mock.PropertyMock
class unittest.mock.PropertyMock(*args, **kwargs)```
A mock intended to be used as a property, or other descriptor, on a class. [`PropertyMock`](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.PropertyMock "unittest.mock.PropertyMock") provides `__get__()` and `__set__()` methods so you can specify a return value when it is fetched.
Fetching a [`PropertyMock`](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.PropertyMock "unittest.mock.PropertyMock") instance from an object calls the mock, with no args. Setting it calls the mock with the value being set...
that exists
is there a way to declare a class with an expression, like one can do __import__ instead of import statement?
ah interesting, an overload of type for declaring classes, not just getting class of an object
is there a way to declare functions as an expression? i know lambdas are limited to only one expression
I mean, I guess you could try instantiating FunctionType, though you'd still have to precompile its code object somehow
If you can do that at all
!e py from types import FunctionType FunctionType()
@spice pecan :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 2, in <module>
003 | TypeError: function() missing required argument 'code' (pos 1)
Okay, so you can indeed do that if you compile the code
oh i never knew you could do multiple things in lambdas
i thought it was limited to one expression
that's cool syntax
It's not really something you should be doing though, just make a named function at that point
@unkempt rock :x: Your eval job has completed with return code 1.
001 | 12
002 | result of func(7)=12
003 | 8
004 | Traceback (most recent call last):
005 | File "<string>", line 4, in <module>
006 | File "<string>", line 2, in <lambda>
007 | File "<string>", line 2, in <genexpr>
008 | OSError: asiajidjifhazkf
(()for()in()).throw(OSError("asiajidjifhazkf")) what
Wait I thought the keyword was raise
Why does that expression work
Just a small nitpick, the __set_name__ dunder isn't part of the protocol, but often used within descriptors.
For your __get__ conundrum, I've never really felt the need to subclass function for it. Could you describe your use-case?
you can try inspect.getsource(module) then disassemble that
wont always work, e.g. if the module's not written in python or some shenanigans replaces the module object with a proxy
what's proxy?
replacing sys.modules[module_name] with an object thats supposed to act as an intermediate step to accessing stuff in the module
interesting
so for example if you have this file:
import sys
value = 12
class Proxy:
@property
def value(self):
return value
sys.modules[__name__] = Proxy()
and then import it as a module, let's say called my_module, my_module.value = 123 will cause an error since the value property of the Proxy doesn't have a setter
this is generally cursed and frowned upon though
explicit is better than implicit. at least that used to be the case...
Also: refuse the temptation to guess
Hmm, why does this happen
!e
from string import ascii_letters
ascii_letters = [l for l in ascii_letters]
letter = "a"
match ascii_letters:
case letter:
print("Its a - letter!")
match ascii_letters:
case "a":
print("Its a - string!")
@gusty marsh :white_check_mark: Your eval job has completed with return code 0.
Its a - letter!
yep
match ascii_letters:
case letter:
print("Its a - letter!")
``` is the same as ```py
match ascii_letters:
case foo:
print("Its a - letter!")
If you want to compare for equality, you need to use an expression with dotted access
which I think is an unfortunate decision
is this the long awaited switch-case for py? š
im sry for going out of context
or you can use case l if l == letter:
So globals()['letter'] š
This is not switch-case. Rather, it's pattern matching. It's new in 3.10.
!pep 636
but it's similar to switch-case isn't it?
ah
sort of
hmm what's the difference bw them?
For one, no fallover
oh
oh-?
so a shud be an iterable in match case?
and b wud be the pattern in the iterable object
in match, sry
-
match-case doesn't have fall-through behaviour
-
match-case allows destructuring the thing, like ```py
match command:
case ["SET", name, value]:
storage.set(name, value)
return "OK"case ["GET", name]:
return storage.get(name)case [other_cmd, *_]:
raise InvalidCommand(other_cmd)
you should read PEP 636 if you want to know more
ooh so just regex but... better?
yeah and this is a general thing
sort of
hmm tysm
Yeah, I was trying to do something else but then noticed this... thanks
I am not sure if I understand this correctly, so if we pass a object in the case it would assign the match x which is ascii_letters to the object which is letter here?
just like _?
yeah š
!e
from string import ascii_letters
ascii_letters = [l for l in ascii_letters]
letter = "a"
match ascii_letters:
case letter:
print("Its a - letter!")
case "a":
print("_")
@gusty marsh :x: Your eval job has completed with return code 1.
001 | File "<string>", line 7
002 | SyntaxError: name capture 'letter' makes remaining patterns unreachable
right
!e
Something you could do is:
from argparse import Namespace
ns = Namespace(letter="a")
match "a":
case ns.letter:
print(f"Found an 'a'!")
With dotted access, you do an equality check against a value
@wide shuttle :white_check_mark: Your eval job has completed with return code 0.
Found an 'a'!
I'm just abusing the namespace class argparse uses for its arguments for a simple class builder here
:incoming_envelope: :ok_hand: applied mute to @unkempt rock until <t:1638184468:f> (9 minutes and 59 seconds) (reason: links rule: sent 14 links in 10s).
what's the difference between dir() and inspect.getmembers?
Ah alright
dir returns a list of names, getmembers returns pairs of name, value. dir result can be overridden with dir. getmembers can take a predicate.
itll use the predicate to filter out results
what else?
ah
dir returns a list of names, getmembers returns pairs of name, value. dir result can be overridden with dir. getmembers can take a predicate.
oops my keyboard acting up, not copying
Note getmembers() will only return class attributes defined in the metaclass when the argument is a class and those attributes have been listed in the metaclassā custom dir().
i was getting confused ^^
so getmembers basically defers to __dir__?
Yes, it uses dir to get the names to fetch values of
it does some extra stuff on top of it. inspect is pure python so you can take a look https://github.com/python/cpython/blob/3.10/Lib/inspect.py#L444
so.. things that manipulate their __dir__ like Enum can hide their attributes effectively?
if i had a slotted class that returns None from __dir__ ..
no way to discover its attributes?
wait. hu?
class B:
__slots__ = ["__dir__", "x"]
def __dir__(self):
return None
raises in <module> class B: ValueError: '__dir__' in __slots__ conflicts with class variable
curious
You shouldn't put methods inside __slots__ since they're effectively attributes on the class rather than a single instance
i wasn't planning to, i'm looking for a reliable way to get all attributes from objects, so i'm trying to think of ways that might break
Enum for instance manipulates __dir__ for some reason
!e ```python
print(object().dir())
@elder blade :white_check_mark: Your eval job has completed with return code 0.
['__new__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__init__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__', '__doc__']
I was curious to see what words of wisdom the first git commit held ...
If this worked (and you setup slots correctly) someone would still be able to do object.__dir__(that_instance) to get what you're looking for
Check pickle source maybe? Since it has to find all attributes yeah?
pickle.. don't they have extra dunder methods?
are you saying that with object.__dir__(obj) all my worries could go away?
holy crap
>>> object.__dir__(Enum)
['__module__', '__doc__', '__prepare__', '__new__', '__bool__', '__call__', '__contains__', '__delattr__', '__dir__', '__getattr__', '__getitem__', '__iter__', '__len__', '__members__', '__repr__', '__reversed__', '__setattr__', '_create_', '_convert_', '_check_for_existing_members', '_get_mixins_', '_find_new_', '__getattribute__', '__init__', 'mro', '__subclasses__', '__instancecheck__', '__subclasscheck__', '__sizeof__', '__basicsize__', '__itemsize__', '__flags__', '__weakrefoffset__', '__base__', '__dictoffset__', '__mro__', '__name__', '__qualname__', '__bases__', '__abstractmethods__', '__dict__', '__text_signature__', '__hash__', '__str__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__class__']
@elder blade you're brilliant
@lusty scroll you seeing this?
yes, I am seeing it
madness!
!e
or:
import enum
cls = enum.IntEnum
members = {
k:v
for typ in reversed(cls.__mro__)
for k, v in typ.__dict__.items()
}
print(sorted(list(members)))
@lusty scroll :white_check_mark: Your eval job has completed with return code 0.
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dict__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__module__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__weakref__', '__xor__', '_generate_next_value_', '_member_map_', '_member_names_', '_member_type_', '_missing_', '_value2member_map_', 'as_integer_ratio', 'bit_count', 'bit_length',
... (truncated - too long)
Full output: https://paste.pythondiscord.com/usipafejev.txt?noredirect
much noise, from the fact that IntEnum inherits many types
hoping it will one day be possible to do this:
members = { **typ.__dict__ for typ in enum.IntEnum.__mro__() } ^ SyntaxError: dict unpacking cannot be used in dict comprehension
correct me if I'm wrong, but in some other languages (Java comes to mind) you cannot avoid calling the "virtual" method
so even if you did
((Object) obj).__dir__()
it would still call
IntEnum::__dir__ ?
that's pretty close actually
can't you just do
{k:v for subdict in dicts for k, v in subdict.items()}
does IntEnum have an .mro() ?
__getstate__ and __setstate__ iirc
every class has an __mro__
Are starred expressions not being allowed to be use in list comps a trade-off/side effect or an intentional design?
Oh they switched to google groups?
idts, doesnt look too new
oh true
It's just a mailing list, you can see the same thread on python's mailman
nice channel name change
i don't believe so, it might be a mirror or alternative interface of some kind? last i checked, the mailman site was still hosting everything
ah
What was it before?
advanced-discussion
Ahh
the overarching goal remains the same: have a place to talk about Python itself at a high-level, rather than answer need-driven programming questions.
(though you can still ask questions about gaining a deeper understanding of Python itself)
š
Not wrong tho :thonk:
what's the purpose behind having a mro() as opposed to just __mro__ ?
I notice y'all aren't going in reverse order. Won't the specific types' keys be overwritten with object's keys this way? since mro goes from most to least specific, i would have thought
i err on the side of avoiding __ if python providers cuter-looking ones
i'd be nice if they'd provide a state(obj) which just returned __dict__
(is vars() just __dict__? i seem to remember it isnt)
maybe it is... i'd use vars() then, also
{k:v for subdict in enum.IntEnum.mro() for k, v in vars(subdict).items()}
it returns a dict, at least
!e
if i'm not mistaken , a sequence of tuples with overlapping "keys" (0th elements) , the later tuples will beat the earlier ones having the same key/0th item.
print(dict([("akey", 1), ("b", 2), ("c", 3), ("akey", 4), ("b", 5)]))
@lusty scroll :white_check_mark: Your eval job has completed with return code 0.
{'akey': 4, 'b': 5, 'c': 3}
!e
do you agree @unkempt rock , @dense grail ?
class Base:
def __init__(self): pass
class Derived(Base):
def __init__(self, val):
super().__init__()
self.val = 4
mbs1 = {k:v for typ in Derived.__mro__ for k, v in typ.__dict__.items()}
mbs2 = {k:v for typ in reversed(Derived.__mro__) for k, v in typ.__dict__.items()}
print(f"{mbs1['__init__']=}")
print(f"{mbs2['__init__']=}")
@lusty scroll :white_check_mark: Your eval job has completed with return code 0.
001 | mbs1['__init__']=<slot wrapper '__init__' of 'object' objects>
002 | mbs2['__init__']=<function Derived.__init__ at 0x7f06ac280ca0>
class A: pass
>>> A.__dict__ is vars(A)
False
>>> A.__dict__ == vars(A)
True
So I was previously convinced that it's okay to shadow useless builtins like id.
Until I started doing this a couple of times: ```py
def handle_foo(id):
print("Handling a foo with id: {0}".format(id))
Careless rename
def handle_foo(foo_id):
print("Handling a foo with id: {0}".format(id))
outcome:
Handling a foo with id: <build-in function id>
shadowing is a real pita
# __init__.py
import builtins
del builtins.id
Must-have for any new package /s
except when you might need it
I don't think I've ever actually needed id
but this manoeuvre will obviously break everything
yup
What exactly is the problem here?
Yeah, but sometimes you forget to use that
or sometimes you comment out the line that used id and then bring it back to life
Forgetting to rename your local id variable everywhere will not trigger an error
Ah, I see. I mean, there's not exactly any real advantages to ever shadowing something, so I just avoid it completely
shame that python has builtins squatting perfectly useable names like id and hash
usually by the time I'm using names like id, I'm in a class where I don't want id to be public anyways, so I use _id
what if it's a parameter?
idk, it depends on what I'm doing. When I was making my own ECS, I used entity_id instead of id
but shadowing really wasn't at my forethought when I came up with entity_id, I just think id itself might be ambiguous
TBH the hash builtin is somewhat useful
you only really use it if you're defining __hash__ for your own objects, i don't think it's that common
slice, reversed, pow, oct, format, divmod, callable, ascii - most useless builtins
hash is useful, but definitely not "needs to be a builtin" useful
hash and id could be in sys or something
i use reversed quite frequently
pow and divmod could be in math
already got **
as builtin
and //
!e help(divmod)
Return the tuple (x//y, x%y). Invariant: div*y + mod == x.```
why does this have to be a builtin anyway?
never considered for removal?
I use divmod more than reversed, but I don't think I've ever once used slice
Doesn't look like it ever was, https://www.python.org/dev/peps/pep-3100/#built-in-namespace lists some for removal but even some of those remained even though their utility as a builtin is really not big
of those, i'd consider removing abs, eval, exec and raw_input, (reload was removed already)
math.abs ~ np.abs
maybe even min, max
removing the temptation to use those on np arrays
those are used fairly often even in general use
min, max on lists maybe, not abs
yeah just min/max; don't recall the last time I used abs
did you need something from math?
I used it for making chess the other day
not everyone uses numpy, so min/max are still needed. I didn't know abs is in main namespace, I thought it's in math. + it's easily solved with max(a,-a) (although if a is something long, then walrus might be needed)
min/max are fine as builtin, at least it's not limited to math applications
subprocess exit codes
Yeah, there's absolutely no reason that max(["cat", "dog", "horse"]) should require importing something from math
hmmm can you name a module the same as a builtin and continue to use both?
ofc you can... lol nvm
was just thinking of an interesting way to solve this
from list import max, min
# or something else
that's really "interesting" :p
....i actually like this idea
most of those methods could possibly fit in operator
There's no reason why max(("banana", "apple", "carrot")) should require importing something from list
backwards compatibility breaks
There's no list in that code.
yep. max works on any iterable, may even be a generator
yeah, it was an example, operator would be a better namespace, or just leaving them as builtins
maybe it'd be nice to have a general module for sequences
itertools?
oh \š¤ max and min from itertools would make sense to me
There's also some like memoryview where they're almost never used, but it's also not like they're using up a name you'd want to commonly use
well, you convinced me that min and max earned their place as builtin
not so sure about the rest
solution: after defining everything, run from builtins import * š
I only just recently first used callable in my Python experience. Definitely the least useful.
!d callable
callable(object)```
Return [`True`](https://docs.python.org/3/library/constants.html#True "True") if the *object* argument appears callable, [`False`](https://docs.python.org/3/library/constants.html#False "False") if not. If this returns `True`, it is still possible that a call fails, but if it is `False`, calling *object* will never succeed. Note that classes are callable (calling a class returns a new instance); instances are callable if their class has a `__call__()` method.
New in version 3.2: This function was first removed in Python 3.0 and then brought back in Python 3.2.
does it do more than an isinstance would? I think I used it once in total
super builtin has bad documentation
iirc there are a few cases where isinstance will not match callable()
" If this returns True, it is still possible that a call fails" <- ehhhh..?
callable() belongs in inspect() I think.
typing?
eg call raises a notimplementederror
No, typing is all about static type checks. callable() is a dynamic check.
got a point there
uh, typing.Protocol?
heh
Still not completely sure where you'd use the descriptor version of it
It's checked statically, like everything else in typing?
er, how is callable dynamic then? /gen
It's checked at runtime
hasattr(obj, '__call__') and getattr(obj, '__call__') is not None
functions?
oh, i was pretty sure that typing.Protocol could be used in isinstance checks
functions also has __call__
or, classes which subclass protocol
Looks like typing does have @typing.runtime_checkable as a decorator to allow isinstance checks
But Protocol doesn't do it by default
ahhhhh
what about c-extensions?
@raven ridge :white_check_mark: Your eval job has completed with return code 0.
001 | True
002 | True
!e
x = lambda: print("hi")
x.__call__ = None
x()
@magic nova :white_check_mark: Your eval job has completed with return code 0.
hi
wtf
setting it on the instance while the lookup is on the type
ah
The built-in types are basically analogous to types defined in an extension module. They work in exactly the same way and use the same APIs.
If you want to truly monkey patch I think you need some actual wizardry there....
what about __new__?
!e You can't set it on the type.
x = lambda: print("hi")
type(x).__call__ = None
@raven ridge :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 2, in <module>
003 | TypeError: cannot set '__call__' attribute of immutable type 'function'
is that forwarded as a __call__ on the type or something?
Then fishhook is doing the equivalent of adding __call__ as an attribute, instead of overriding the tp_call slot. Which is a mistake people sometimes make when writing C extensions, too.
Someone in #c-extensions tried to define __str__ that way within the last week or so, and was confused why it didn't work.
By putting __str__ into PyMethodDef
@raven ridge fishhook modifies tp_call
Does it set just tp_call and not tp_vectorcall maybe? Setting those to incompatible implementations results in undefined behavior from the interpreter
i cant remember if i ever added the code to null out tp_vectorcall
yea currently fishhook never touches tp_vectorcall (its only used for type and function afaik and removing the default implementation there will crash, as your hook can never be called)
if you could hook function.__call__ internally it would recurse infinitely and crash in the C code
because the hook itself is a python function. so when it is attempted to be called, it would be recursive
its undefined by definition, but from my reading of the source code, the interpreter just ignores tp_call if tp_vectorcall is set
except for type which will crash the interpreter if type.__call__ is hooked (for the same recursion reason)
tp_vectorcall can only be customized if its not on something critical (ie type/function)
!e ```py
from fishhook import *
@hook(type)
def call(self, *a, **k):
print(self, a, k)
return orig(self, a, k)```
@pliant tusk :x: Your eval job has completed with return code 139 (SIGSEGV).
001 | <class 'type'> ('<94000787646112>', (<class 'fishhook.P'>,), {'__call__': <function __call__ at 0x7fd3efe769e0>}) {}
002 | <class 'TypeError'> ('unbound method type.mro() needs an argument',) {}
003 | <class 'TypeError'> ('unbound method type.mro() needs an argument',) {}
004 | <class 'TypeError'> ('unbound method type.mro() needs an argument',) {}
005 | <class 'TypeError'> ('unbound method type.mro() needs an argument',) {}
006 | <class 'TypeError'> ('unbound method type.mro() needs an argument',) {}
007 | <class 'TypeError'> ('unbound method type.mro() needs an argument',) {}
008 | <class 'TypeError'> ('unbound method type.mro() needs an argument',) {}
009 | <class 'TypeError'> ('unbound method type.mro() needs an argument',) {}
010 | <class 'TypeError'> ('unbound method type.mro() needs an argument',) {}
011 | <class 'TypeError'> ('unbound method type.mro() needs an argument',) {}
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/ekepaqipim.txt?noredirect
yea that one breaks because fishhook needs to make classes in order to grab function pointers
Some things in some places still call tp_call instead of using the vector call protocol, so if you set them to something inconsistent, some things might use the old slot and others the new
fishook was never meant for production anyways ĀÆ_(ć)_/ĀÆ
And there's no documented guarantees about when vector call is used, so it's the developer's responsibility to not set them to something inconsistent.
it can only be inconsistent if you try to hook one of the callable builtin types (something that already has other issues that a hooking lib cant solve without assembly code)
I'm just talking about C static types in general. I know essentially nothing about fishhook
But for user defined C types, the docs specifically call out that it's the user's responsibility to set them both to something that does the same thing.
oh yea i agree with that
i tried to make fishhook do that but ran into some weird wrapping issues cause of the places were the implementation isnt consistent about what is called
....what in the world
where do or and and do different things which aren't necessarily bools...
or...
have my bools been lying to me this whole time
!e eg
print(2 and 3)
```prints 3
whereas ```py
print(0 and 5)
```prints 0...
So where exactly do bools behave like bools, or has this always been a thing even in if conditions?
@white nexus :white_check_mark: Your eval job has completed with return code 0.
001 | 3
002 | 0
iirc you always get the last value evaluated. and shorts at 0 because the statement cannot be true.
a or b returns a if it's truthy, otherwise b.
a and b returns a if it's falsey, otherwise b
Hm, that's right. I use some or tomfoolery in some of my model assignments.
var.get("keyname") or {}
but how does that work in condition statements.... oh
The same way.
I just used this to make pyright happy
webhook_id: Optional[int] = int(env.get("WEBHOOK_ID",0)) or None
If either operand is truthy, or returns something truthy. If either operand is falsey, and returns something falsey.
Doesn't pyright see that as inferred type int | None or is env a dict[any, any] here?
var.get("keyname", {})
Wait, it's wrapped in int(). That should infer int | none
Allows keyname to be None in the payload which is undesired.
oh
It's in the contract that the api I'm talking to can give me none, but I don't want to model none. I'd rather model and empty dict. :)
dict is str,str
but--
!e int(None)
@white nexus :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 1, in <module>
003 | TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'
so I pass a falsey default value from env.get()
Right, I was just confused by the type hint. Doesn't seem needed is all. The or makes sense in your case.
(its part of a dataclass)
I might just use environs TBH
thanks tho, just used my first and in assignment š
Essentially, it's the truthiness of objects in python that lets you use and and or outside of bools. The rules don't change, just the implied truthiness is used
But dict.get() has an argument for defaults š¢
. your PR review lol
I compile Python in my brain so I can make any additions I want
But so far I just removed f-strings and walrus
Yes, my brain has a SATA port
You removed fstrings? But its one of the most useful features
Don't we all
did you figure out how to get the compiled artifacts out of your brain and make them run on silicon chips? ^^
graphite? that doesn't make sense :p
did you mean graphene?
i'd say the next big thing are silicon chips, actually
optronics
let's take it to #ot0-psvmās-eternal-disapproval
what an unfortunate course of action
what the heck?
lol
i was just experimenting a little with __call__ and found something curious
def f(): pass
object.__setattr__(f, "__call__", lambda: print("ehhh"))
>>> f()
>>>
Right, that's because magic method are looked up on the type, not the instance
<@&831776746206265384> would you mind?
@gray hemlock wrong channel, go to #āļ½how-to-get-heck
lmao
meh š
!pban 654239909732941844 Seems like you're only here to troll. Please take that elsewhere.
:incoming_envelope: :ok_hand: applied purge ban to @gray hemlock permanently.
ty
Works as expected, functions don't really use their __call__ attribute, that's just for compatibility.
Also aren't magic methods looked up on the type anyways?
So this wouldn't even work if it would work
well, i was more surprised that object.__setattr__ didn't complain about it in the first place, i was expecting some kind of read-only wrapper
function.__call__ returns a wrapper, yeah
Right, but this only assigns it in the instance dict
The function type is one of the few (if not the only) builtins that allow setting arbitrary attributes
!e ```py
def f():
print(f.attr)
f.attr = 10
f()
@spice pecan :white_check_mark: Your eval job has completed with return code 0.
10
!e
class Foo:
def __str__(self):
return "foo"
f = Foo()
f.__str__ = lambda: "bar"
print(f)
@quick snow :white_check_mark: Your eval job has completed with return code 0.
foo
that's.. wha..? access to the locals?
no
you can set arbitrary attributes on a function object
It's an attribute on the function object
what about closure functions?
same
can you get access to them from the outside?
outside of where?
as attribute of f?
yep
When you make a "closure function" you create a new object every time
it's a name lookup followed by an attribute lookup, there's no magic going on
lame
!e
def f():
def g():
return g.x
return g
g1 = f()
g2 = f()
g1.x = 42
g2.x = 69
print(g1(), g2())
@grave jolt :white_check_mark: Your eval job has completed with return code 0.
42 69
i meant f.g
isnt there a way to refer to the function itself inside of it
you can probably do that with inspect
eh, also lame
def f():
def g():
print("foo")
>>> f.g
Traceback (most recent call last):
File "<pyshell>", line 1, in <module>
AttributeError: 'function' object has no attribute 'g'
that's more interesting to me
Why would it have an attribute g? Does the function even exist yet?
it doesn't, right?
there's one g for every invocation of f
the code object exists already, but not the function
f.attr does not access a local inside f if that's what you were asking about
yeah, gotcha
functions don't really store their locals, because there may be several calls to the function at once
and that would create a lot of cycles
let's say i want to decorate g() from the outside, programmatically
i'd need to get the code object and work with that?
yeah, that's just changing the code of f
Unless you're in a multi threaded context you also don't really have a chance of accessing the locals from a function, apart from the things the function itself calls but those can have them passed in in the first place
how would you go about it? use ast on the code object, compile and put it back?
Depends what you want to do
programmatically decorate g from the outside?
You'll need to use inspect to find the code of the function, then turn it into an AST, then modify the AST, then compile the AST back.
I'm not sure how to do that correctly, never done that
You can do it without inspect and parsing AST
you could manipulate bytecode directly, but that's a bit of a hassle
You don't need to do that either
manipulating bytecode to decorate the function would be pretty easy
Just create your own wrapper function (a) that calls a dummy function (b), then replace the code object of the b with the code object of a, after having replaced the code object of b with the code object of the function to be decorated (c).
fixing jumps that come after that... yeah nah
that is if you want to make a classic "wrapper" decorator (do things before call, call function, do things after call)
You get (and set) the code objects inside co_consts, no need to ever touch co_code
i didn't get that, but that's probably because i never worked with code objects directly before
I'll try to build a proof-of-concept
thanks š
Damn, I can't set __closure__. That might make this difficult in general :D
What I do if I don't want to deal with the AST is just inspect.getsource(the function)
replace parts of the code (via just str.replace)
exec the source code now (the changed one, set to inspect.getsource(the function) then changed accordingly), with __locals set to locals,
and then I just reassign function to locals()[function.__name__]
cc @verbal escarp ^ if you wanna do it this way
getsource wouldn't work in the REPL regardless so even fix's solution wouldn't work
(a little late, I slept... yay!) You are 100% correct, .get() does have a default. In this edge case, however, the dict being parsed should contain another object at the keyword but can contain None. So even if I default to an empty dict, I hand a factory None if that's the valid value of the key. Instead of the overhead to identify and handle None, I chose to still create an object. Just an empty one.
# Instead of handling `None` as a possible value for
# .build_from(), we default to an empty dict() which
# allows the factory to fullfil the request.
team = Team.build_from(result.get("team") or {})
Perhaps a bit of laziness, but it allows the object factory to remain simple, asks forgiveness instead of permission, and falls-through on bad data from an unreliable vendor. Since its a provider library, ultimate validation of the data is on the consumer regardless.
Huh š¤
i'm not concerned about the REPL, only code from files
why esoteric? it's a seemingly simple question
ah awesome, if you want a really easy solution you could just get the source of the function, edit the source code string, exec that, get the new function from locals() and yeah
hmm.. that feels like a very crude instrument, but i'll keep it in mind as a last resort
Yeah its probably cleaner to modify the AST
it's more of a lazy way to do it
always good to have options
@rapid schooner I don't think this is the purpose of this channel
IIRC pytest doesn't manipulate the bytecode, but rather, manipulates the ast before it becomes bytecode
it rewrites every assertion by default, so its likely to have a good internal way of modifying the code
This blogpost explains how pytest rewrites assert statements in files its test finder has discovered: http://pybites.blogspot.com/2011/07/behind-scenes-of-pytests-new-assertion.html
py.test 2.1 was just released . py.test, which uses the Python assert statement to check test conditions , has long had support for display...
since when do you write c?
it's used to look up docs in IPython/Jupyter
but not in the core language, no
hm
This has helped me out a lot when starting https://docs.python.org/3/tutorial/
very cool!
what is that in python ?
self.foo()(params)
foo() call returns a callable
foo is a method that returns another callable
which is then being immediately invoked
Are you asking what the name foo means or how self.foo()(params) works
If it's the first, it's just a placeholder name
Hey anyone know why inspect.getblock is not in the docs?
It's not on the inspect page or the search
https://docs.python.org/3/library/inspect.html
I can see it's in the source, so I know I'm not imagining it at least.
i see it under retrieving source on that link you gave. i dont have an answer to your question though. just took a look.
https://bugs.python.org/issue17972 lloks like theyomit many functions
Where are you seeing it?
getblock not getdoc lol
im so sorry
At some point I started looking at getsource, these names sorta mix together
Thanks Jason, that looks about right
On that note, is there someway to get all the lines that define a variable? I can probably figure out the first line of the variable by just looking for it's name, but that's kinda hacky, and can't find the last line for multi-line variables
!e ```python
src = """
x =
'hello'
' world'
y = (
1 +
2 +
3 +
4 +
5,
'h'
)
"""
import ast
module = ast.parse(src)
for a in module.body:
if isinstance(a, ast.Assign):
target_names = ','.join(name.id for name in a.targets)
print(f'{target_names} {a.lineno}:{a.col_offset} - {a.end_lineno}:{a.end_col_offset}')
@paper echo :white_check_mark: Your eval job has completed with return code 0.
001 | x 2:0 - 2:24
002 | y 4:0 - 11:1
ast is great
last time i wondered how to decorate closures, which was only doable with extremely volatile code from hell.. now i'm wondering if there is a more straight forward way to at least tell whether there's a closure function inside (and maybe its name)?
def some_func():
count = 0
def closure():
nonlocal count
count += 1
return count
do closures need to be nested in functions
in this case i'd like to have a function find_closure(some_func) -> ["closure"]
that's pretty much the definition of "closure", yeah
although, i'm not 100% about classes in classes
that could also be closures in a sense
<@&831776746206265384>
!ban 913379681426866186 Racism
:incoming_envelope: :ok_hand: applied ban to @grim quarry permanently.
ty
whats the difference between
def some_func():
count = 0
def closure():
nonlocal count
count += 1
return count
and
count = 0
def closure():
global count
count += 1
return count
in the second example, closure is defined globally, no problem. you can decorate it and do whatever you like with it. in the first example, closure is not defined outside of some_func and it's very hard to get a handle on it
yea, the difference is how they can be referred to, not how they close over values then
so any function that uses a name not passed to it is a closure
difference is that functions also can have attributes, which are available outside and don't have to be passed in
but a closure function isn't even defined really until the outer function is called
you need to do some crazy bytecode or ast-gymnastics to do anything with a closure-function
in #esoteric-python i got https://gist.github.com/thatbirdguythatuknownot/524234dbe8415f1873da57713fa0869c as a POC for decorating a closure
so now i figured it might be simpler to just detect closures and notify the user about unreachable functions
why not make your decorator decorate the return value of the outer function
yeah
you could just run the decorator as a regular function on the return value
and maybe wrap that into another decorator if you need to
hu?
let's say you have an inner function and some looping etc. happening in the outer function
There most be something in code object for this. I checked code but didn't find any relevant thing.
if you want to decorate the inner function for instance to see what's happening, decorating the outer function's return value (which doesn't necessarily return the inner function) wouldn't help any
Nice question š
it's weird.. i love using closures to simplify stuff, but now this seemingly simple problem almost is en par with figuring out how to make subprocess-interpreters work
it's like the spanish inquisition
I have taken this as an interview question and here is the solutionš
import dis
ans = []
flag =0
nflag = 0
bytecode = dis.Bytecode(some_function)
for ins in bytecode:
if nflag == 1:
ans.append(ins.argrepr)
if ins.opname == 'LOAD_CLOSURE':
flag = 1
if ins.opname == 'MAKE_FUNCTION':
nflag = 1
else:
nflag = 0
return ans if flag == 1 else []```
interview question? oh man, you're evil š
print("hello world")
i would argue that all functions are closures, but top-level functions are only closed over the top-level scope
that was exactly what i was thinking but if you look at examples of closures online theyre always nested in some other function
while it could go either way, closures usually capture their lexical state right? e.g. a closure would 'close over' the parameters passed to the enclosing function
it closes over the names, not the values
well, not really names
but references to values
def f():
def g():
print(34)
def find_closure(some_func):
import dis
ans = []
flag =0
bytecode = dis.Bytecode(some_func)
for ins in bytecode:
if ins.opname == 'LOAD_CLOSURE':
flag = 1
if ins.opname == 'MAKE_FUNCTION':
ans.append(ins.argrepr)
return ans if flag == 1 else []
>>> print(find_closure(f))
[]
you sure about this applicant? š
looks almost too easy
the heck?
not sure if that's the expected result
Is g the closure function? If yes then I have missed some edge cases.
yeah, g is the closure
what edge cases did you cover?
"the search for closure" - the new novel about love and sadness and weird edge cases
but disassembler is showing some different story (edited)
what would g be if not a closure?
oh, so internally it's only considered a closure if g needs a reference to something in the outer function
def f():
x = 23
def g():
return x
return
exactly
but i also get the same result as @lusty scroll - it returns ["closure"] and not the name
if there's an internal difference between nested functions and closures, how to deal with nested functions?
i feel like tumbling down a rabbit hole š
i dimly remember having problems pickling closures in the past, yes
sorry, i have update the code
ty
i recall having seen STORE_FAST before
hahaha
i broke your code š
def f():
x = 23
def g():
return g
but this opcode should we followed by MAKE_FUNCTION with argrepr='closure'
now it returns ['x']
wait
looks like more update in it is required
def g(): return g is so outlandish, it should probably belong in #esoteric-python
how to compute this:
ValueError: b requires closure of length 0, not 1
i noticed for my test function it was doing LOAD_CONST instead of LOAD_CL0SURE, from the looks of it
updated again, hopefully this will work for all
import dis
ans = []
flag =0
nflag = 0
bytecode = dis.Bytecode(some_function)
for ins in bytecode:
if nflag == 1:
ans.append(ins.argrepr)
if ins.opname == 'LOAD_CLOSURE':
flag = 1
if ins.opname == 'MAKE_FUNCTION':
nflag = 1
else:
nflag = 0
return ans if flag == 1 else []```
seems to hold, yep.
!e
this sort of works:
from types import FunctionType, CodeType, CellType
def a():
def b(t):
return 9
return b
def find_closure(some_func):
import dis
ans, args = [], []
bytecode = dis.Bytecode(some_func)
for ins in bytecode:
if ins.opname in ('LOAD_CLOSURE', 'LOAD_CONST'):
args.append(ins.argval)
if ins.opname == 'MAKE_FUNCTION':
ans.append([*args[-2:], ins.argval])
return ans
x = find_closure(a)[0]
func_b = FunctionType(x[0], a.__globals__, x[1], None, (CellType(),) * x[2])
print(func_b)
print(func_b(7))
@lusty scroll :white_check_mark: Your eval job has completed with return code 0.
001 | <function b at 0x7f8884895a20>
002 | 9
yes, but that's just the easiest way to demonstrate it. all functions in python are always and automatically closures. but the property of a function being a closure is easiest to demonstrate with nested functions
i agree that it's often not explained well
would it be any function that references a non-local, or would this be a closure as well:
def a():
pass
yep, at least in my understanding of what the word means, a is a closure, but it is only closed over the top-level module scope
Seems to be this https://github.com/python/cpython/pull/29577
Hasn't the idea of treating type instances like sets been floated over the years? Is there a reason this hasn't been implemented?
(or rather, made part of the spec)
what would it mean to treat it like a set?
@spark magnet obj in cls being an alternative to isinstance, comparison operators for issubclass
i see
haven't set foot in this unfamiliar territory for a long time... internals-and-peps? this place has changed
agreed. the line between eso and ad used to be thin
hm, sounds like gh/objectivitix/dundermagic/compareclass lmao
the intended topic of this channel hasn't changed
i forgot the actual repo path, but i made a metaclass whose classes have subclass testing with comparison ops
, >=, <, everything works
yeah, i know, i love this name change
perhaps the reason issubclass shouldn't be replaced by comps is because they considered ABCs and __subclasscheck__ (or __issubclasscheck__, forgot). using comparison operators might imply a direct subclassing relationship and excluding ABCs
ah yes, thank you
after aoc i shall make squarepython
square functions, square classes, any ordinary python callable shall be squared
oh my, yes
squareclasses
4 sided classes, duh
well that was an interesting read
spent some time reading a person arguing against python, saying that they would rather teach someone python 2 than 3
especially because python doesn't have a standard
lol
this is gold
there's this part that stands out to me, could someone who was around/known a bit about the 3.0 to 3.4 gap explain a bit?
You also have no idea what history of Python was like. the 13 years you quote are very misleading. Very few people wanted Python 3 13 years ago. It's a miracle that Python 2 vs Python 3 didn't end up the same way Perl 5 did. It very much could've been the same story (in retrospect, it would've been better, if Python 3 just died / was renamed after some anime character, while Python 2 stayed).
Python 3 versions prior to 3.5 weren't really used. There were many reasons. Performance degradation, incompatibility. In general, Python 3 didn't and still doesn't offer anything of value that would justify updating from Python 2. It's all cosmetic changes, which incur a huge penalty on anyone wanting to update. The acceptance of Python 3.5 started with large Linux distributions being forced into it by Python Foundation abandoning support for Python 2.7. Nobody wanted to pick up the slack and support Python 2.7, so, naturally they had to use the newer version, just to stay afloat.
In my life, I had to update Python from 2.5 onward in many different projects. There hasn't been a case when things improved as a result of update. At best they stayed the same.
The first Python 3 version I ever used was 3.5. 3.0 and 3.1 were missing some important features that eventually led to the ability to write 2+3 compatible code in a reasonable way - like support for u"foo" unicode literals. 3.0 and 3.1 both had some serious bugs as well, I believe.
Support did eventually coalesce around Python 3 for various reasons - nice new features, loss of upstream support for 2, etc - but for a long time, it's true that it wasn't clear that 3 would win, and big corps were reluctant to switch to it as a result
the first Python 3 version with a feature that I really miss when writing Python 2 code is 3.6, with f strings
and when they switched to Unicode strings for text, it took them a long time to figure out how to handle things that people expect to be able to use string functions with, but which don't necessarily have a well defined encoding - like command line arguments and filesystem paths, both of which are arbitrary byte strings, not necessarily textual strings.
Python 3, for me, fixed a lot of crucial language feature errors that would/did result in a huge amount of bugs. But yes, there was a huge amount of momentum for python2, and python2 wasn't a bad language, it just could have been better. And such a big change came with some very large speedbumps that didn't really get cleaned up until 3.4ish
Plus, nobody really has a desire to rewrite all their code just so that later they'll write less bugs. You need new features to be attractive, and those started properly showing up with 3.4
Python 2 made it really easy to write code that worked with your test input, but failed in production when it had to deal with real people's names, or things like that. But at the same time - once you had that code tested and debugged, there was very, very little value in upgrading to Python 3
