8

As the Python 2 documentation on __repr__ states:

If at all possible, this (i.e. __repr__) should look like a valid Python expression that could be used to recreate an object with the same value (given an appropriate environment).

So how come builtin __repr__ for classes does not act accordingly to that guideline?

Example

>>> class A(object):
...   pass
>>> repr(A)
"<class 'A'>"

To meet the guideline, the default __repr__ should return "A", i.e. generally A.__name__. Why is it acting differently? It would be extra-easy to implement, I believe.


Edit: The scope of 'reproduction'

I can see in the answers that it is not clear in the discussion what repr should return. The way I see it, the repr function should return a string that allows you to reproduce the object:

  1. in an arbitrary context and
  2. automatically (i.e. not manually).

Ad.1. Take a look at a built-in class case (taken from this SO question):

>>> from datetime import date
>>>
>>> repr(date.today())        # calls date.today().__repr__()
'datetime.date(2009, 1, 16)'

Apparently, the assumed context is as if you use the basic form of import, i.e. import datetime, because if you would try eval(repr(date.today())), datetime would not be recognized. So the point is that __repr__ doesn't need to represent the object from scratch. It's enough if it is unambiguous in a context the community agreed upon, e.g. using direct module's types and functions. Sounds reasonable, right?

Ad.2. Giving an impression of how the object could be reconstructed is not enough for repr, I believe. Helpfulness in debugging is the purpose of str.

Conclusion

So what I expect from repr is allowing me to do eval on the result. And in the case of a class, I would not like to get the whole code that would reconstruct the class from scratch. Instead, I would like to have an unambiguous reference to a class visible in my scope. The "Module.Class" would suffice. No offence, Python, but "<class 'Module.Class'>" doesn't just cut it.

Community
  • 1
  • 1
Janusz Lenar
  • 1,690
  • 2
  • 13
  • 19
  • Actually, it would need to return something like `type("A", (), {})`: code that can generate a class equivalent to `A`. As mgilson points out, it's difficult to build an *expression* (note that classes are typically defined by a `class` *statement*) that creates a class. – chepner Mar 12 '13 at 13:18
  • This would actually quite tricky to implement as well as rather useless and confusing. – Fred Foo Mar 12 '13 at 13:43
  • @larsmans Depends how deep you'd go to define an object. I'm not talking about reproducing a class from scratch. See the edit, please. – Janusz Lenar Mar 12 '13 at 15:19
  • @JanuszLenar: ah, yes, if that's what you want, it's actually quite simple and reasonable. – Fred Foo Mar 12 '13 at 21:32

4 Answers4

3

Consider a slightly more complicated class:

class B(object):
    def __init__(self):
        self.foo=3

repr would need to return something like

type("B", (object,), { "__init__": lambda self: setattr(self, "foo", 3) })

Notice one difficulty already: not all functions defined by the def statement can be translated into a single lambda expression. Change B slightly:

class B(object):
    def __init__(self, x=2, y, **kwargs):
        print "in B.__init__"

How do you write an expression that defines B.__init__? You can't use

lambda self: print "in B.__init__"

because lambda expressions cannot contain statements. For this simple class, it is already impossible to write a single expression that defines the class completely.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • Python 3 solves this by making `print` a function, so no obstacles remain for a new `repr` on classes (although `eval` probably works even in Python 2 ;) – Fred Foo Mar 12 '13 at 13:41
  • I was ignoring the `print` function in Python 3 :), but there are other statements (`if`, `while`, `try`, etc.) that you would need to handle. `eval` also expects an expression (or a code object); you may be thinking of `exec`. But `__repr__` isn't supposed to be a robust dynamic code generator; it's a convenience function that should be somewhat usable if reasonably possible. – chepner Mar 12 '13 at 13:57
  • `exec` is a statement. With `eval`, you can actually set variables: `eval('locals().__setitem__("ham", "spam")')`. `while` can be made an expression with a fixed-point operator, `if` has an expression form... I'm fully aware that I'm speaking great evils :) – Fred Foo Mar 12 '13 at 14:09
  • 2
    We're turning this question into "How can I rewrite my class in Lisp?" :) – chepner Mar 12 '13 at 14:21
  • @chepner You're totally right about the lambda misfit for the general solution. As Martijn says, if I were to represent the whole class fully, I would rather pickle it. I think the purpose of `repr` on a class is pinning down the class' name. Do you agree on that? – Janusz Lenar Mar 12 '13 at 15:22
2

Because the default __repr__ cannot know what statements were used to create the class.

The documentation you quote starts with If at all possible. Since it is not possible to represent custom classes in a way that lets you recreate them, a different format is used, which follows the default for all things not easily recreated.

If repr(A) were to just return 'A', that'd be meaningless. You are not recreating A, you'd just be referencing it then. "type('A', (object,), {})" would be closer to reflecting the class constructor, but that'd be a) confusing for people not familiar with the fact python classes are instances of type and b) never able to reflect methods and attributes accurately.

Compare the output to that of repr(type) or repr(int) instead, these follow the same pattern.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 1
    It's worth noting that we're talking about the class itself, not about an instance of the class. – NPE Mar 12 '13 at 13:13
  • Notice that OP isn't trying to represent an *instance* here ... Python does know (in many cases at least) the source code used to create the class. – mgilson Mar 12 '13 at 13:13
  • It's true. Creating a class via `type(name,subclasses,cls_dict)` would be pretty hard to gather all of that information into a meaningful string to recreate it. – mgilson Mar 12 '13 at 13:16
  • @MartijnPieters You are right that the result of `repr` might be hard to read. But it's not aimed to be readable; it's meant to be able to reproduce the object. So regarding a), I wouldn't care. Want a readable string? Use `str`. – Janusz Lenar Mar 12 '13 at 14:29
  • @JanuszLenar: *I* want a string that gives me a good idea of what it is I am debugging instead. If you want to have a serialization format, use pickle or marshall instead. – Martijn Pieters Mar 12 '13 at 14:31
  • @MartijnPieters Good point. I'm editing the question to pin down requirements for `repr`. – Janusz Lenar Mar 12 '13 at 14:33
1

I know this is an older question, but I found a way to do it.

The only way I know to do this is with a metaclass like so:

class A(object):
    secret = 'a'

    class _metaA(type):
        @classmethod
        def __repr__(cls):
            return "<Repr for A: secret:{}>".format(A.secret)
    __metaclass__ =_metaA

outputs:

>>> A
<Repr for A: secret:a>
theannouncer
  • 1,148
  • 16
  • 28
0

Since neither "<class 'A'>" nor "A" can be used to re-create the class when its definition is not available, I think the question is moot.

NPE
  • 486,780
  • 108
  • 951
  • 1,012