#internals-and-peps
1 messages Β· Page 161 of 1
load 5 ([] -> [5])
load z ([5] -> [5, z])
swap ([5, z] -> [z, 5])
assign x ([z, 5] -> [5])
assign y ([5] -> [])
pretty sure changing the order of 5 and z on the stack is called "swapping"
I see
should there be a special case that replaces UNPACK_SEQUENCE/SWAP with just the store instructions in the right place
It's not always legal to reorder things, since one of the two loads could raise an exception, and it's important that all of the RHS happens before the LHS.
yeah they should
i'm talking about reordering the STORE_*s
Hmm that could be doable, not sure if tracing etc could make that observable. Hmm also __del__ could be sneaky...
I think that could cause problems for tracers like debuggers
What was the pep that allowed this syntax @list_of_callables[0] or @obj.attribute_which_is_callable?
Previous versions you couldn't use attribute or item access with @ during decoration
Are you sure? Definitely could use attribute access
yeah, you could
I see, I thought it was both that were blocked
Hi I am trying to find people who are interested in efficient coding, My mission is to find solutions for coding problems with the minimum time complexity possible. If anyone's interested DM me. Thanks!
!rule 6
buddy, how is this advertising? this is purely for educational purpose.
Its offtopic for the channel, ask in offtopic
Found this in the help of array.array:
NOTE: The 'u' typecode corresponds to Python's unicode character. On
narrow builds this is 2-bytes on wide builds this is 4-bytes.
AFAIK, narrow/wide builds aren't a thing anymore since 3.3. Should this just be removed and changed to always be4?
I think so, worth verifying in the code or REPL though
array.array("u", "hello").itemsize == 4, in my REPL. I'll look into the code..
Looks like it.
'u' is wchar_t (https://github.com/python/cpython/blob/6fd4c8ec7740523bb81191c013118d9d6959bc9d/Modules/arraymodule.c#L562=).
What's new in Python 3.3:
The distinction between narrow and wide builds no longer exists and Python now behaves like a wide build, even under Windows.
Modules/arraymodule.c line 562
{'u', sizeof(wchar_t), u_getitem, u_setitem, u_compareitems, "u", 0, 0},```
are you interviewing developers?
no I am the candidate
don't study for an interview: answer honestly. if you don't know an answer, be clear about your thought process to figure it out.
and #career-advice would be a better place for this topic
any idea why https://peps.python.org/pep-0505/ was deferred?
Python Enhancement Proposals (PEPs)
That's an interesting take
I certainly do like a lot of that pep, especially the user defined null protocol. I know singletons are frowned upon but I use them quite a bit at work in certain parts bc it just makes development cleaner in certain aspects. Passing around None is too much of a catch all and you lose context some times. It's like using np.nan as both a signaling that a floating point computation went bad and to represent missing data. Can't tell what the original context was without looking backwards
It looks like the internals for the ABCs (collections.abc) were re-written in C for Python 3.7, but the Python implementation remains in _py_abc.py. Does anyone know if/when this Python implementation is still used? It seems like the C implementation has had some changes since then and they could behave differently.
possibly on pypy? If you see a behavior difference, that's a bug, so please report it so it can be fixed
Sure - I just see the difference by reading the code but without knowing when the Python implementation is used I couldn't actually test or make it happen. It looks like it will fall back to the Python implementation if it fails to import the C module, so maybe I can force that to happen or just monkeypatch a proof-of-concept.
It's a difference in subclass registration and setting Py_TPFLAGS_MAPPING/Py_TPFLAGS_SEQUENCE - I'm not sure this is relevant for PyPy because I imagine they have their own implementation of these flags or something like it.
you can set the C module to None in sys.modules before import to force the python version
Thanks - good call.
Okay I got the minimal example working, but also realized it's basically this bug, but for Mapping instead of Sequence: https://github.com/python/cpython/issues/89646
The investigation led me to this function though, which is neat: https://docs.python.org/3/library/test.html#test.support.import_helper.import_fresh_module
yes, I think a few tests use that to assert that the C and Python versions of some modules match :))
@dusk reef this is not a help channel; see #βο½how-to-get-help
I'm looking for some general feedback on code style/legibility. E.g. part of this:
def _createFiles(imagelist):
if len(imagelist) == 1:
print('WARNING: single image found - sequential pipeline')
raise NotImplementedError
else:
p = lambda x:(str(Path(config.dataset_path) / x))
originalFileNames = [i.get('file_name') for i in imgs_seq_lookup.get(imagelist)]
baseFilePaths = [p(i) for i in originalFileNames]
cats = [i.get('category_id') for i in imgs_seq_lookup.get(imagelist)]
ids = [i.get('image_id') for i in imgs_seq_lookup.get(imagelist)]
for baseFilePath, categoryId, imageId in zip(baseFilePaths, cats, ids):
if config.generate_histlp:
lbp = colorhistslbp.getLpb(baseFilePath)
This is not PEP-8, but is it fine? Should I adhere more to standards?
You should.
Is colorhistslbp your code? Make get_lpb() take a path-like object.
You don't need all those .get(), since your code would anyways fail if those values were None.
If you're assigning a lambda to a name, you're doing something wrong.
First approximation of improvement:
def create_files(imagelist):
if len(imagelist) == 1:
logger.warn("single image found - sequential pipeline")
raise NotImplementedError
for img in imgs_seq_lookup[imagelist]:
base_path = Path(config.dataset_path) / img["file_name"]
cat_id, img_id = img["category_id"], img["image_id"]
if config.generate_histlp:
lbp = colorhistslbp.get_lpb(base_path)
instead of
logger.warn("single image found - sequential pipeline")
raise NotImplementedError
do ```py
raise NotImplementedError("single image found - sequential pipeline")
Hi guys. I'm interested in learning more about the garbage collector in Python. Just started reading the Garbage Collection Handbook by Jones, Hosking & Moss (2011) but was wondering if anyone had other recommendations / more recent texts. Sorry if this is the wrong channel.
This is the right channel! Are you aware of https://devguide.python.org/garbage_collector/ ?
Nope. I didn't know there was a devguide. Ty!
I wonder whether there should be a link from the gc module docs to that devguide article; it's a fantastic write-up, and it's not as discoverable as it deserves to be.
How can I call internal cpython functions in python
I want to call the _PySys_ClearAuditHooks
Since there is no variant of it in the sys module
Python/sysmodule.c line 322
* and as such the function is not exported.```
anything is possible using ctypes, but you may get segfaults instead
I also don't see why they would remove the feature. Doesn't it make sense that if you can add an audit hook you should also be able to remove it?
if audit hooks could be removed, that would defeat one of the biggest points of having audit hooks. The hooks are supposed to tell you what the arbitrary code you call is doing, and if that arbitrary code could just silently uninstall your hook, they'd fail at doing that.
I mean.. there is an audit hook for _PySys_ClearAuditHooks, so at least that could be logged
ah true, so at least it wouldn't be silent.
Well they can still be removed just not through one function call sadly
just got the idea in python-general, but i guess here's a better place for that: what would be required (syntax-wise?) to have x = mylist[0] as a lazily evaluated variable?
can't you just do it with a custom getitem on a custom subclass? or am I misunderstanding something
i was thinking of a global, but a descriptor could work
ooh forgot about descriptors
that makes it easier
do those work in non-attribute variables?
Can you explain what you mean by "lazily evaluated variable"?
x = mylist[0] # add syntax-voodoo to make it lazily evaluated
mylist[0] = 1
x == 1
mylist[0] = 2
x == 2
like a label in a UI
Understood now
just make a proxy class
that just forwards every method call to the current element of the list
I think that should work?
Do you require x is 1, or is x == 1 fine?
either way is fine
like dict_values, I see
!e
class LazyList(list):
def __getitem__(self, item):
return ItemProxy(self, item)
class ItemProxy:
def __init__(self, parent, item):
self.parent = parent
self.item = item
def __eq__(self, other):
return list.__getitem__(self.parent, self.item) == other
my_list = LazyList([1,2,3])
x = my_list[0]
print(x == 1)
my_list[0] = 2
print(x == 2)
@quick snow :white_check_mark: Your eval job has completed with return code 0.
001 | True
002 | True
@amber nexus gave a different approach in py-gen: ```py
import ctypes
import builtins
base = ctypes.py_object.from_address(id(globals()) + 8)
class fglobals(dict):
slots = ()
def getitem(self, key, dict=dict, base=base, builtins=builtins, getattr=getattr, print=print):
print(f"Looking up {key}")
try:
base.value = dict
return self[key]
except:
try:
return getattr(builtins, key)
except:
return key
finally:
base.value = class
base.value = fglobals
a = 10
print(a)
forward the lookup
lots of work for a "simple thing" π
def __getitem__(self, key, dict=dict, base=base, builtins=builtins, getattr=getattr, print=print):
```Is rather cursed
And gives me an idea π
can't be the only one who ever wondered about lazily evaluated variables..
@amber nexus base = ctypes.py_object.from_address(id(globals()) + 8) throws me off, why the +8?
ha! π
okay, lazy expressions are another thing i've been pondering about, mostly as conditionals evaluated as rules
Uh I think the first 8 bytes are a pointer or something along those lines, I need to dive into CPython's internals a little more
but simple variables that work like labels is really hard, never seen that in the wild
nah, it's fine. thanks π
For your usecase using lazex is a bit explicit, which I think I read somewhere is better than implicit, can't remember where.. :P
x = lazex.Expression("my_list[0]")
(it came from a desire to be able to do stuff R can do)
yet, simple is better than complex - and passing the expression as a string isn't beautiful π¦
i'm guessing you're eval-ing?
ah, parse and ast-juggling
crazy monkey
huh
waitasecond
if annotations aren't evaluated, couldn't you use that?
or variable docstring
x = lazycrazy()
"""
my_list[0]
do not try this at home!
"""
Yes. But you have to keep track of the locals/globals of the frame.
I mean, you could do lambda: my_list[0]
anyone can call a function, that's not cool
indeed
You can replace __annotations__ with something that helps you with that (remembering locals/globals)
is x evaluated every time you print it or just once?
In lazex? Never automatically.
The first 8 bytes of any object are the reference count. The second eight bytes are a pointer to the objects type
getting the type
struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
PyTypeObject *ob_type;
};
btw the size of object can be anywhere from sizeof(void *) + sizeof(Py_ssize_t) to sizeof(void *) * 3 + sizeof(Py_ssize_t)
can't it be larger than that? Tuples allocate their elements in the memory after the head struct.
sizeof(_object), they meant. Because _PyObject_HEAD_EXTRA can be 0 pointers or 2 pointers, depending on whether it's a debug build of Python.
i see
Include/object.h lines 65 to 76
#ifdef Py_TRACE_REFS
/* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA \
PyObject *_ob_next; \
PyObject *_ob_prev;
#define _PyObject_EXTRA_INIT _Py_NULL, _Py_NULL,
#else
# define _PyObject_HEAD_EXTRA
# define _PyObject_EXTRA_INIT
#endif```
it's part of the reference tracing built into debug builds.
Does anyone know of any free hotel or flight Api's to get prices?
this channel is about Python internals, and Python Enhancement Proposals (PEPs)
I'm sorry, do you know what channel I would go to about python Api's?
you could ask in #python-discussion - I don't think there's any appropriate topic channel.
if the first bytes are the ref count, what happens if there are more than 255 references to an object?
The first 8 bytes are the ref count. So the max ref count of an object is the max signed 8 byte number
so, can there be an overflow of references?
255 would be the maximum number of references if the first 1 byte was the reference count.
In theory yes, but that would be very difficult and slow in practice
instead, the first 8 bytes are, so the maximum number of references is 18446744073709551616
It's signed @raven ridge
ah, ty
ah, well that that / 2
So this would be the max 9,223,372,036,854,775,807
is there a test against this potential vulnerability?
not even in theory, no - a program that could use all of those references (without a reference leak) wouldn't be able to fit them into a 64 bit address space.
that is, an object can have at most 9,223,372,036,854,775,807 references, and each of those references uses 8 bytes, and a 64-bit program can use at most 18,446,744,073,709,551,616 bytes of memory, so that can't happen.
unless something miscounted its references, but then you were in undefined behavior territory anyway.
hmm
why does each ref use 8 bytes?
because a reference is a pointer.
the reference count of an object is how many shared ownership pointers to that object exist.
okay
Afaik you can generate a ref miscount with hand crafted bytecode
But that puts you in undefined behavior anyways
right.
it's really easy to do with the C API, as well - just incref a borrowed reference, or fail to decref a strong reference
but in either of those cases, you've screwed up badly, anyway - you've leaked an object, it will never be destroyed.
please don't tell me its possible to make the refcount negative
π
I think I vaguely recall that the garbage collector itself relies on that to do some tricks
the refcount field is also a public field of the object structure - you can assign whatever you want to it from the C API. It's wrong to ever do that, but nothing stops you.
!e ```py
from ctypes import *
import sys
x = 255
c_ssize_t.from_address(id(x)).value = -2
print(sys.getrefcount(x))```
@pliant tusk :white_check_mark: Your eval job has completed with return code 0.
-1
like that π
oh my.
that's cheating!!
(I picked 255 because most other objects would have crashed it lol)
well, it's the only way to do it, absent a bug.
that's comforting
I mean I can use hand crafted bytecode or one of my handful of memory bugs to do it
There are fun things you can do when the gc runs at unexpected times
both of those are just bugs (well, one might be undefined behavior rather than a bug, but that's splitting hairs)
the normal way to manipulate reference counts, even when you're using the C API, is to use functions that increment/decrement the reference count by 1, and when it reaches 0 the object is destroyed. Getting it to go negative would require doing abnormal stuff.
that's 18 exabytes, no? we might need to rethink that approach in a couple of years ^^
Unlikely, but if we ever need to, we can. 32-bit address spaces were the norm until about 15 years ago, and those only supported up to 4 GB
good ol' times π
we've already gone through 8 bit, 16 bit, 32 bit, and 64 bit computers. We might hit 128 bit one day.
okay, concerns are mitigated for now, thanks π
hi
i noticed that in python when u create a file within a directory that doesnt exist python ends up with an error, would it be an improvement if i create a issue and a pr relating to this, in the pr the directory being cretaed if it doesnt exist and then the file is put into it
it's not really Python's responsibility to create directories for users to put files in
what if someone has mistyped the directory name? wouldn't it just end up creating redundant dirs
just like every other language
There's also good reasons not to automatically create missing directories - ownership and permissions, for one.
docker-compose moment...
quite annoying
Actually, I think that's docker's behaviour, compose doesn't change it. If the target directory doesn't exist when mounting a volume, it's created.
should the set abc also require the named methods like set has to be defined? Currently __le__ etc. are required, but usages of some of those feel confusing to be compared to just doing e.g. issubset
I think it's bad operator overloading
yeah I'm not sure how I feel about the operators themselves other than maybe union/intersection/difference
The use of logical operators to do set ops is fine bc they're all the same thing
Like there's very uniform definition between logic, predicate calculus, and set theory
it also looks like it's impossible to check a proper subset without operators on a plain set, that could me a kwarg on the issubset method
I was just about to mention this
So gt is superset and lt is sunset? I've never even thought of using the relationship operators for subsets
is expanding an abc like that something that's viable?
hey i need help with turtle
ask in #python-discussion
See you posting in python ideas
why do we use isalpha instead of is_alpha()
Because a consistent coding style was not established at the time it was added, and renaming it would be a breaking change.
Can someone help me im new to python
Would someone kindly be able to help me with micropython?
@quaint sedge @unkempt rock please open a help channel, see #βο½how-to-get-help
does anyone knows
how can a app be designed such that it activates only in location tracker range..
See the frozen timecapsule that is the logging module π
Hi
Hi. I had someone ask me if len(gc.get_referrers(thing)) == sys.getrefcount(thing) should always be True, is this a reasonable expectation or no?
dunno, to weak_refs count as referrers
!e ```py
import gc
import sys
a = []
b = [a, a]
print(len(gc.get_referrers(a)))
print(sys.getrefcount(a))```
@inland acorn :white_check_mark: Your eval job has completed with return code 0.
001 | 2
002 | 4
4? 
!d sys.getrefcount
sys.getrefcount(object)```
Return the reference count of the *object*. The count returned is generally one higher than you might expect, because it includes the (temporary) reference as an argument to [`getrefcount()`](https://docs.python.org/3/library/sys.html#sys.getrefcount "sys.getrefcount").
There we go
π€¦π»ββοΈ
imagine a squre and in that square there are doors to each side.
then you go to each room and start boiling water in the room then move to another room to start to boil another water until they are all done.
is this an example of async?
you are python
boiling water is the task
then each function is the room?
Yeah, especially if you emphasize that you go to first room, andbset it to start boiling and immediately move into the next room and set it to start boiling. Maybe call it turning the gas on or something like that
it's that easy? 
oh also how would you know that the water is already boiling?
Basically you check each room to see if it is boiling, handle that situation, then go back to looking
There is some other stuff where you can get notified when it is boiling so you know to check that room first when you can
for normal IO, the OS tells you it finished
in order?
like room 1 first then room 2...
can it skip rooms?
The system for checking can be designed as you see fit
Generally implementations keep track of when pending tasks were checked last, if it's a check based system. And then items that haven't been checked in a while start getting higher prio for next check
Order isn't guaranteed in the real world. To keep with your example, what if the amount of water in each room is unequal? Then room will take unequal amounts to reach boiling. Your scheduler just keeps checking and ultimately as rooms get finished you keep moving on
The main thing though, is that essentially any task where the actual work doesn't require you, you can have it "start working" and then then you're free to do whatever while it keeps going
This is analogous to io bound tasks, where something external is doing the work
- I can design the checker
- It will check EACH one in the order they are started?
Depends on how you design it
Let's just say, no, order isn't guaranteed
You can design your checker in such a manner that it always checks tasks in order
But often there's smarter ways to do things
Since different tasks may take different amounts of time, or effort

It's honestly not even that, I'm just trying to keep things simple

Ultimately the scheduler could even start the tasks out of order
It's like giving a command, turn gas on in room 1, turn gas on in room 2, etc
But then your assistant is the one turning gas on, and maybe they just like doing things out of order
Bottom line is, with async, you give up guarantees about what order things happen in, but you gain benefits of having multiple tasks, as a whole, finish faster because wait time is reduced.
That make sense?
I'm trying to but this doest make sense to me code wise 
Code wise, it's like a queue of tasks to start, and a queue of ongoing tasks to check, maybe with some kind of "last checked" indicator
(the rust book is really good at teaching async, it even has you code an async implemention from scratch! You just need to have read the rest of the book first, I.e learn rust)
That could be one simple implementation

now this makes sense
starting to make sense
now it all makes sense
Yay
π₯³
I should probably mention that it may still be worth reading some kind of resource on this
Have you ever had a bug where things were happening in the wrong order, or particular style changes were being ignored? Ever fixed that bug by wrapping a section of code in a setTimeout? Ever found that fix to be unreliable, and played around with the timeout number until it kinda almost always worked?
This talk looks at the browser's event loo...
It's definitely a different style of programming, and you just want to let the concept sit in your mind for a bit
If you are willing to learn rust π
Ah great! Then I highly recommend the rust book
I actually remember a python talk, that started very innocently with generators, and ended up essentially building a full async system
Let me see if I can find it
...
my brain can't read 
I am using a dataclass to store some counts and aggregated values and have a few properties to return average or calculated values. In a code review someone has suggested that where I increment the counts in a method I should implement a method on the class which does the increment. This feels hugely unnecessary since Python letβs us increment the attributes directly. Am I missing something?
ie this:
def increment_val(self):
self.val +=1
I'd talk it out with them, hard to say without context.
There isnβt much more context, I mainly just wanted to try and understand if there are generic compelling reasons not to directly increment attributes before I shoot down the idea?
maybe for logging? would be easier to add that to a function. also easier to change 1 function than change like 30 individual increments
I usually go the other way, simple implementation first, and refactor if it ends up being harder to maintain
Fully agree. If for whatever reason you really need custom logic later for incrementation, then you can always replace the simple attribute with something more complicated that still works with the normal incrementation syntax.
!e
class Foo:
def __init__(self):
self._var = 0
@property
def var(self):
return self._var
@var.setter
def var(self, new_value):
if new_value - self.var != 1:
raise ValueError("only allowed fo increment!")
self._var = new_value
f = Foo()
print("var is", f.var)
f.var += 1
print("var is", f.var)
f.var += 2
print("var is", f.var)
@quick snow :x: Your eval job has completed with return code 1.
001 | var is 0
002 | var is 1
003 | Traceback (most recent call last):
004 | File "<string>", line 19, in <module>
005 | File "<string>", line 12, in var
006 | ValueError: only allowed fo increment!
you can also use +=1
yes he was aware of that, read his original message
Is it possible for us to put a "-" in a string. after a word in a long string(sentence). The main issue for me that me I'm not sure it is even possible or not.
Has anyone worked on "recommendation systems" ?
need advice on how to determine how much a user has liked certain content when i am not taking single feedback(like in movie we rate out of 5) but the feedback is indirectly given based of :
duration of uptime
liked/dislike
shared the content or not etc.
the base of easier problem is we have movie to rating dataset but how do i determine rating in my case?
of idea is as follows, AM i right?
except score everything is bool
@granite ravine Try #python-discussion or a help channel
as for internals of python, is there a no-op bytecode instruction? i want to make it so that two or more identical compiled code objects can hash to different values (long story as to why but suffice it to say i cant change the functionality of the code objects or add the two+ bytecode objects to a list of sorts)
There is a NOP instruction documented
You're welcome
keep in mind where you add the NOP's since it will affect all the absolute jumps after it
yeah it would probably be best to put them at the end
oh yeah i was going to add them at the end of the function
thanks, i didn't realize that!
or put anything at the end really since i don't think you ever fall off the end of a code object without encountering a RETURN_VALUE so it would never be ran
i bet there's an esoteric way to not have a return value but yeah that assumption is probably safe for most cases
geen probleem π
why did you scratch it
in what case would that happen?
!e ```python
import dis
def test():
pass
dis.dis(test)
@elder blade :white_check_mark: Your eval job has completed with return code 0.
001 | 3 0 RESUME 0
002 |
003 | 4 2 LOAD_CONST 0 (None)
004 | 4 RETURN_VALUE
Oh, alright.
!e import dis def test(): raise Exception dis.dis(test)
@feral island :white_check_mark: Your eval job has completed with return code 0.
001 | 2 0 RESUME 0
002 | 2 LOAD_GLOBAL 0 (Exception)
003 | 14 RAISE_VARARGS 1
Hi experts, I have a question and I think it might be best suited for this channel:
Python by default builds the library libpythonMAJOR.MINOR.a and statically links it into the interpreter. Also it has an --enable-shared, (https://docs.python.org/3/using/configure.html#cmdoption-enable-shared) flag, which will build a shared library libpythonMAJOR.MINOR.so.1.0, and dynamically link it to the interpreter.
Are there any benefits of a shared build python, compared to a static build python? Is there any performance difference?
I found a related question on SO and is it like he said (https://stackoverflow.com/a/73035776/5983841), shared built vs statically built python only affects the "Embedding Python in Another Application" scenario ?
hello
do you think it would work if most python builtin libaries are rewritten in c?
and maybe even more things
many already are
yeah, things like math, list, dict are C
personally i think they've over-written libs in C. there are modules in the stdlib written in C that probably didn't need the boost.
curious, which ones are you thinking of?
i knew someone was going to ask that π
functools? bisect?
operator probably
is datetime time-critical?
at least parts of operator can't be written in Python
right, but some parts can be, and are still in C. It's not a lot of C, but still.
wait which parts? it looks to me like it's all just functions that are equivalent to operators
operator.indexOf for one
def indexOf(a, b):
for i, el in enumerate(a):
if el == b:
return i
return -1```
hm yes, PySequence_Index is pretty much equivalent to that, thought it would do something more direct. I'd have to check if any others do C API calls that aren't directly exposed to Python
no it would do literally the exact same thing
i checked the source code, it calls _PySequence_IterSearch which just uses the C equivalents of iter and next
the C version throws an error if the index exceeds the possible range of a C int
granted, not a very likely condition π
import sys
def indexOf(a, b):
for i, el in enumerate(a):
if i > sys.maxsize:
raise OverflowError("index exceeds C integer size")
if el == b:
return i
return -1```
... i didn't mean to start a fight...
With the existence of non-entry frames in 3.11, making functools pure-Python might actually speed up partial rather than slow it down.
at the very least it would save a bunch of frames on the C call stack per call to a partial
non-entry frames?
what did i miss?
!e
print(__import__('sys').maxsize)
@grave jolt :white_check_mark: Your eval job has completed with return code 0.
9223372036854775807
that's gonna be one hell of a loop π
operator.index(range(10 ** 1000), 10 ** 999)
so I was looking at cpython source (specifically: https://github.com/python/cpython/blob/main/Lib/operator.py#L339-L355=), because I was wondering about the difference between iadd and iconcat, and it seems to just be that iconcat has an error check? is there a reason for this or? ```py
def iadd(a, b):
"Same as a += b."
a += b
return a
def iconcat(a, b):
"Same as a += b, for a and b sequences."
if not hasattr(a, 'getitem'):
msg = "'%s' object can't be concatenated" % type(a).name
raise TypeError(msg)
a += b
return a```
concat is for a different c api method, but the c level methods also both fall back to each other
ah, I forgot stuff is sometimes implemented in C and python
I asked about why it is a thing a while back, and I think it pretty much was just because it was implemented in the C operator module when it was added, even though the two are pretty much the same when used from python
that's one big leaky abstraction π
it still needlessly creates and destructures args and kwargs into the arguments
you sure that's needless? Seems it'd be pretty tricky to get print(locals()) to do the right thing otherwise
maybe not impossible, but it's certainly not as easy as just inlining the bytecode from the called function into the caller
needless for the partial
partial isn't exactly a hot spot in typical code - optimizations that might be specific to partial don't seem terribly worth pursuing. I only pointed it out because it's interesting that moving it to Python might actually make it faster, since it doesn't benefit much from being in C, and it's missing out on that inlined frames optimization as a result
on3.11.0b4
In [2]: a=functools.partial(lambda:None)
In [3]: %timeit a()
62.2 ns Β± 0.39 ns per loop (mean Β± std. dev. of 7 runs, 10,000,000 loops each)
In [4]: sys.modules["_functools"] = None
In [5]: importlib.reload(functools)
Out[5]: <module 'functools' from 'C:\\Users\\miso1\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\functools.py'>
In [6]: a=functools.partial(lambda:None)
In [7]: %timeit a()
229 ns Β± 1.73 ns per loop (mean Β± std. dev. of 7 runs, 1,000,000 loops each)
while probably not a hotspot, I'd also expect it to be as cheap as it can be. Some callbacks can be triggered a lot, which is where a partial also fits in perfectly
wow, that's much more of a difference than I would have expected
thanks for checking my conjecture with data π
That's really good speed up
I know 3.11 isn't going to be ground breaking but I think it's a great step forward
that's not really related to 3.11 - that's showing the speed difference between the C functools.partial implementation and the Python functools.partial implementation
Oh I misread that at a glance
https://github.com/python/cpython/issues/93910#issuecomment-1188892439
Later versions will have larger region optimizations allowing us to inline the property call (3.14 at the earliest).
π
we're getting inlines in python 3.14??
that sounds like a weather forecast for three months from now: very speculative
well i mean we're starting to do a lot of optimizing in 3.11 and above
I remembered I read a blog post once that explained how, because of implementation choices that were being made anyways
it was very cheap, nearly free, to provide insertion ordering
on python 3's dict
but I cannot find it
anybody know of a blog post that explains a bit about this?
Hello everyone! As of today, we merged the latest branch that brings better dictionaries to PyPy by default. The work is based on an idea ...
thank you!
It's already in 3.11 - though inlining here just means the interpreter pushes a frame, then jumps back to the beginning of the eval loop to execute the new function, without needing to call a new C function. There's also several specialisations implemented so that things like __getitem__, properties and even __init__ can use this to quickly run the Python code.
yeah well i already know about the frame thingy
but if that's just that then what does he mean by "inline the property call"
It does sound like potentially actually inlining the actual code for simpler function calls, which would be very nice.
Builtins are defined within the interpreter, but standard libraries and modules are defined in the library folders that ship with the interpreter, correct?
builtins is also a module
which gets auto imported when you run the interpreter interactively (i.e. the Python REPL)
So the interpreter imports int and the like from a .py file somewhere?
it's not a .py file, it's a module that's written in C
ok
the module or builtins are not really imported into your modules (unless you import it yourself), instead it serves as the namespace from where python looks up the builtins when you try to get them
for a generic name lookup, cpython will first look at the locals dict, then the globals dict if locals don't have the key, and builtins if the global lookup fails
ah. right.
Ok
also why you may sometimes find something like def f(int=int) as it'll turn the "slow" builtin lookup (first tries to find global, then the builtin) into a fast locals lookup
I see... That way every time code inside f references int, it's in locals. I guess it only has to try as far as builtins once when called then?
Yes; if it's used in a tight loop it may be a noticeable speed benefit, but on the other hand a loop where that may help is probably better of not being in pure python
right
I'm designing a hardware implementation of Python, so I have plenty of questions that I haven't been able to work out through the docs and other resources. When i call import foo, __loader__ is instantiated to try and find a module or package by the name foo?
According to the REPL __loader__ is _frozen_importlib.BuiltinImporter.
can you say more what you mean by hardware implementation?
Hey all how can I automate running my python function in a jupyter notebook? I know I can do with schedule library in a python file but I don't know how to proceed with jupyter notebook
This isn't really the right channel for that, but it sounds like you're using jupyter notebooks for something other than their intended purpose.
you should think of jupyter notebooks as the end of the line. if you need anything in a jupyter notebook outside of that exact notebook, at any time, it should be defined in a py file outside of the notebook, and be imported into it.
He might mean just programmatically running the notebook, which there are libraries for, even take cli
@ashen kelp see link
I'm big into homebrew CPUing and I'm designing one that executes Python bytecode. Here's my project so far: https://github.com/AwesomeCronk/SiliconPython
This is the simulator I'm using: https://github.com/hneemann/Digital/

