#internals-and-peps
1 messages · Page 83 of 1
Surely you should just trust the docs RE: behaviour. Simply going by observation feels a bit like thinking a coin is bias because you did 5 flips and got 5 heads?
Relying on something that isn't documented is kind of silly no?
@flat gazelle wrong words. people shouldn't have to be clever to write python
you want smart people writing code
you do, but even dumb people should manage
If the docs say "dict order is not guaranteed" that is fine. Even if a particular implementation happens to cause it to be guaranteed
I don't check the docs for every little oddity I find, there would definitely be at least a few people who would decide to use it out of laziness
list(dict.fromkeys(l))```vs
```py
ls = set()
r = []
for elem in l:
if elem not in ls:
ls.add(elem)
r.append(elem)
it is useful enough that I think even the docs would make go: eeeh, I will fix it later
There are plenty of things where quirks can trip you up though no?
>>> n = 1
>>> n2 = 1
>>> n is n2
True
>>> n = 14
>>> n2 = 14
>>> n is n2
True
>>> n = 10000
>>> n2 = 10000
>>> n is n2
False
Like this behaviour can get people
The assumption here is that the documentation gets read. That's not always a given. Especially because the docs are less visible in search results than endless tutorial sites.
(re: rtfm)
yes, that is an annoying quirk. But it is easy to fix, since you can just replace is with==. There are other things which would be nicer to have to deal with, but its not horrible.
@unkempt rock Ordered dicts are nice for building GUIs. Saves you from having to use collections.OrderedDict everywhere
Why is wierd behaviour at last lines of code above
integers from -3 to 255 are cached and always use the same instance
all other integers are allocated anew
Yeah it does
!e 1 is 1
@feral cedar :white_check_mark: Your eval job has completed with return code 0.
<string>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
>>> 1 is 1
<stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
True
Ha beat me to it
In [14]: x = "HelloWorld"
In [15]: y = "Hello" + "World"
In [16]: x is y
Out[16]: True
In [17]: x = "Hello World"
In [18]: y = "Hello " + "World"
In [19]: x is y
Out[19]: False
though I don't think I ever saw this in real code
can't ordereddict be enumerated by int?
generally people figure out is vs == by strings
>>> 0 is False
<stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
False
>>> 0 == False
True
This is fun
We should try to reduce the use of is operator
there is one use for is: identity.
which applies to singletons like None, True, and False every time
also NotImplemented
isn't NotImplemented an Error?
NotImplemented is a singleton, NotImplementedError is an error

