why __repr__ affected after __getattr__ overloaded?

R

Roc Zhou

Now I have to design a class that overload __getattr__, but after
that, I found the __repr__ have been affected. This is a simple
example model:
#!/usr/bin/env python

class test:
def __init__(self):
self.x = 1
def __getattr__(self, attr_name):
try:
return self.__dict__[attr_name]
except KeyError:
self.__dict__[attr_name] = 'inexistent'
return self.__dict__[attr_name]

t = test()
print t.x
print t.y
print type(t)
T = t
print T.x
print t

So far, I want the operation "print t" still return "<test instance
at ...>", but the reuslt is:
sh$ python test.py
1
inexistent
<type 'instance'>
1
Traceback (most recent call last):
File "testtree.py", line 23, in ?
print t
TypeError: 'str' object is not callable

I also tried to overload __repr__ itself:

#!/usr/bin/env python

class test:
def __init__(self):
self.x = 1
def __getattr__(self, attr_name):
try:
return self.__dict__[attr_name]
except KeyError:
self.__dict__[attr_name] = 'inexistent'
return self.__dict__[attr_name]
def __repr__(self):
return 'test.__repr__'

t = test()
print t.x
print t.y
print type(t)
T = t
print T.x
print t

But the result remains:
Traceback (most recent call last):
File "testtree.py", line 23, in ?
print t
TypeError: 'str' object is not callable

So why? What is the principles?
 
G

Gabriel Genellina

Now I have to design a class that overload __getattr__, but after
that, I found the __repr__ have been affected. This is a simple
example model:

You are creating many attributes with value "inexistent", even special
methods. Put a print statement and see what happens:
#!/usr/bin/env python

class test:
def __init__(self):
self.x = 1
def __getattr__(self, attr_name):
try:
return self.__dict__[attr_name]
except KeyError:
print "Now creating:",attr_name
self.__dict__[attr_name] = 'inexistent'
return self.__dict__[attr_name]
 
R

Roc Zhou

I know what's wrong. Thank you. And I think
try:
return self.__dict__[attr_name]
is unnecessary, because python will do it itself for us.

So now I have to overload __str__, but how can I make self.__str__
print as builtin str(): at here, I want get the result like:
<test instance at 0xb7bbb90c>
?

Now I have to design a class that overload __getattr__, but after
that, I found the __repr__ have been affected. This is a simple
example model:

You are creating many attributes with value "inexistent", even special
methods. Put a print statement and see what happens:
#!/usr/bin/env python
class test:
def __init__(self):
self.x = 1
def __getattr__(self, attr_name):
try:
return self.__dict__[attr_name]
except KeyError:

print "Now creating:",attr_name
self.__dict__[attr_name] = 'inexistent'
return self.__dict__[attr_name]
 
R

Roc Zhou

return hex(id(self))

I know what's wrong. Thank you. And I think
try:
return self.__dict__[attr_name]
is unnecessary, because python will do it itself for us.

So now I have to overload __str__, but how can I make self.__str__
print as builtin str(): at here, I want get the result like:
<test instance at 0xb7bbb90c>
?

En Fri, 22 Jun 2007 00:30:43 -0300, Roc Zhou <[email protected]>
escribió:
You are creating many attributes with value "inexistent", even special
methods. Put a print statement and see what happens:
#!/usr/bin/env python
class test:
def __init__(self):
self.x = 1
def __getattr__(self, attr_name):
try:
return self.__dict__[attr_name]
except KeyError:
print "Now creating:",attr_name
self.__dict__[attr_name] = 'inexistent'
return self.__dict__[attr_name]
 
R

Roc Zhou

I'm sorry but I still have a question, look at this example:.... def __init__(self):
.... self.x = 1
.... def __getattr__(self, attr_name):
.... print attr_name
.... if attr_name == 'y':
.... return 2
.... else:
.... raise AttributeError, attr_name
....
__str__
__repr__
<__main__.test instance at 0xb7f6d6cc>

Since __str__ and __repr__ does not exist because their names was
printed, why not the "AttributeError" be raised?
 
G

Gabriel Genellina

I know what's wrong. Thank you. And I think
try:
return self.__dict__[attr_name]
is unnecessary, because python will do it itself for us.

Exactly; by the time __getattr__ is called, you already know attr_name is
not there.
So now I have to overload __str__, but how can I make self.__str__
print as builtin str(): at here, I want get the result like:
<test instance at 0xb7bbb90c>
?

I would do the opposite: *only* create inexistent attributes when they are
not "special". This way you don't mess with Python internals.

.... def __getattr__(self, name):
.... if name[:2]!='__' or name[-2:]!='__':
.... self.__dict__[name] = 'inexistent'
.... return self.__dict__[name]
.... raise AttributeError,name

This way you don't create "fake" attributes for things like __bases__ by
example, and dir(), vars(), repr() etc. work as expected.
 
G

Gabriel Genellina

I'm sorry but I still have a question, look at this example:
... def __init__(self):
... self.x = 1
... def __getattr__(self, attr_name):
... print attr_name
... if attr_name == 'y':
... return 2
... else:
... raise AttributeError, attr_name
...
__str__
__repr__
<__main__.test instance at 0xb7f6d6cc>

Since __str__ and __repr__ does not exist because their names was
printed, why not the "AttributeError" be raised?

This is the implementation of str() in action; tries to find a __str__
method and fails; tries to find a __repr__ instead and fails; then uses
the default representation.
See <http://docs.python.org/ref/customization.html#l2h-179>
 
P

Peter Otten

Roc said:
I'm sorry but I still have a question, look at this example:
... def __init__(self):
... self.x = 1
... def __getattr__(self, attr_name):
... print attr_name
... if attr_name == 'y':
... return 2
... else:
... raise AttributeError, attr_name
...
__str__
__repr__
<__main__.test instance at 0xb7f6d6cc>

Since __str__ and __repr__ does not exist because their names was
printed, why not the "AttributeError" be raised?

Because classic classes invoke

t.__getattr__(self, "__repr__")

and expect that to return a proper __repr__() method -- unless __getattr__()
raises an AttributeError:
.... def __getattr__(self, name):
.... if name == "__repr__":
.... raise AttributeError
<__main__.Test instance at 0x401d42ac>

If you use newstyle classes you won't run into that particular problem:
.... def __getattr__(self, name):
"<inexistent 'yadda'>"
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,742
Latest member
AshliMayer

Latest Threads

Top