__repr__ vs repr - python

Is there a difference between the two methods?
For example,
from datetime import date
today = date(2012, 10, 13)
repr(today)
'datetime.date(2012, 10, 13);
today.__repr__()
'datetime.date(2012, 10, 13)'
They seem to do the same thing, but why would someone want to use the latter over the regular repr?

__repr__ method is used to implement custom result for repr(). It is used by repr(), str() (if __str__ is not defined). You shouldn't call __repr__ explicitly.
The difference is that repr() enforces the string as the returned type and repr() looks up __repr__ on a class object, not an instance itself:
>>>> class C(object):
.... def __repr__(self):
.... return 1 # invalid non-string value
....
>>>> c = C()
>>>> c.__repr__() # works
1
>>>> repr(c) # enforces the rule
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: __repr__ returned non-repr (type 'int')
>>>> c # calls repr() implicitly
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: __repr__ returned non-repr (type 'int')
>>>> str(c) # also uses __repr__
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: __str__ returned non-str (type 'int')
>>>> c.__repr__ = lambda: "a"
>>>> c.__repr__() # lookup on instance
'a'
>>>> repr(c) # old method from the class
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: __repr__ returned non-repr (type 'int')
>>>>

It's the same thing
Think of repr() as containing the following code:
def repr(obj):
return obj.__repr__()
All it does is call the object's __repr__() function. I'm not sure why anyone would need to call the object's __repr__() method explicitly. In fact, it's generally bad coding style to do so (it's confusing, and leads the programmer to ask questions like the one that you did just now).

Related

staticmethod from function object. Why don't I need to staticmethod it?

Let us, counterfactually, assume I had a good reason for wanting to make builtin print a static method of some class.
My, apparently wrong, gut feeling was that I need to declare it static doing something like
class sm:
p = staticmethod(print)
as opposed to
class no_sm:
p = print
But it seems both work just fine.
a = sm()
b = no_sm()
a.p("hello")
b.p("hello")
prints
hello
hello
Why does it just work and is there any difference between the two?
Related: Why use staticmethod instead of no decorator at all
for ~most normal functions, they go through a descriptor protocol (__get__) and so they need special decorating when attached to classes in the way you're doing.
take for example:
def f():
print('hi')
class C:
f = f
class D:
f = staticmethod(f)
in this case C().f() errors:
>>> C().f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 0 positional arguments but 1 was given
that's because it goes through:
>>> C.f.__get__(C())()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 0 positional arguments but 1 was given
but you'll notice, that print has no such attribute __get__:
>>> hasattr(print, '__get__')
it even has a different type!
>>> type(print)
<class 'builtin_function_or_method'>
>>> type(f)
<class 'function'>
so the answer is: print (along with other C functions) without special treatment do not participate in the method descriptor protocol so they act as normal callable objects without attachment of self

Using Python's struct library to pack None type

>>> import struct
>>> struct.pack("!x", None)
Traceback (most recent call last):
File "<console>", line 1, in <module>
struct.error: pack expected 0 items for packing (got 1)
In the documentation, the x format character acts as a pad byte in C which translates to a 'no value' type in Python or None. But I'm still getting the above error.
In this case, "no value" means do not put a value, not that None needs to be specified.
>>> struct.pack("!x")
'\x00'
Likewise, when unpacking a struct, x will effectively cause that byte to be skipped.
>>> struct.unpack("!x", '\x00')
()

Different ValueError for the same operation in List and Tuple

I am curious why ValueErrors are different in List and Tuple when I try to get an index. ValueError of a list returns in well format with actual argument "ValueError: 'ITEM' is not in list", whereas tuple returns something like this "ValueError: tuple.index(x): x not in tuple".
I think List and Tuple both are calling same index() method then why it is raising different ValueErrors?
>>> jframe_li
['Angular', 'React', 'Vue.js', 'Ember.js', 'Mereor', 'Node.js', 'Backbone.js']
>>> jframe_tu
('Angular', 'React', 'Vue.js', 'Ember.js', 'Mereor', 'Node.js', 'Backbone.js')
>>> jframe_li.index('React')
1
>>> jframe_tu.index('React')
1
>>> jframe_li.index('react')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: 'react' is not in list
>>> jframe_tu.index('react')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: tuple.index(x): x not in tuple
There are implementation differences in the index methods for lists and tuples, including in the text of a raised ValueError.
See ValueError string for tuple.index and ValueError string for list.index

Extending peewee expressions throws 'Expression' object is not iterable

I want to dynamically create where-clauses in peewee. I learned I need to use expressions, but cannot get this to run. Here my code:
clauses = [
(Docs.language_frst == 0),
(Docs.body_len <= max_body_len),
(Docs.body_len >= min_body_len)
]
if len(aValid_ids_used):
clauses.extend( (Docs.id.not_in(aValid_ids_used)) )
docids = Docs.select(Docs.id).where(reduce(operator.and_, clauses))
As long as aValid_ids_used is empty the code runs fine. Once aValid_ids_used is not empty any longer and I am asking the clauses to be extended I get an error:
Traceback (most recent call last): File "xyz.py", line 170, in <module>
clauses.extend( (Docs.id.not_in(aValid_ids_used)) )
TypeError: 'Expression' object is not iterable
You need to pass a list to extend with. You're currently passing an Expression
clauses.extend( (Docs.id.not_in(aValid_ids_used), ) )
e.g.
>>> c = []
>>> c.extend((2))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>> c.extend((2,))
>>> c
[2]
You probably want to use list.append rather than list.extend. extend takes a list as an argument, while append takes a single item.

clarification on comparing objects of different types

The following sentences are a cause of confusion for me(from Guido's Tutorial on python.org):
"Note that comparing objects of
different types is legal. The outcome
is deterministic but arbitrary: the
types are ordered by their name. Thus,
a list is always smaller than a
string, a string is always smaller
than a tuple, etc."than a tuple, etc."
That means that for :
a=[90]
b=(1)
a<b
the result should be True. But it is not so!
Can you help me out here?than a tuple, etc."
Also, what is meant by "The outcome is deterministic but arbitrary"?
(1) is an int. You probably meant (1,), which is a tuple.
Please note that you should not rely upon this behavior anymore. Some built-in types cannot be compared with other built-ins, and new data model provides a way to overload comparator functionality.
>>> set([1]) > [1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only compare to a set
Moreover, it was removed in py3k altogether:
>>> [1,2] > (3,4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: list() > tuple()
>>> [1,2] > "1,2"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: list() > str()

Categories

Resources