Is ... a singleton?
yes
I've never seen NotImplemented used as an object
!d NotImplemented
NotImplemented```
Special value which should be returned by the binary special methods (e.g. [`__eq__()`](../reference/datamodel.html#object.__eq__ "object.__eq__"), [`__lt__()`](../reference/datamodel.html#object.__lt__ "object.__lt__"), [`__add__()`](../reference/datamodel.html#object.__add__ "object.__add__"), [`__rsub__()`](../reference/datamodel.html#object.__rsub__ "object.__rsub__"), etc.) to indicate that the operation is not implemented with respect to the other type; may be returned by the in-place binary special methods (e.g. [`__imul__()`](../reference/datamodel.html#object.__imul__ "object.__imul__"), [`__iand__()`](../reference/datamodel.html#object.__iand__ "object.__iand__"), etc.) for the same purpose. It should not be evaluated in a boolean context.
Note... [read more](https://docs.python.org/3/library/constants.html#NotImplemented)
It's a special value that you return if you don't implement a dunder in a certain instance
It allows Python to look for an implementation in the class of the object on the other side of the operator
oh, oops
ah, interesting
class Foo:
def __init__(self, value):
self.value = value
def __lt__(self, other):
if not isinstance(other, Foo):
return NotImplemented
return self.value < other.value
I've never had a need for it. that's nice
In this case, if you use anything but an instance of (a subclass of) Foo at the other side of the <, you return NotImplemented
In [27]: 4 .__mul__('aaa')
Out[27]: NotImplemented```
This allows Python to then look for an implementation in the other class
Weirdly it has a bit of a quirk amongst the python singletons:
>>> NotImplemented = 'a string'
>>> True = 'a string'
File "<stdin>", line 1
SyntaxError: cannot assign to True
>>> False = 'a string'
File "<stdin>", line 1
SyntaxError: cannot assign to False
>>> None = 'a string'
File "<stdin>", line 1
SyntaxError: cannot assign to None
>>> __debug__ = 'a string'
File "<stdin>", line 1
SyntaxError: cannot assign to __debug__
>>> ... = 'a string'
File "<stdin>", line 1
SyntaxError: cannot assign to Ellipsis
Yeah, in this case, the int does not define a multiplication with a str, but str does implement multiplication with integers
yeah, its not really important enough for a syntax level singleton, so its just a builtin.
So, if you do 4 * "aaa", Python will first look for an implimentation in int for 4, does not find one there, and then goes on to "aaa" to see if it makes sense there
Which it does, so you get "aaaaaaaaaaaa"
And now I am veryyyy confused:
>>> ... is Ellipsis
True
>>> Ellipsis = 'a string'
>>> ... = 'a string'
File "<stdin>", line 1
SyntaxError: cannot assign to Ellipsis
... is probably a special case in the identifier rules
Ellipsis is one of the built-in constants, and the same as the literal ...
One is a literal, but the other is just a name that's not protected like False and True are
ah, it's not even an identifier apparently, so it gets refused as any other literal with a bit different text
Just makes me laugh:
>>> ...
Ellipsis
>>> Ellipsis
'a string'
>>>
Yeah I noted that up there somehwere^
does the ! symbol have a use in Python? I can't remember
https://docs.python.org/3/library/constants.html mentions the 4 "proper" constants
Ah, missed that
Don't think it's used anywhere other than != and the format language
There's !=
And, yeah, the conversion specifiers in string formatting
Other uses don't come to mind
May be in future Python versions they may take advantage of these symbols I guess
? Has a few proposed uses, don't like ` too much for any syntax
https://docs.python.org/3/library/constants.html mentions the 4 "proper" constants
@peak spoke What is up with...? I know it's a literal but it does seem to be different to other literals:
>>> 1 = 10
File "<stdin>", line 1
SyntaxError: cannot assign to literal
>>> ... = '1'
File "<stdin>", line 1
SyntaxError: cannot assign to Ellipsis
well, it's just... ellipsis
It's a Singleton in the family of None and co.
It gets a specific SyntaxError message like True/False etc, but the value it refers to Ellipsis can actually be assigned to
As I showed above
So it's kind of odd
Would probably have to look into the source for why it's handled like that. But id guess it's because if the dot syntax which is already used for attr access
But it is on the page? https://docs.python.org/3/library/constants.html#Ellipsis
It's just funny to me that Ellipsis appears to be a builtin constant for the literal ... so then when you try assigning to ... it tells you it can't assign to the literal Ellipsis then when you assign to Ellipsis it works haha
I guess cannot assign to ... might have looked a bit strange as a message
!e
import dis
dis.dis('... = 42')```
@undone hare :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "/usr/local/lib/python3.8/dis.py", line 38, in _try_compile
003 | c = compile(source, name, 'eval')
004 | File "<dis>", line 1
005 | ... = 42
006 | ^
007 | SyntaxError: invalid syntax
008 |
009 | During handling of the above exception, another exception occurred:
010 |
011 | Traceback (most recent call last):
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/jaxupofaku.txt
I wonder if you can break numpy by assigning to Ellipsis. It seems to use Ellipsis in a couple of places
You will just shadow it with a name in your module-level globals
It won't actually "break" the name internally
Just like assigning to the name list
Depending where and how numpy uses it, you may or may not see issues
It uses it in like a two modules
lib.arraypad, lib.shape_base, and core.shape_base I think
I don't know enough about numpy to know where the code it's used in has effect
Yeah __builtins__ are shared
Say that you have a two.py with this in it:
def foo():
return Ellipsis
and then have a one.py with this:
from two import foo
import builtins
Ellipsis = "One"
print(foo()) # prints Ellipsis
builtins.Ellipsis = "One"
print(foo()) # prints One
Could also reassign the c pointer
Ah right yeah
What is happening here:
>>> __builtins__.True
File "<stdin>", line 1
__builtins__.True
^
SyntaxError: invalid syntax
>>> __builtins__.Ellipsis
Ellipsis
does python have a builtin random string generator for like passwords?
!d secrets
New in version 3.6.
Source code: Lib/secrets.py
The secrets module is used for generating cryptographically strong random numbers suitable for managing data such as passwords, account authentication, security tokens, and related secrets.
In particular, secrets should be used in preference to the default pseudo-random number generator in the random module, which is designed for modelling and simulation, not security or cryptography.
@safe hedge that’s the fault of the parser
Ooo sick, thanks @spice pecan
I’ll let our dear Batuhan anwser haha
Weirdly it has a bit of a quirk amongst the python singletons:
>>> NotImplemented = 'a string' >>> True = 'a string' File "<stdin>", line 1 SyntaxError: cannot assign to True >>> False = 'a string' File "<stdin>", line 1 SyntaxError: cannot assign to False >>> None = 'a string' File "<stdin>", line 1 SyntaxError: cannot assign to None >>> __debug__ = 'a string' File "<stdin>", line 1 SyntaxError: cannot assign to __debug__ >>> ... = 'a string' File "<stdin>", line 1 SyntaxError: cannot assign to Ellipsis
@safe hedge for True/False/None, they are embedded in the grammar. NotImplemented and Ellipsis are kept as normal names. The thing with __debug__ is, it is actually preventing changing the code flow. On the compile time __debug__ is optimized depending on the flags passed into the compiler, so if __debug__: print(1) would just appear if you disable __debug__ and vice verse. For preventing users to mess with this, assigning to __debug__ is disabled (since runtime assignments won't have any affect on compile time optimizations)
The reason that changing the value of builtins.Ellipsis won't change the value of ... is, it is also embedded in the grammar to statically point to the real Ellipsis object rather than a lookup to the builtins.Ellipsis on each ocurrence
The error messages actually from the same place, but we have special conditions against True False etc.
I guess then the question is why ... and not Ellipsis too?
And then finally why does my interactive interpreter throw a syntax error on __builtins__.True and __builtins__.False?
As I said, True and False are parsed as constants not normal names
so you can't actually chain them as normal attributes
just like you can't actually access an attribute that is not a valid identifier like "$"
you could use setattr/getattr for these though
It is also mentioned in the page I linked previously that they're forbidden also as attrs
Direct assignment to the dicts only cares about them being strings right?
I guess then the question is why
...and notEllipsistoo?
@safe hedge for this, I dont know for sure. If you have time, probably you could search for discussions in the time of introducement ofEllipsisto figure out
Direct assignment to the dicts only cares about them being strings right?
@peak spoke what do you mean by direct assignment?
a[b] = c?
It is also mentioned in the page I linked previously that they're forbidden also as attrs
@peak spoke Literally that was where I started this rabbit-hole journey from, and how I realisedNotImplementedwasn't protected. I just blanked on the second half of that note hahah
Yeah going through the globals builtin or the setattr you mentioned
Hoisted by my own petard RE: RTFM from earlier haha
The first time I noticed the attes was when I found out you can access pretty much any string in strings through format
AFAIK (seen in the past, might be not the case for now) when pytest is rewriting the assertions (to get a prettier output) they use $ prefix to normal names on their constructed AST
So that it wouldn't suppress anything on the scope
why does ellipsis exist?
I couldn't really find the intial reason last time I checked as it already existed for python 1
I remember seeing discussions that it was existed to support a.b[...] syntax only
but need to check
I think that's one of the things mentioned in Fluent Python, that it was to have things like a[1:3, ..., 4] slice notations
I think it was even only allowed in slice notation before Python 3
sebastiaan@sebastiaan-N53SV:~$ python2.7
Python 2.7.18 (default, Aug 4 2020, 11:16:42)
[GCC 9.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> ...
File "<stdin>", line 1
...
^
SyntaxError: invalid syntax
>>> class Foo:
... def __getitem__(self, i):
... return i
...
>>> f = Foo()
>>> f[...]
Ellipsis
One thing that I remember from python 2 times was a[. . .]
infinite whitespace allowed between each dot on py2
erm...
an empty slice shallow copies a list, right? [:]
yeah
is there similar behavior for dicts or other builtin collections?
Likely true for the ones that allow slices, since empty slices get filled with start=0, stop=length, step=1
For dicts you can use their .copy method, for example
In python3, slicing is syntactic sugar for creating a slice object and passing it to the same dunders that cover regular indexing, so __getitem__, __setitem__ and __delitem__ (I think?) (Yeah, __delitem__ is a thing)
!d slice
class slice(stop)``````py
class slice(start, stop[, step])```
Return a [slice](../glossary.html#term-slice) object representing the set of indices specified by `range(start, stop, step)`. The *start* and *step* arguments default to `None`. Slice objects have read-only data attributes `start`, `stop` and `step` which merely return the argument values (or their default). They have no other explicit functionality; however they are used by Numerical Python and other third party extensions. Slice objects are also generated when extended indexing syntax is used. For example: `a[start:stop:step]` or `a[start:stop, i]`. See [`itertools.islice()`](itertools.html#itertools.islice "itertools.islice") for an alternate version that returns an iterator.
The elipsis was mainly added for numpy (and other third-party frameworks that wanted to take advanced of it)
Say, you have a[1, :, :, :, 2] in numpy
That's equivalent to a[1, ..., 2] (in numpy!)
I like using the elipsis as a placeholder for a function body that I’ll write later
saving one char of pass
The ellipsis didn't have a use in the stdlib until relatively recently, when it got a use in typing IIRC
I typically just add a docstring for that purpose, so that I have a description of the function I still need to write
I see pass more as a way to declare an empty body, rather than just a placeholder
Yeah, the only advantage of Ellipsis over pass is it is an expression. So if you are trying to encode some sort of math formula, like x = A * (2 + b) - 5 + ... * 4 etc it might be handy to not to forget put there something
I don't really see the need for pass tbh
since it can be replaced with ...
...or a docstring!
I feel like it better communicates the intent in some cases
There are some legitimate cases where you’d want an empty body, like if you need to have an empty with statement, I feel like it communicates best that you don’t have to do anything in there, you just pass it
^
what would the purpose of an empty with statement be?
for the side effects
!e
class X:
def __enter__(self):
print("foo")
return self
def __exit__(self, *args):
print("bar")
return False
with X():
...
@grave jolt :white_check_mark: Your eval job has completed with return code 0.
001 | foo
002 | bar
or for exception handling
well, ... can't throw any exceptions, right
but the unpacking in with can fail
like
!e
class X:
def __enter__(self):
print("foo")
return []
def __exit__(self, *args):
print("bar")
print(args)
return True
with X() as [a, b, c]:
...
@grave jolt :white_check_mark: Your eval job has completed with return code 0.
001 | foo
002 | bar
003 | (<class 'ValueError'>, ValueError('not enough values to unpack (expected 3, got 0)'), <traceback object at 0x7f5ac7d41c80>)
well... if a program doesn't produce any side effects, it's pretty useless 🙂
A functional program still produces side effects.
the result of a haskell program is a very complex side effect
well, yes, Python isn't a functional programming language
and things like that are pretty gross
ye
I don't think I ever needed an empty with
I used the redirect stdout once or twice
imagine coding an entire program by using enter exit context managers
O_O
horrifying
@unkempt rock take a look at https://github.com/decorator-factory/context_manager_patma if you want something horrible with context managers
This is what I'm talking about
whitespace isn't even the worst esolang 😛
!ot
Off-topic channels
There are three off-topic channels:
• #ot0-psvm’s-eternal-disapproval
• #ot1-perplexing-regexing
• #ot2-never-nester’s-nightmare
Their names change randomly every 24 hours, but you can always find them under the OFF-TOPIC/GENERAL category in the channel list.
class X:
def enter(self):
print("foo")
return []
def __exit__(self, *args):
print("bar")
print(args)
return True
with X() as [a, b, c]:
...
Hi. I have experience programmming in python and solving engineering problems using python.
I would like to improve my software development skills in python -> designing maintainable software by using OOP concepts etc.
Can anyone suggest resources and opensource projects which can help?
Hey @Mkk_#0996 and @rao#5271, see #❓|how-to-get-help
Can anybody explain what are two problems caused by the deepcopy through examples as mentioned in this documentation
``Recursive objects (compound objects that, directly or indirectly, contain a reference to themselves) may cause a recursive loop.
Because deep copy copies everything it may copy too much, such as data which is intended to be shared between copies.``
>>> from copy import deepcopy as dc
>>> l = [1, 2, [3, 4, [5, 0]]]
>>> d = dc(l)
The 2 nd point is , while we create d from l unnecessary elements such as l[0],l[1] is enough to be copied no need to get deepcopy as they are imutables hence consuming more data( The data is enough to be just copied rather than deepcopied)
import random
def random_graph(n):
R = [[0] * n] * n
for i in range(0, (len(R)*len(R))):
a = random.randint(i, n - 1)
b = random.randint(i, n - 1)
if a==b:
R[a][b] = 0
R[b][a] = 0
elif a!= b:
R[a][b] = 1
R[b][a] = 1
return R
@unkempt rock This is not a help channel, this is a discussion channel. See #❓|how-to-get-help an open a help channel.
thanks
what are the cases when __call__ is invoked?
I'm seeing some example cases where method overrides to __call__ are doing super().__call__ instead of super()() just curious why that would be the case
when you call an instance of the class and when you specify the class as a metaclass. As for the super thing, that is just convention to make it visually similar to other super method calls
super([type[, object-or-type]])```
Return a proxy object that delegates method calls to a parent or sibling class of *type*. This is useful for accessing inherited methods that have been overridden in a class.
The *object-or-type* determines the [method resolution order](../glossary.html#term-method-resolution-order) to be searched. The search starts from the class right after the *type*.
For example, if [`__mro__`](stdtypes.html#class.__mro__ "class.__mro__") of *object-or-type* is `D -> B -> C -> A -> object` and the value of *type* is `B`, then [`super()`](#super "super") searches `C -> A -> object`.
The [`__mro__`](stdtypes.html#class.__mro__ "class.__mro__") attribute of the *object-or-type* lists the method resolution search order used by both [`getattr()`](#getattr "getattr") and [`super()`](#super "super"). The attribute is dynamic and can change whenever the inheritance hierarchy is updated.... [read more](https://docs.python.org/3/library/functions.html#super)
I would say either is fine
okay, so super() would never return a type
I've never seen super()() in real life and I would be a bit confused
Does it work?
Since super returns a proxy object
Probably
hmm, good point. Let me test my example
it does not
I don't think it works. You'll probably get something along the lines of "super object not callable"
but, I can't test it right now
huh, that does make sense, I guess it would be a bit silly to delegate dunders
I guess this is why __init__ gets explicitly called, too
well, how would you do that with __init__
In [8]: class U:
...: def __call__(self):
...: print('aha')
...:
In [9]: class V(U):
...: def u(self):
...: super()()
...:
In [10]: V().u()
------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-10-c8ce57f13006> in <module>
----> 1 V().u()
<ipython-input-9-a13c917bc4ad> in u(self)
1 class V(U):
2 def u(self):
----> 3 super()()
4
TypeError: 'super' object is not callable
oh weird, so super is just a proxy
Reposting a question from #c-extensions here:
How do I assert that an object has a
__call__()that takes a certain number of arguments?
@misty oxide
So far as I know, there's not any great way to do this that works for all types of callables (bound methods, things taking *args, etc), and normally you just have to call the thing and see if it works. Anybody know of better ways?
You could technically inspect the method's __code__ attribute and check the amount of args, but *args definitely do throw a curveball in, yeah
I'd just go with try-except
I think it's easier to check in C code than in Python code tbh
i mean doing it in python could just be done with inspect no?
inspect.signature could work IG
just a joke I wanted to share with you folks and a curiosity: is true immutability possible? or only with like, C extensions?
You could use the same ways to go around other ways of implementing it that you can use for current immutable builtins
Even C extensions don't give true immutability - users can still (ab)use ctypes to modify immutable data.
C also cannot really enforce immutability. It just calls it UB when you break it, but it can be broken
yeah. A tuple is immutable, but a tuple is implemented as an array of PyObject* pointers in writable memory. If someone overwrites one of those pointers, the tuple contains different items. And ctypes gives you the tools to do so, in pure Python code. You can even change things like the values of the cached integer constants.
Yea nothing in python can be truly immutable
Does anyone mind giving an example of how you can use ctypes to modify immutable objects? Seems interesting
depends on the immutable object
Does anyone mind giving an example of how you can use ctypes to modify immutable objects? Seems interesting
@unkempt rock well into undefined behavior, but here:
!e ```py
import ctypes
obj = b"foo"
print(obj)
ctypes.memmove(id(obj) + 32, b"bar", 3)
print(obj)
@raven ridge :white_check_mark: Your eval job has completed with return code 0.
001 | b'foo'
002 | b'bar'
byte strings are immutable, but ctypes lets me mutate it anyway.
that relies on several different CPython implementation details, so, ya know, don't actually do that, heh
Interesting, thanks
what stops objects from having arbitrary attributes?
I've noticed if I create an object(), I can't assign attributes, but I can with my own types class Test: pass
In [1]: a = object()
In [2]: a.a = 5
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-2-17f85e12aec5> in <module>
----> 1 a.a = 5
AttributeError: 'object' object has no attribute 'a'
In [3]: class Test: pass
In [4]: t = Test(); t.a = 5
In [5]: t.a
Out[5]: 5
"A Python-List is an object that contains multiple data items, you are expected to use the proper list functions to do the following activity.
Design a python application that prompts the user three times for three number values (integer or float) one by one. The application prints these three values and finally uses list functions to find and print the maximum and the minimum of these number values.
Please run the program three times and change the order of the integer values you enter such that the maximum number you enter is at different position at each execution.
Please upload your python source code and a screen-shots of your three executions." one my assignment canvas show the coding
"A Python-List is an object that contains multiple data items, you are expected to use the proper list functions to do the following activity.
Design a python application that prompts the user three times for three number values (integer or float) one by one. The application prints these three values and finally uses list functions to find and print the maximum and the minimum of these number values.
Please run the program three times and change the order of the integer values you enter such that the maximum number you enter is at different position at each execution.
Please upload your python source code and a screen-shots of your three executions." one my assignment canvas show the coding
@torpid pollen hi, I don’t mean to be rude, but:
- do you seriously expect someone to do your assignment for you?
- and that, without showing any work you’ve already done?
- this is a channel for discussion of the language. please read the description before indiscriminately spamming.
- try #❓|how-to-get-help.
Question: What does sys.audit do?
I read the docs and it says "Raise an auditing event and trigger any active auditing hooks"
I guess my question is what audits are for? I'm not quite familiar with that terminology
I guess my question is what audits are for? I'm not quite familiar with that terminology
@fresh cargo you mean what they are, or what they're for?
Maybe both. I'm just not familiar with what auditing is
Maybe both. I'm just not familiar with what auditing is
@fresh cargo basically...
you can register a function to be called when "certain things" happen.
"certain things" <- auditing events
"function to be called" <- auditing hook
why? for debugging, to do some advanced stuff, etc.
Some event-driven programming stuff?
sys.audit(event, *args)```
Raise an auditing event and trigger any active auditing hooks. *event* is a string identifying the event, and *args* may contain optional arguments with more information about the event. The number and types of arguments for a given event are considered a public and stable API and should not be modified between releases.
For example, one auditing event is named `os.chdir`. This event has one argument called *path* that will contain the requested new working directory.
[`sys.audit()`](#sys.audit "sys.audit") will call the existing auditing hooks, passing the event name and arguments, and will re-raise the first exception from any hook. In general, if an exception is raised, it should not be handled and the process should be terminated as quickly as possible. This allows hook implementations to decide how to respond to particular events: they can merely log the event or abort the operation by raising an exception.... [read more](https://docs.python.org/3/library/sys.html#sys.audit)
it's referring to OS events, I believe.
I think sys.audit is closely related to the Audits event table
Can I add events I want to audit or I'm limited to the ones in the table?
maybe...half?
It's there for testing, logging etc. as mentioned https://www.python.org/dev/peps/pep-0578/
A few nights ago in voice, someone seemed to be making the argument that Python's use of third-party libraries is a weakness. I'm not sure if they were arguing that the language itself should have more functionality out of the box or if people should implement everything they need from the ground up or what. Do we have any idea what point they may have been trying to make?
if I had to guess, too many libraries = too much foreign code in your project
I would guess the latter?
I think Rust learned from what Python did and only brought the core into std while leaving the crates ecosystem to thrive instead
Basically you end up with a lot of dependencies, which, outside the bigger third-party libs could become deprecated/unmaintained at any point
I think most of the stdlib is unmaintained 🤷
but at least the python org owns it
so I see the pro in that
It's a choice between doing it yourself or bringing in a third party module, which only helps as you still have the choice; and the amount of libs is one of the main upsides of the language
A few nights ago in voice, someone seemed to be making the argument that Python's use of third-party libraries is a weakness. I'm not sure if they were arguing that the language itself should have more functionality out of the box or if people should implement everything they need from the ground up or what. Do we have any idea what point they may have been trying to make?
@boreal umbra I think the stdlib already has a ton of functionality
too much, in fact
there are only like two packages I always bring into my project and they're pytest / ipython
so I would be surprised if that was the argument
I usually try to temper whether I need a dependency that might be in the stdlib since it has so much
Some older modules will probably be taken out of the stdlib, not sure what the state of the PEP is now
it was pretty controversial
@gleaming rover I don't really know what most stdlib packages are. Most of the ones that I regularly use are ones that I think of as an extension of the builtins, like itertools and pathlib.
it was pretty controversial
@desert peak I assume the argument was "muh batteries"?
I can't really think of a language with a vaster stdlib than python, maybe java SE.
the argument was the python organization took over some public projects and was now getting rid of that code without a community replacement @boreal umbra
!pep 594
do we really need wave?
!docs wave
Source code: Lib/wave.py
The wave module provides a convenient interface to the WAV sound format. It does not support compression/decompression, but it does support mono/stereo.
The wave module defines the following function and exception:
I could cope without it, but that stuff isn't me
It was opted to keep since you can teach it to beginners, similar to turtle
right, but python's thing is general purpose so there are people who do everything
Which sounds super cool tbh
Looks like it has been a while and may need someone to revive the pep
it's still talked about on the discourse
Learning environments are commonly restricted
the problem is - who maintains it once it leaves the stdlib?
the same person
do they move it to gitlab? github? who takes ownership of the code and package on pip?
who normally maintains it
good luck 🤷
like the starting point is - should this be kept in the stdlib?
and if it's not...
if it's important enough, someone will pick it up or create an alternative
core-js is pretty important to the js ecosystem, but there's no one lining up to take ownership of it.
without financial incentive, a lot of open source just dies
it's naïve to think otherwise
no
do we really need
wave?
yes.
beyond https://www.python.org/dev/peps/pep-0299/ , anyone know of any other PEP that tries to improve the if __name__ == '__main__' stuff? Was thinking of writing up a small proposal (basically if __is_entrypoint__ or something) but wanted to figure out any past discussion first to avoid treading the same ground
what would you solve @forest pawn ?
personally, I forget the incantation (is it __name__ or is it __file__ for example) and I think that from a pedagogical perspective it's simpler to have a boolean for this check instead of the __name__ mangling.
I also think doing something like this would pave the way for removing the mangling in .... 5-10 years or whenever but maybe that's asking too much
pyproject has been stable for a while and still doesn't see any use
We already have entrypoints for packages too
entrypoints generated exes usually get flagged as malware for me
And __is_entrypoint__ implies that wherever that is true should be an entrypoint
i.e. how/where do you define the value of it?
anybody here know how to make twitter bot
Wrong channel
Yes. This is not a help channel
😇
it wouldn't be unreasonable to have an implicit py globals()["__main__"] = globals()["__name__"] == "__main__" That would let you shorten: py if __name__ == "__main__": To just: ```py
if main:
__is_entrypoint__ is probably the wrong name given entrypoints, but basically "a bool that replaces __name__ == "__main__"
why not just have a __main__ dunder?
yeah, that's what I was proposing: to define __main__ to be the result of evaluating __name__ == "__main__"
But why is __name__ == "__main__" so bad?
Especially if all you're doing is aliasing it like @raven ridge did
is __name__ used for anything else?
Internally you mean? I've used it in a extensible CLI thing I wrote
more accurately
But why is
__name__ == "__main__"so bad?
@safe hedge It's not that it's bad, it's that it's hard to remember unless you know Python's data model pretty well.
how often do you use __name__ for anything but if __name__ == '__main__' (and getLogger(__name__) I guess)?
@safe hedge It's not that it's bad, it's that it's hard to remember unless you know Python's data model pretty well.
@raven ridge agreed. it's quite counterintuitive
@safe hedge It's not that it's bad, it's that it's hard to remember unless you know Python's data model pretty well.
@raven ridge Is it? Feels like one of those things which isn't obvious at first but after adding it to about 4/5 scripts its burned in your mind
Is remembering __name__ == "__main__" really massively more difficult than __main__ ?
is it?
From what I've heard, yes. I've seen people writeif "__name__" == "__main__"before, andif __name__ == __main__, and both of those are badly wrong.
Also would having __main__ cause problems with the having __main__.py be the entrypoint when you do python -m module?
No, I don't think it would.
Since I assume there is something like import __main__ going on
import __main__ would still work. has to still work.
And then you've immediately masked the __main__ variable though...
if you assign it to that namespace, sure.
to understand why if __name__ == "__main__" works, you need to know a few non-obvious facts:
__name__is a magic global variable that stores the name that the current module was implemented with- For the first module that the interpreter started running, it's instead set to the string
"__main__"
That's a fair amount of magic needed in order to do something that sounds relatively simple: do something only when run as a script, and not when imported.
and it's pretty hard to remember that if you can't contextualize it. (I've also seen people try "if __name__ == "main" now that I think of it...)
Or you just learn anything inside if __name__ == "__main__": runs when the script is called directly
Which is how I learned
I feel like you only make those mistakes one or two times whilst starting out
sure - this would be a thing that lowers the learning curve for people who are starting out. One less completely opaque magic incantation that doesn't make any sense and which they can't put in context.
I guess the question is how much of why do you need to understand to grasp what something does
the question shouldn't be "is if __name__ == "__main__" hard to remember", it should be "is it hard to learn". I'd argue that it is.
Are they not really the same thing here though
consider also that
most people don't encounter dunder anything
until classes
and it looks weird af
The barrier to using them is "can you remember it and what it does"
even more so to someone who's new
You literally don't have to understand the how to implement it
which adds to the confusion of if __name__ == '__main__'
The barrier to using them is "can you remember it and what it does"
OK, let's take that as the barrier - can we agree thatif __main__would be easier to remember thanif __name__ == "__main__"?
Erm. Maybe? It's like 12 extra chars though
yes - weird characters, with strange punctuation, that is hard to remember devoid of the context.
Maybe it's the way I learn, but I just committed it to memory through use long before I understood what it was doing
So the concept was irrelevant
I'm not sure thats a fair comparison
it's not, not exactly
but the points I want to make are:
- syntax matters
- sometimes it's not a question of "why?", but "why not?"
I just don't think an __main__ is all that much clearer honestly
I'm not sure thats a fair comparison
@safe hedge well, there is a fair comparison there, actually. What if you needed to calliter()on the iterable yourself, instead offordoing it implicitly?
for does that for you. People who know Python know that. It's only 6 extra characters.
I just don't think an
__main__is all that much clearer honestly
@safe hedge I do think it is.
Like how does __main__ convey that it's true if the script is run directly
"if this is the main program (the script is being run, as opposed to being imported)"
okay
get ready for a mega radical proposal
WHAT IF
it was if main()
Haha
that would break quite a lot of backwards compatibility.
I nearly said why not make it a non-dunder
yup but let's just say
hypothetically backward compatibility issues aren't present
would that be nice?
if mainModule
if (mainModule) {
as far as I can see... A new variable that covers the most common case is entirely backwards compatible, as long as it's allowed to be reassigned. It's certainly more memorable (14 fewer characters to memorize!), and it'd be easy to implement.
if you did do import __main__, the __main__ global variable would be overwritten, but that's what you expect and want, so... 🤷
arguably the real problem here is that this is an advanced thing that people should rarely need to do. You need if __name__ == "__main__" in the case where you want a single file to both be importable as a module and runnable as a script, and do different things in each of those cases. That's not actually a very common need, and people overuse if __name__ == "__main__" in places where they don't actually need it
That is a fair assessment
The problem with the existing comparison, beyond “longer” (which I don’t think is a strong argument) is that somehow the “did I point python directly to this file to run it” question is answered by “did Python decide to mangle the name atttibute”.
Now name is sometimes used for logging but otherwise it’s one of those “advanced python” things that small scripts aren’t really messing with. And on top of that the name behavior in general fails the “don’t do magical stuff if you can avoid it” test.
So there’s both a sort a semantically weirdness of doing X to figure out Y instead of just being provided Y, and it had infected a global with some odd behavior
Buuuuut I recognize there’s both a lot of inertia and it’s not the biggest issue, so I’m not super tempted to introduce something comtroversial for such a marginal gain. Just feels like not how things would be tackled if this were happening today.
it's worth a thread on python-ideas, I think. __main__ = __name__ == "__main__" would be, as far as I can tell, completely backwards compatible and pretty trivial to implement.
it might get some inertia if it's proposed.
it's definitely less invasive than the change PEP 299 proposed.
and yeah - there's inertia for what exists today, but the proposal wouldn't make the old way stop working - it'd just introduce a new, simpler way. Not unlike what happened for super()
is it not a common need? I feel like there're little tests I put at the bottom of a lot of my files meant for imports
i'm pretty sure i even put if __name__ == in files called __main__ because of the habit of it
I feel like there're little tests I put at the bottom of a lot of my files meant for imports
I'd sooner recommendpytestordoctestto someone who isn't already in that habit.
i don't know what that is and i don't want to do more than little tests at the bottom of my file
blink
i feel like i'm already doing the simplest thing possible
how is it equally simple if i need to learn another module
and they just put the test at the bottom of the file in the example anyway
there's not much to learn. For the most part, you can copy-paste from repls into your docstrings, and those become tests.
and they just put the test at the bottom of the file in the example anyway
@deft pagoda true - but you don't need to, you can also run doctest from the command line, withpython -m doctest
small tests at the bottom of an importable module is fine, in simple cases. It doesn't scale very well, though. Like, you can't easily hook it into a CI system that runs all of your tests and lets you know if a change breaks any of them. You can't easily run all the tests across an entire package.
And it isn't what I'd recommend people do, since it's not really any easier to get started with than pytest is, and it eventually hits a scaling problem. Though it does work OK up until you hit the point of multi-module packages.
pytest, in a nutshell, is just: you write a file called test_foo.py, you put a function called def test_something() in it, and inside of that you make whatever assertions you want to make using assert. You run it with pytest test_foo.py, or pytest . to run all test_*.py in the current directory.
if you have a couple different tests you want to run, you have multiple def test_something_else() functions.
pytest isn't built into the stdlib like doctest and unittest are - but pytest is lighter weight and easier to start with than unittest, IMHO
my tests are different than that --- like running a toy kivy app with only the widget implemented in the file
so you don't mean automated testing, you mean a manual, interactive test.
ok. in that case, __name__ == ... is reasonable enough.
(you threw me because that isn't what I would call a test, but I'm with you that that's a reasonable use of checking __name__)
there's this weird operator in ponylang .> that I've never seen before --- it calls a method of a class then returns the class as in:
my_dog = Dog() .> bark()
i wonder if there's ever been a similar operator proposed for python
@deft pagoda so bark is only being called for it's side effects?
that does sound a lot like bark should just be a part of the constructor somewhere
yeah, but you could do other things with .>
like:
class MySet:
def copy_add(self, item):
"""Return a new copy of self with item added to it."""
return self.copy() .> add(item)
you can sort of do this with := ie ```py
(my_dog := Dog()).bark()
yeah, it's just a small convenience, i thought it was a neat operator in any case
The problem with the existing comparison, beyond “longer” (which I don’t think is a strong argument) is that somehow the “did I point python directly to this file to run it” question is answered by “did Python decide to mangle the name atttibute”.
Now name is sometimes used for logging but otherwise it’s one of those “advanced python” things that small scripts aren’t really messing with. And on top of that the name behavior in general fails the “don’t do magical stuff if you can avoid it” test.
So there’s both a sort a semantically weirdness of doing X to figure out Y instead of just being provided Y, and it had infected a global with some odd behavior
@forest pawn your issue seems to be with Python setting__name__to“__main__”but i don’t think that is changing anytime soon so all this just obfuscates that fact further
And as @raven ridge pointed out if a script is small-time enough to where the person writing it is unfamiliar with the __name__ principles then they probably don’t really need the behaviour, since it’s meant mainly for code that can be run as a module or a script
I've just sent a message to python-ideas proposing it. We'll see what people think.
any django experts?
@raven ridge self doxed
lol whoops. I don't follow the mailing list actively, heh
at some point, you stop caring about hiding your identity
a lot of online presence depends on your identity, especially in open source if you want to turn that into professional representation
I meant "whoops" about re-proposing something that has already been suggested. It's never been hard to tie me to my email address, or real name.
Doesn't worry or bother me.
Hell, my name is rare, it's probably not tough to find my IRL address.
I'll visit you 👀
Your pfp makes that so threatening 😂
something that inspired the "stop caring about being anonymous" to me is that usernames are hard to come up with and remember and others can steal them from you depending on the platform (I'm getting old)
I try not to be an asshole online. Hopefully I'm more likely to get beer in the mail than a bomb. 🤷♂️
twitter was a mistake for mankind. I agree with your sentiment
what was the feature you proposed anyways? I missed the context
Something else than __name__ == '__main__'
ah
<@&267629731250176001>
!tempban @brisk mantle 14d posting NSFW off-topic gifs
:x: According to my records, this user already has a ban infraction. See infraction #19029.
time for that pban
!p 448
So, how does PEP 448 work?
How does dictionary unpacking work and why do we need it?
Sounds a bit complicated in my opinion
It seems as if we are merging dictionaries
something very common is that you get a dict like
{'name': 'John Doe', 'age': 21, 'height': 163}
```, and you want to get the 3 things out of it into separate variables
unpacking makes that a lot easier.
It's just that it seems to look like it merges dictionaries or seems too hard to notice when reading the code the first time
Difficult to understand the syntax
This was an issue mentioned in the PEP
https://www.python.org/dev/peps/pep-0448/#rationale the rationale provides the why
oh wait, that is a different PEP. don't mind me
So, they picked this syntax to prevent line noise which affects readability drastically
yeah, it's much easier to unpack things now
Hmmm, I see
can someone help me with this code
it says invalid syntax and i dont know what is wrong with it
simple
@knotty sequoia this channel is not for help, read #❓|how-to-get-help
@knotty sequoia u didnt insert colon after if statement
Just a thing that happened, might apply here, Guido works for MSFT now
woah
Hey people not sure if this is the right channel for this.
Do you use dotenv to manage environment secrets? Or do you use something else?
@prisma cypress try asking in #cybersecurity
ty ty.
with python 2 being EOL finally, does tox provide much benefit anymore?
From the perspective of a library maintainer, indeed! Python 3.6, 3.7, 3.8 and 3.9 have still some differences. Especially if you are used to work with the latest version in the matrix, you might sometimes forget to give up from certain habits.
I'd suspect you just stick to a specific version when developing the library
While doing changes, I test with the version that is installed in my environment. After the suite passes, I'll just execute tox to verify it works on all 4 versions (and pypy).
does tox handle the version installation and such or do you need to set up your environment yourself?
No, AFAIK it uses virtualenv under the hood so that you'd need have the environments in your system already.
How does that workflow look? You have 4 envs for a single package, and each one has a different python version?
Yes.
But it was rejected
@undone hare Can I ask why?
https://mail.python.org/archives/list/python-ideas@python.org/thread/CUNE3Y2YSQQSTXFITSXKFRVPO6EM2DV7/ is the thread for this time around
@desert peak why would tox be obsolete just because you don't use python 2?
because I have yet to see any breaking changes in supported versions of Python @spark magnet
so the thought would be, just use the oldest supported version and only use that for development of your package
@desert peak i guess that could be a strategy. it's safer to run on many versions.
You might want to test on pypy, for example.
shouldn't pypy/cpython be equivalent?
like, they have a spec, and they implement that spec equally
I have no idea what defines Python now that I think about it
if we're talking about the base language (no stdlib), there surely isn't that much to it, right?
it depends how detailed you want to get. PyPy closes files at different times, for example.
for coverage.py, the versions make a huge difference.
side-note: I was looking into why I use pytest-cov and I remembered; generating a bunch of different reports with coverage alone is a PITA
What is the pain? You run a number of commands.
for the purpose of sonarqube consumption, I'd have to invocate coverage some 3-4 different times
why is that hard?
tossing that into a config file is much easier
it's not hard, but it's more places I have to look to ensure my configuration is right
i don't understand. we have .sh, Make, tox, etc, for running commands. why cram it into pytest?
I like having a centralized place to look at config
because my environment sucks. I develop on a windows 7 box with py38 while my pipeline & runtime are py37 on RHEL, and then on Ubuntu
sounds like tox would be mighty handy....
no, you hav to have those installed
yeah, that's my first non-starter
I'd have to go through a multi-month procurement cycle and hope the other team responsible is engaged
avoiding tox won't get you the python versions.
plus theres a bunch of breaking changes even between "minor" versions
@desert peak how do you get python versions now?
why semver is better
@spark magnet we have a software store that deploys whatever is supported through SCCM. For Linux? pray that the greybeards actually packaged something
ok, so you have python versions. How is that a tox dealbreaker?
i get the feeling there's a tox misconception here
because I can only pick one python version for my pipeline
ok. where's the problem?
I guess I'm not sure what problem you see I have that tox would solve
you said you didn't want to deal with multiple commands. tox.ini can be the place to put those commands.
@spark magnet so does it take your list of envs and run the list of commands against each environment?
that's the simplest form of execution, yes. it's very configurable.
why semver is better
@sacred yew 🤷 If Python used semver, it would just use a new major version on every release instead of a new minor version. The issue isn't the versioning system, it's the decision to allow breaking changes on any release.
anyone wanna talk about something
im bored
also i need 7 more messages to get voice verified
anyone wanna talk about something
@unkempt rock I hope it's related to the language
because this is a channel for language discussion
it's literally in the channel description.
also i need 7 more messages to get voice verified
@unkempt rock I believe it's also against the rules to send messages for the sake of having more messages so you get verified...which kind of looks like what you're doing right now.
!ot
Off-topic channels
There are three off-topic channels:
• #ot0-psvm’s-eternal-disapproval
• #ot1-perplexing-regexing
• #ot2-never-nester’s-nightmare
Their names change randomly every 24 hours, but you can always find them under the OFF-TOPIC/GENERAL category in the channel list.
oh
just my two cents
well i mean im also trying to actually have a convo
im not just typing to have messages
i was just throwing that out there incase anyone wanted to vc
sure, go ahead, but not here...because as I said, this channel is for discussion of the Python language...
i swear that one time someone showed me a trick about expanding arguments to set a few variables.. something like
var1, *, var2 = *something that has more than 3 return values
and it worked somehow, but i cant get it to now :\
anyone know?
@compact scarab i assume you want to throw away the inner values?
yep exactly
var1, *_, var2 = something
oh snap thats the syntax? 👀
it places all of the inner values into _
oops, meant to ctrl k
dope, worked! thank you @pliant tusk
no prob
@safe hedge sorry for my late reply, but here is the thread https://discuss.python.org/t/add-an-imported-flag-to-avoid-the-use-of-name-main/4141
It boiled down to two things : the __main__ module is actually imported so this flag wouldn't make sense, and if you want to keep retro compatibility in your code you'll have to write something even longer to integrate the new flag
Ok yeah that got shot down pretty sharpish
The main module is imported (under the name
__main__, precisely).
This seems key I guess
Yeah, they made pretty fair arguments honestly
I don't find either of those arguments terribly compelling. One was merely about the name of the flag, rather than its worth, and the other is a valid argument against ever introducing any feature that simplifies something that is already possible.
Yes, there will be a period where the new feature is not ubiquitously supported and you'll need to avoid using it in code intended to be portable for older interpreters. Just like f-strings, and async def coroutines, and data classes, and the walrus operator, and positional only arguments...
@unkempt rock You could try it in #bot-commands. If you think you've found something that you probably shouldn't be able to, please do get in touch. We won't be mad if you find something, although do be a considerate in actually exploiting it.
hello !
hello
hello
I started to dislike the look of 'bare returns'. Just not dealing with them, I do my best to avoid early exits (even that means I have to indent redundantly a couple of levels). At worst, I'd go with return None. Does anyone have a similiar (or counter) opinions on this?
I usually go with return None, but don't really go out of my way to avoid early exits
if the function normally returns a value, then i usually go with return None
otherwise just return
I think you should consider readability. I don't mind "bare" returns myself and I think that it sometimes very clearly follows the logic of a function, which makes it a logical and readable part of the routine logic.
However, I forgot the name (structured programming?) states that a function should only have one return and it should be at the end of the function
By the way, what I mean by 'avoiding early returns' is writing the first one as the second one;
def some_func(item):
if not isinstance(item):
return
result = do_something(item)
if not result.flag | other:
return
for item in result:
print(item)
def some_func(item):
if isinstance(item):
result = do_something(item)
if result.flag | other:
for item in result:
print(item)
I like the first one more than the second one
I feel like you need to do a lot of gymnastics just to get that only (implicit) return at the end of your function
High cyclomatic complexity
This specific example isn't to bad, but this function is relatively short
I feel like you need to do a lot of gymnastics just to get that only (implicit) return at the end of your function
@wide shuttle Unfortunately, yes. It gets more and more complex when forcefully gather everything under a roof of a single branch.
I like the "if the input is not this, we can stop, no need to scan the function for a maybe use somewhere"
I find myself using early returns more and more
I strongly prefer it to deep indentation
Yes
Can i share github project link here?
@hasty portal not in this particular channel. You can talk about your projects in relevant topical channels, but reddit is probably a better platform because discussion isn't limited to who sees a message before it's in scrollback territory.
Okay thanks
I started to dislike the look of 'bare returns'. Just not dealing with them, I do my best to avoid early exits (even that means I have to indent redundantly a couple of levels). At worst, I'd go with
return None. Does anyone have a similiar (or counter) opinions on this?
@true ridge those are called guard clauses I believe
and well like if you look at functional languages there basically aren’t even return statements
which I am actually quite a fan of
knowing a function’s return value is always at the end adds value
Yeah, and actualy can be quite useful for keeping the function lineer.
and I do things in Python like use if expressions in place of if statements
to achieve “one return”
that said
there are syntactic constructs that are just missing
Like a special exception (Release) raised if the guard fails ensure isinstance(a, int) that would pop out from the current context and switch the upper one on the stack
to achieve that effect as easily as you can in other languages
for example, pattern matching expressions
or an explicit option type
well, there is an option type --None vs not None, it's just that there aren't any built-in utilities for that
I optimize for readability. Sometimes early returns are more readable, sometimes less.
I think this:
def abs(x: int) -> int:
if x >= 0:
return x
else:
return -x
``` makes more sense than this:
```py
def abs(x: int) -> int:
if x >= 0:
return x
return -x
because the two branches are 'equally likely', or rather none of them is more special than the other
unlike here (contrived example):
def filter(iterable, fn=None):
if fn is None:
return fn(iterable, bool)
result = []
for x in iterable:
if fn(x):
result.append(x)
return result
``` or maybe even:
```py
def filter(iterable, fn=None):
if fn is None:
yield from fn(iterable, bool)
return
for x in iterable:
if fn(x):
yield x
but it's kind of vague
well, there is an option type --
Nonevs notNone, it's just that there aren't any built-in utilities for that
@grave jolt it's not explicit
just like a function that returns String in Java really means "returns String or null"
Optional[T] is pretty explicit to me 🙂
like there is no distinction between T and Optional[T]
Optional[T]is pretty explicit to me 🙂
@grave jolt yes, that's my point
Optional[T] isn't actually a thing beyond T | None
like there is no distinction between T and
Optional[T]
there is, a typechecker (if configured correctly) will yell at you if you assume that anOptionalis notNone
yes, there is
but what I'm saying is more like
it's just an untagged union type (as opposed to a sum type)
@unkempt rock This is not a help channel, this is a discussion channel. See #❓|how-to-get-help
That.. is a funny error though especially if it is a professional library
@final scroll We don't allow advertising on this server. You can share your article if it's relevant to a particular discussion (e.g. when someone wants to know how decorators work (although there's already a good article on realpython.com, not sure if more are needed)), but don't just dump links to your resources here.
Sure
@echo harness your proposed syntax restricts functionality because for any (f on someSeq), there has to be a method f.__call__ that does exactly what is wanted. Whereas the status quo lets you do any expression.
I don't really like the look of (x for x in y if f(x)), but you have filter for that.
^
list(map(f, iterable))
[f on iterable]
list(filter(f, iterable))
(_ on iterable if f)
not that much of a difference IMO
I do think it's more readable in the map case
but not really sure if it's worth the tradeoff (new syntax)
and in the filter case...that changes the meaning of if
because there's implicit function application
what does | this syntax mean in python?
it is a bitwise opperator, means 'or'
if x>y | a>b :
would read as if either x is greater than y or a is greater than b
Oh i see
n
That happens to work, but using bitwise operators for truth testing is unusual and can lead to bugs.
don't use bitwise for that
bitwise ops are for operations based on bits
@mint forge @inner acorn
bitwise or means for each bit, take the or of the 2 corresponding bits of the 2 operands
if x>y | a>b :
would read as if either x is greater than y or a is greater than b
@inner acorn Shouldn't that evaluate tox > (y|a) and (y|a) > b?
for instance (0b100 | 0b010) == 0b110
same thing for bitwise and, not and xor
plus bitwise ops have really weird operator precedence
wait what?
@inner acorn Shouldn't that evaluate to
x > (y|a) and (y|a) > b?
@radiant garden ah, yes it would. Like I said, leads to bugs 😄
use logical or/and for bools
ik, i wont use that but like what does that mean in python?
or?
You know how logical and/or applies to "single bits"?
@sacred yew i do not
wdym by "single bits"?
0s and 1s
oh
binary
so true or false
is 1 or 0
and the result is always a single bit(assuming all bools)
I see, but how does that relate with my main questions?
!e ```python
print(3|7)
print(3&7)
@raven ridge :white_check_mark: Your eval job has completed with return code 0.
001 | 7
002 | 3
So:
7 in binary is 111
3 in binary is 011
| finds the number where anything that's 1 in either is 1 in the result. So 111, 7.
& finds the number where anything that's 0 in either is 0 in the result. So, 011, 3
by doing an or for each bit in a number's binary representation
@raven ridge :white_check_mark: Your eval job has completed with return code 0.
001 | 14
002 | 8
@raven ridge how do u know what they are in binary?
bin(7)
you can count it out
That's because:
12 is 1100 in binary
8 is 1010 in binary
| finds the number where anything that's 1 in either is 1 in the result. So, 1110, 14
& finds the number where anything that's 0 in either is 0 in the result. So, 1000, 8
hmmm
In base 10, the system you're used to, a number like 623 means "three and two tens and 6 hundreds"
In binary, a number like "1110" means "zero and one two and one four and one eight"
and 2 + 4 + 8 is 14, so 1110 in base 2 is 14 in base 10
so for 7:
4 2 1
1 1 1
4+2+1=7
for 3:
4 2 1
0 1 1
2+1=3
tbh bitwise ops aren't used that commonly now
how about the square root function from doom though
since you can use a set to represent flags
they're used commonly in some areas, but not everywhere.
I think I've only used them for some crypto and bitwise flags
Yeah. The place you're most likely to see them is crypto and implementation of network protocols or manual serialization.
Discord uses it for their permissions system
aka the only places where bits matter anymore
another common application
yeah bitwise flags
It really sucks that they have such an awful operator precedence
thanks to c
that doesn't actually use any bitwise ops per se. I guess i >> 2 but that's just a way of writing i / 2 for stupid compilers
is it not a cheaper way of doing it?
not with a modern optimizing compiler, no
ik the article mentions how it truncates the remainder, idk if that's important or not
there's too many parenthesises in the text to tell
https://godbolt.org/z/Yrrxr9 - check out the assembly, the shr in the assembly is a right shift,
actually performing the shift doesn't call it tho?
that's got a sar operation instead, which is... also a right shift.
it's c
throwing -Og in the "Compiler options..." box in the top right gives nicer assembly output.
-0g made it fail
capital oh, not zero
smh
capital o is the optimization level flag, and g is "optimize for debugging"
regardless it still looks cheaper to do a right shift
there's a very high possibility idk what I'm talking about tho
ah, yes - because I had a bug there.
Check https://godbolt.org/z/7qb5oj instead.
/4 and >>2 generate exactly the same assembly. Likewise for /2 and >>1
(the bug the first time was using signed rather than unsigned integers)
we've wandered off topic, though - feel free to ping me in an OT channel if you'd like
I see now, I'll ping you when I have braincells to spare
Hi, I have some questions about the google colab, It is easy to run a Neural Network on colab with a TPU?
>> and << should only be used to perform multiplication and division of integers by 2. I mean you can do floats too buts a lot more tricky. There's a famous computation some guy did for a game where he performs a super fast 1/✓2 calculation for vectors by utilizing bit shifting and approximating it
@nocturne cloud hey, this is not the correct channel for your question. I think your question is more suited for an off-topic channel ( #ot0-psvm’s-eternal-disapproval , #ot1-perplexing-regexing , #ot2-never-nester’s-nightmare ) or , if it is related to python, in #data-science-and-ml I think
This channel is meant more for abstract discussion about python
I didn't see the channel sorry
this isn't a help channel, see #❓|how-to-get-help
although, i believe there is a word wrap option in format or something
Might also be a CRLF vs. LF issue - see https://en.wikipedia.org/wiki/Newline#Representation
judging by the top bar, it's windows 8 at least, the default notepad was capable of handling both CRLF and LF at that point IIRC
Hey all, I think my pyenv and settings are all messed up. I was wondering if I can run couple things by you guys.
I'm on osx, and it has its own python.
I tried not to use python installed from homebrew and instead do everything do pyenv.
But typing pip into command line shows something like
~ pip
pyenv: pip: command not found
Brew has python@3.8 and python@3.9 installed. I think other packages depend on it.
I think I figured it out. I think there's no pip installed with the system Python and by linking to it, there's no pip.
First of all: this is unrelated to the topic, reread the description
Second of all: Good job!
@raven ridge Sorry for the unnecessary ping, I was looking back at the code you wrote and saw that you did id(obj) + 32, and if I do it without 32 it doesn't work. Do you mind explaining why you did that?
@unkempt rock that's the offset, in bytes, of ob_sval inside https://github.com/python/cpython/blob/master/Include/cpython/bytesobject.h#L5-L15
(I told you, it depends on lots of fragile implementation details)
Ah, interesting. Is there any way for me to start learning about this stuff other than just reading source code?
It depends on CPython implementation details, so learning about the CPython C API is a good place to begin. https://docs.python.org/3/extending/index.html#extending-index
Thank you
note that, with the C API, under some specific scenarios, it's even allowable to modify a bytes object. https://docs.python.org/3/c-api/bytes.html#c.PyBytes_AsString says
The data must not be modified in any way, unless the object was just created using
PyBytes_FromStringAndSize(NULL, size).
Hi, I am not quite happy with the current state of timeit. Not allowing arguments for functions is something that really frustrates me. I would like to use timeit to make a quick check how performant my code is - especially with differing arguments - like testing different sorting algorithms for different sizes of an array. I have to make a workaround like this:
t = timeit.Timer(lambda: eratostones(limit))
or create a wrapper function just for a quick check on performance.
I would also like to have a median for fast functions - I know it is possible, but takes more time to set up
ipython's %timeit allows exactly for what I am asking. I can just write something like this:
%timeit sum(range(100))
>>>100000 loops, best of 3: 1.54 µs per loop
I ask myself why this is not used in pythons timeit - or if there may be a module that provides this functionality (not the % line magic, but something that is just shorter)
The command-line module is more useful for something like this. python3 -m timeit
within your code, timeit.timeit(str/callable) also works
you can pass in globals iirc
doesnt work with args
globals={"limit":limit} to the fn call
you've got to pass everything from the external scope in manually
Or just: globals=globals()
thats what I mean - it is possible, but I have to manually write extra code just for testing it with timeit
with ipython, I have my function that I could use in a prod environment, write %timeit in front of it and get the runtime
yeah no luck with that ig
like, I made it callable with "wrapping it" in a lambda, but I still pollute the output.
Maybe a mistake on my side, but I dont know how to fix it.
https://hasteb.in/doyaziza.py
ipythons timeit just seems superior to me. I wonder if that is the case or if I am missing something crucial. Or it might just be superior.
how often does this whole library get used? https://pymotw.com/3/ I barely learned the function of random a few days ago.
you mean the entire stdlib?
whose official docs are https://docs.python.org/3/library/ btw
yeah. my mind is blown. I have endless hours of information to read on. this is going to take more than 300 hours to master.
Ehh, more like months
Ehh, more like months
@unkempt rock seriously. brb. lol.
trying to memorize the entire standard library isn't a great use of time. There's lots of things in it that are only useful in particular situations.
Start trying to build real programs, ask around for how other people would approach the problem, and learn the modules they point to.
trying to memorize the entire standard library isn't a great use of time. There's lots of things in it that are only useful in particular situations.
@raven ridge ah ok. thanks for the knowledge bomb!
?why?
You definitely do not need to memorize every function that exists, though I do find it both fun and informative to go through the module index every once in awhile to see whats available
difflib is a lesser known module, but really nice to have when you need it, for example
pathlib is way underutilized
I have code that I want to get reviewed. If there is a channel or if someone wants to review it, please tell me
#python-discussion not here
hi when i want to generate a key value pairs into empty discitnors as dicto['value2']['value2'] = 123 it gives key error it is a bug
@sweet peak see #❓|how-to-get-help , this is not the correct channel for that
it probably isnt a bug
We’re discussing the implementation and differences between == and is for strings. Above is the relevant source code for the string eq method
I think it looks like it’s comparing the data of the strings (after ruling out obviously false things) and not the actual memory address, when checking for equality. Is this actually what the implementation is? I heard that it might actually be checking if the objects are the same in memory, which doesn’t quite make sense to me
== would have to compare the data of the strings, as the memory address may be different even if they are the same
That’s what I had thought as well. Not sure why someone thought it would compare memory addresses
It could technically compare the address first, because if both operands reference the same string in memory, there's no need to actually compare them
memcmp(PyUnicode_1BYTE_DATA(a), PyUnicode_1BYTE_DATA(b),
PyUnicode_GET_LENGTH(a) * PyUnicode_KIND(a)) == 0;
I don’t know enough c to interpret this function, but doesn’t it sound like memcmp would be comparing the memory addresses? This is part of the code I linked above
It compares the contents, yeah
Yeah. It could do that. I’m mostly wondering about the current implementation
The current implementation doesn't seem to check whether or not they're the same string during equality comparison
You mean by checking the memory address?
It should all be in the file I linked
Unless I’m completely lost in navigating the CPython source code
The one I linked...?
no I'm just being slow, nvm
Hahah okay
I remember something about dictionaries that exclusively use interned strings for keys
CPython just checks the address in those cases IIRC
Perhaps that's what they were thinking about
Hmm... maybe
It seems it does check if they are at the same memory address first https://github.com/python/cpython/blob/master/Objects/unicodeobject.c#L11504
if (left == right) is comparing the pointers, and returns True if the op is case Py_EQ
Hmm.. interesting
So it basically does str1 is str2 before going into the entire “are the values the same?” route?
Makes sense, it's a cheap check that can save lots of time for long strings
Yep
If they aren't equal it goes on to the other check (the one you linked to)
else if (op == Py_EQ || op == Py_NE) {
result = unicode_compare_eq(left, right);
result ^= (op == Py_NE);
return PyBool_FromLong(result);
Yeah. It is very smart. As well as returning false directly if the string lengths aren’t equal
Aah, right. The check I linked starts off with doing a Unicode eq check
Hello folks. I am attempting to turn a modest for loop into a one liner (I can't use reduce):
dispose = set()
for index, item in enumerate(prosodies, 1):
if item in dispose:
return index
dispose.add(item)
@unkempt rock this isn’t a help channel. Feel free to ask in #❓|how-to-get-help
... which basically finds the index of the first duplicate in a sequence.
I got to this: next(filter(lambda enumeration: enumeration[1] in dispose, map(lambda x: dispose.add(x[1]), enumerate(prosodies, 1))))[0]
This might be better in #esoteric-python if you're trying to make a one liner
@unkempt rock this isn’t a help channel. Feel free to ask in #❓|how-to-get-help
@spark parcel Ok, sorry.
This might be better in #esoteric-python if you're trying to make a one liner
@sturdy timber Alright, I will knock at their door. The idea is to bring CC (cyclomatic complexity) down to 1 ... so without using for loops, list comprehensions, etc.
Hmm actually well if you want to make the code more efficient #esoteric-python might not be the right place, you could try #algos-and-data-structs or use the help system #❓|how-to-get-help @unkempt rock
Sorry for moving you around so much 😅. Asking in the right place should increase your chance of getting an answer though
@sturdy timber Thanks. I am not after efficiency in this case. Gains would be inconsequential. I am merely looking for an alternative syntax on one line, as I've done with other portions of my code. I'll ask the "esoteric" crowd.
@unkempt rock I'm pretty sure a giant one liner isn't going to reduce the complexity of the code.
maybe it will trick the CC calculation tool, but map(lambda x: dispose.add(x[1]), enumerate(prosodies, 1)) is no better, and maybe worse, than (dispose.add(x[1]) for x in enumerate(prosodies, 1))
Thanks @grave jolt, I actually got it in the end, although I am not satisfied:
dispose = set()
# horrible hack to remain within dipose's scope and feed the return value to the filter
def check_add(enumeration):
check = enumeration[1] in dispose
dispose.add(enumeration[1])
return check
return next(filter(check_add, enumerate(prosodies, 1)))[0]
I think this version was the best
def index_of_first_duplicate(prosodies):
dispose = set()
for index, item in enumerate(prosodies):
if item in dispose:
return index
dispose.add(item)
return None
Of course, I totally agree. But I have a long script whose CC I want to bring down to 1. So I am removing all loops, ifs, etc.
Self imposed exercise, to learn.
well, I think you'll only trick a CC computation tool -- I wouldn't say that a loop has more cyclomatic complexity than map with a side-effectful function
I mean, in Haskell there are no loops or if statements -- do Haskell programs all have CC of 1?
Yes. But not using loops forces me to get more familiar with functional styles, map, filter and the lot. I am using Radon to calculate CC.
oh, okay
Thanks though, @grave jolt.
I'm storing a NxN matrix in a file (2D list) and I need a way to rotate it by 90 degrees, i.e.:
from:
1 2 3 4
5 6 7 8
9 0 0 0
1 1 1 1
you'd get:
1 9 5 1
1 0 6 2
1 0 7 3
1 0 8 4
This could be easy if I just loaded the list into a python list and did something like: list(zip(*reversed(lst)))
Problem is that this 2D list is way too big to load it whole into memory so that's not possible.
The way I'm storing this list is basically in "blocks" in which the matrix is flat, each block containing certain amount of data (let's call this amount b), so basically for the example above, with block size of 2 the stored list would look like this: [1, 2], [3, 4], [5, 6], [7, 8], [9, 0], [0, 0], [1, 1], [1, 1]
I need some meaningful way to rotate this list without loading too many blocks into memory.
The storing works in a way where the amount of data each block can contain (b) is known and n (size of matrix) is also known and it will always be a multiple of b
I figured I could just go through these elements, get the block they're in, read it, get the element from that block, store it and get the block in which the corresponding element number (after rotation) would be. Then just swap those and write them back. Problem is that this would make way too many calls to write and read (2xN^2) calls to read and another (2xN^2) for write, which would be way too slow. Is there a more meaningful way to do this than just going through every element, finding the rotate pos and swapping it directly?
@radiant scroll I don't think this is the correct channel for that, try #algos-and-data-structs
alright, thanks
Not sure if this is supposed to be here, but if it isn't I'll move it somewhere else.
But how would you type ctypes?
For example:
from typing import Union
from ctypes import *
def func(*pointers: ...):
pass
I can't seem to find a way to make it generic
@unkempt rock you can probably get help in #esoteric-python, although it's not necessarily on topic there. You could just open a help channel
Ok, I see
say there's something like zip is there a way to inspect how it works? like the underlying programming for it?
For how the builtins work you'll have to look into the C source they're implemented in
The bytecode will only contain a call instruction
oh, yeah, that's right, in that case yeah, you will have to look into the actual cpython source (https://github.com/python/cpython)
i'm new to python. my intent here is to glance over something to get a better sense of the underlying logic of what i'm using.
so i used zip as an example. can you link to the file, subfolder, whatever, where i might find what i'm looking for at that repo? @deep bramble
well it's kind of hard since there isn't necessarely a specific place to look, but if you're looking for common objects, you could go here: https://github.com/python/cpython/tree/master/Objects which contains things like enumerate, or tuple objects
zip is a funciton iirc. is there not a location at which that is described?
Most of builtins will be in bltinmodule.c, the implementation for zip begins here https://github.com/python/cpython/blob/master/Python/bltinmodule.c#L2518
okay i'll explore that. so what i'm reading there isn't python. is that correct? it's some other language? @peak spoke
It's C
it's code of python itself, which is written in C
ah okay. maybe i should take a C crash course.
@violet jetty I would suggest to check this out at the first https://docs.python.org/3.9/library/functions.html#zip
A couple of functions (like zip, all, any etc.) have ~similiar python implementation at the docs, for people who intend to comprehend the underlying implementation
So im making a class with __add__ the thing is the other operand should be anything which can be added, so I can add it into my instance, how do I implement it? typing.SupportsFloat or should I use the abc in numbers i dont know
i would like to be able to do instance + 1 instance + 2.3 instance + decimal.Decimal('2.3') instance + fractions.Fraction(23, 10) for example
You should be able to just define a def __add__(self, arg)
yeah I can
but i need an abc for the NotImplemented part
What's the correct abc here
numbers.Number I'd assume
If you really mean "anything that can be added", https://mypy.readthedocs.io/en/stable/protocols.html#defining-subprotocols-and-subclassing-protocols to create your own SupportsAdd protocol.
str has __add__ but isn't a numbers.Number.
@noble mesa #web-development
Oh I only want numbers that can be added
Then numbers.Number sounds right.
Sorry for the image , but what is (*args) here
What not simply super().init()
( program is for creating a sequence of own where major features from type -list)
*args is a variadic number of positional arguments, collected into a tuple
^ you're initializing List with the args from init'ing CounterList
oh would that initialize a list with args as the items?
>>> def check(*args) -> None:
... print(args)
>>> check(0)
(0,)
>>> check(13, 42)
(13, 42)```
no
>>> def add(a: int, b: int) -> int:
... return a + b
>>> args = (13, 42)
>>> add(*args)
55``` `*` in the call is unpacking an iterable object
It's just there to act as a pass-through right
so in the end super().__init__(*args) will proceed to make CounterList(whatever) do list(whatever)
also I don’t think super(CounterList, self) is necessary and you could use just super() instead
that's what I mean, is there a redefinition of list, or will it do list(*args) -> [*args]?
what do you mean redefinition
I mean the parent class is list which is a builtin
__init__ of the list takes only one argument, an iterable object
and that’s what is called
built-in objects are no special in a sense of OOP, really
I've just never seen a builtin being called like that
super() may be list, but not necessarily.
I've just never seen a builtin being called like that
@signal tide So you used to be advised to use: https://docs.python.org/3.8/library/collections.html?highlight=userdict#userlist-objects but some changes were made and now it is less problematic to subclass some builtins
neat I'll have to play around with that
and besides, you can freely subclass builtins if you know the consequences that you’ll have
super() calls the next class in the MRO. When you're instantiating a CounterList, that will be list, but when you're instantiating a subclass of CounterList, the next thing to be called after CounterList.__init__ isn't necessarily list.__init__
super() gets compiled differently tho right
Because how does it know the class it is currently in
it's handled specially when the file is parsed
right
what if you overwrite the variable super?
does it still get modified or does it the parser check for that
that's handled.
Right, makes sense
!e ```python
super = 42
class C:
def init(self):
super().init()
C()
@raven ridge :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 5, in <module>
003 | File "<string>", line 4, in __init__
004 | TypeError: 'int' object is not callable
Actually - this is kinda interesting. PEP 3135 says:
While
superis not a reserved word, the parser recognizes the use ofsuperin a method definition and only passes in the__class__cell when this is found. Thus, calling a global alias ofsuperwithout arguments will not necessarily work.
looks like if you redefine super and try to call it with no arguments from a class body, it is passed the class, actually, @tawdry gulch
!e ```py
super = print
class C:
def init(self):
super()
C()
@raven ridge :warning: Your eval job has completed with return code 0.
[No output]
hm, and that behaved differently for me than it did for the bot!
In [7]: super = print
...: class C:
...: def __init__(self):
...: super()
...: C()
...:
Out[7]: <__main__.C at 0x7dd9643d5e10>
maybe, the bot isn't a repl
!e print()
@gleaming rover :warning: Your eval job has completed with return code 0.
[No output]