As far as I'm aware, every builtin object in Python has a docstring. Except, as I just found out today, None. Why is this?
None has no other function than to exist. It is one instance, not a type, while other built-ins are invariably callable or are instances of something that is.
Strings, numbers, booleans, etc. all have a callable type object, that often has specific conversion functionality as well (bool(), int(), str()). None doesn't; it's type doesn't produce anything because there is just the one instance:
>>> type(None)
<type 'NoneType'>
>>> type(None)()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot create 'NoneType' instances
None is not the only such object. Ellipsis and NotImplemented are other such objects:
>>> Ellipsis.__doc__ is None
True
>>> NotImplemented.__doc__ is None
True
>>> type(Ellipsis)()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot create 'ellipsis' instances
>>> type(NotImplemented)()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot create 'NotImplementedType' instances
They are all sentinels, objects that signal a specific state or value, but are not useful outside of that function.
As such, they may have meaning in how they are used, not how they are created. The correct place to document this is the Datamodel reference documentation, not in docstrings.
Related
I am a python beginner and was reading about dunder methods. Is it somehow possible to change the dunder methods of classes like int or str?
For instance, can I somehow change dunder method __add__ of int class to perform multiplication instead of addition? So if I type 3 + 4, output is 12?
You can subclass, but it's worth pointing out this is likely a bad idea since no-one reasonably expects add to perform multiplication:
class FunkyInt(int):
def __add__(self, other):
return FunkyInt(self * other)
f = FunkyInt(3)
print(f + 4)
# 12
My best guess would be that you can't (which is in line with this answer). I tried a couple of options and got the same error with in-built classes. As per Chris_Rands' answer, you can always create a Class inheriting from the in-built object in question.
>>> int.__add__ = int.__mul__
int.__add__ = int.__mul__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'int'
and
>>> dict.__add__ = list.__add__
dict.__add__ = list.__add__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'dict'
Looks like the error is not a syntax problem but more explicitly you can't redefine built-in methods.
In Python strings have a method lower():
>>> dir('A')
[... 'ljust', 'lower', 'lstrip', ...]
However, when one tries '{0.lower()}'.format('A'), the response states:
>>> '{0.lower()}'.format('A')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'lower()'
Can someone help me understand why the line above throws an AttributeError in this case? This seems like it should not be an AttributeError, though I must be mistaken. Any help understanding this would be very welcome!
Edit: I understand I can't call the lower() method inside the format call (though it'd be neat if that were possible); my question is why doing so throws an AttributeError. This error seems misleading in this case.
You can't call a method from within a format specification. Dot notation inside the format specifier is a way to look up attribute names and render their values, not to call functions.
0.lower() tries to look up an attribute on the string literally named "lower()" - the equivalent of getattr(some_string, 'lower()'). You need to call the method before formatting.
>>> '{0.lower()}'.format('A')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'lower()'
>>> '{0}'.format('A'.lower())
'a'
As others have said, you can't do this in a format expression. It would work in an f-string though:
a = "A"
print(f"{a.lower()}")
In python, how to iterator all types?
Like the image above, there are many types in python, but 'types' is not iterable.
Traceback (most recent call last):
File "D:\...\abc.py", line 189, in <module>
for t in types:
TypeError: 'module' object is not iterable
Is there any way to iterate the types without manually specify them?
Something I'm doing in PIL is giving me back an object of a class I don't recognize. It may be a fairly thin wrapper around a C data structure or something. How can I get Python to tell me where to look for more information?
Here are some failed attempts to use introspection to learn more:
>>> import os, PIL
>>> obj = PIL.Image.open(os.path.expanduser("~/Desktop/foo.png")).getdata()
>>> type(obj)
<type 'ImagingCore'>
>>> ImagingCore
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'ImagingCore' is not defined
>>> PIL.ImagingCore
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'ImagingCore'
>>> obj.__class__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: __class__
>>> obj.__module__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: __module__
>>> import inspect
>>> inspect.getsource(obj)
...
TypeError: <ImagingCore object at 0x105e64b50> is not a module, class, method, function, traceback, frame, or code object
>>> inspect.getsource(type(obj))
...TypeError: <module '__builtin__' (built-in)> is a built-in class
>>>
PIL's core functionality is implemented in module _imaging, written, as you guessed, in the C language -- see _imaging.c (3281 lines...:-) in the top level source directory, Imaging-1.1.7. That code doesn't pay any attention to introspection -- rather, it's 100% focused on performance. I believe it doesn't even bother to expose anything but functions (it does implement several types, including ImagingCore, but doesn't even expose those types' names to Python -- only generates and uses them internally).
So Python won't tell you where to look for more info because the library, in turn, doensn't tell Python:-). As the docs for getdata at http://effbot.org/imagingbook/image.htm says:
Note that the sequence object returned by this method is an internal
PIL data type, which only supports certain sequence operations,
including iteration and basic sequence access. To convert it to an
ordinary sequence (e.g. for printing), use list(im.getdata())
...and "that's all she wrote" -- nothing but that small subset of sequence operations gets exposed.
I am new to Python,
and have started working on code written by others.
In the source of packages downloaded from Pypi I have noticed the use of
import __module__
to use functions and classes defined in the src folder of packages.
Is this common practice? I actually can't really understand this kind of syntax,
could you explain it to me or send me to some reference?
It's a python convention for some builtin objects. From PEP8:
__double_leading_and_trailing_underscore__: "magic" objects or attributes that live in user-controlled namespaces. E.g. __init__, __import__ or __file__. Never invent such names; only use them as documented.
But in the end it is not a "kind of syntax" to understand or not, __module__ is just a name with underscores in it. It's different from and completely unrelated to module.
An example to show you it's just a name:
>>> __foo__ = 42
>>> print foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
>>> print _foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_foo' is not defined
>>> print __foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '__foo' is not defined
>>> print __foo__
42
>>> type(__foo__)
<type 'int'>
Nothing inherently special about it.
Without more info about where you saw this though, it's hard to say what the author's intention was. Either they are importing some python builtins (e.g. from __future__ import...) or they are ignoring PEP8 and just named some objects in this style because they think it looks cool or more important.