473,769 Members | 6,653 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

__getattr__ and functions that don't exist


Maybe I just don't know the right special function, but what I am wanting to
do is write something akin to a __getattr__ function so that when you try to
call an object method that doesn't exist, it get's intercepted *along with
it's argument*, in the same manner as __getattr__ intercepts attributes
references for attributes that don't exist.
This doesn't quite work:
class Foo: .... def __getattr__(sel f, att_name, *args):
.... print "%s%s" % (att_name, str(tuple(*args )))
.... f = Foo()
f.bar bar() f.bar(1,2,3) bar()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'NoneType' object is not callable f.bar()

bar()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'NoneType' object is not callable
Is there some other special function like __getattr__ that does what I want?

Thanks,
-ej
May 25 '06 #1
6 4507
Erik Johnson wrote:
Maybe I just don't know the right special function, but what I am wanting to
do is write something akin to a __getattr__ function so that when you try to
call an object method that doesn't exist, it get's intercepted *along with
it's argument*, in the same manner as __getattr__ intercepts attributes
references for attributes that don't exist.
This doesn't quite work:
class Foo: ... def __getattr__(sel f, att_name, *args):
... print "%s%s" % (att_name, str(tuple(*args )))
... f = Foo()


The problem is that the call to f.bar happens in two stages: the
interpreter calls getattr(f, "foo") to get a function, and then it
calls that function. When __getattr__ is called, you can't tell what
the parameters of the function call will be, or even if it'll be called
at all - someone could have run "print f.bar".

Instead, you can make __getattr__ return a function. Then *that*
function will be called as f.bar, and you can print out its arguments
there:

class Foo:
def __getattr__(sel f, attr):
def intercepted(*ar gs):
print "%s%s" % (attr, args)
return intercepted

May 25 '06 #2

Thanks for your reply, Nick. My first thought was "Ahhh, now I see. That's
slick!", but after playing with this a bit...
class Foo: .... def __getattr__(sel f, attr):
.... def intercepted(*ar gs):
.... print "%s%s" % (attr, args)
.... return intercepted
.... f = Foo()
f
__repr__()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: __repr__ returned non-string (type NoneType)
my thought is "Oooooh... that is some nasty voodoo there!" Especially
if one wants to also preserve the basic functionality of __getattr__ so that
it still works to just get an attribute where no arguments were given.

I was thinking it would be clean to maintain an interface where you
could call things like f.set_Spam('ham ') and implement that as self.Spam =
'ham' without actually having to define all the set_XXX methods for all the
different things I would want to set on my object (as opposed to just making
an attribute assignment), but I am starting to think that is probably an
idea I should just simply abandon.

I guess I don't quite follow the error above though. Can you explain
exactly what happens with just the evaluation of f?

Thanks,
-ej
"Nick Smallbone" <ni************ @gmail.com> wrote in message
news:11******** *************@g 10g2000cwb.goog legroups.com...
Erik Johnson wrote:
Maybe I just don't know the right special function, but what I am

wanting to do is write something akin to a __getattr__ function so that when you try to call an object method that doesn't exist, it get's intercepted *along with it's argument*, in the same manner as __getattr__ intercepts attributes
references for attributes that don't exist.
This doesn't quite work:
>> class Foo:

... def __getattr__(sel f, att_name, *args):
... print "%s%s" % (att_name, str(tuple(*args )))
...
>> f = Foo()


The problem is that the call to f.bar happens in two stages: the
interpreter calls getattr(f, "foo") to get a function, and then it
calls that function. When __getattr__ is called, you can't tell what
the parameters of the function call will be, or even if it'll be called
at all - someone could have run "print f.bar".

Instead, you can make __getattr__ return a function. Then *that*
function will be called as f.bar, and you can print out its arguments
there:

class Foo:
def __getattr__(sel f, attr):
def intercepted(*ar gs):
print "%s%s" % (attr, args)
return intercepted

May 26 '06 #3
Erik Johnson wrote:
Thanks for your reply, Nick. My first thought was "Ahhh, now I see. That's
slick!", but after playing with this a bit...
class Foo: ... def __getattr__(sel f, attr):
... def intercepted(*ar gs):
... print "%s%s" % (attr, args)
... return intercepted
... f = Foo()
f __repr__()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: __repr__ returned non-string (type NoneType)
my thought is "Oooooh... that is some nasty voodoo there!" Especially
if one wants to also preserve the basic functionality of __getattr__ so that
it still works to just get an attribute where no arguments were given.

I was thinking it would be clean to maintain an interface where you
could call things like f.set_Spam('ham ') and implement that as self.Spam =
'ham' without actually having to define all the set_XXX methods for all the
different things I would want to set on my object (as opposed to just making
an attribute assignment), but I am starting to think that is probably an
idea I should just simply abandon.
You're right, you should probably abandon it because python is not
java; there's no reason to bloat your API with getters and setters
instead of the natural attribute access and assignment. Now if you've
spent a lot of time in the java camp and can't live without verbose
getters and setters, it's not hard to emulate them:

class Foo(object):
def __getattr__(sel f, attr):
if not (attr.startswit h('get_') or attr.startswith ('set_')):
raise AttributeError
name = attr[4:]
if attr[0] == 'g':
return lambda: getattr(self,na me)
else:
return lambda value: setattr(self,na me,value)

f = Foo()
f.set_bar(1)
print f.get_bar()
print f.bar

I guess I don't quite follow the error above though. Can you explain
exactly what happens with just the evaluation of f?
Several thing happen:
1. When you give an expression in the shell, its value is computed and
then passed to the repr() function. The result of repr(f) is what's
printed.
2. repr(f) attempts to call f.__repr__()
3. __repr__ is not defined in class Foo or any of its (zero)
superclasses.
4. As a result, f.__getattr__(' __repr__') is called instead and returns
the intercept local function.
5. intercept() is called with zero arguments (remember, intercept is
the result of f.__repr__)
6. intecept prints something but it doesn't return explicitly; thus it
returns None.
7. There's a rule that __repr__ (like __str__ and __unicode__) has to
return a string-type (I'm not sure where is this rule enforced, by the
classobj maybe ?). Since you returned None, an exception is raised.

Note that there is not an exception if
- you replace print with return in __getattr__, or
- Foo is a new-style class, i.e. extends object like this:
class Foo(object):
# rest remain the same
The reason is that in step (3) above, __repr__ would be looked up in
Foo's superclass, object, and object.__repr__ would be called instead
of Foo.__getattr__ . Try to use new-style classes in new code unless you
have a good reason not to.
Thanks,
-ej
HTH,
George

"Nick Smallbone" <ni************ @gmail.com> wrote in message
news:11******** *************@g 10g2000cwb.goog legroups.com...
Erik Johnson wrote:
Maybe I just don't know the right special function, but what I am

wanting to do is write something akin to a __getattr__ function so that when you try to call an object method that doesn't exist, it get's intercepted *along with it's argument*, in the same manner as __getattr__ intercepts attributes
references for attributes that don't exist.
This doesn't quite work:

>>> class Foo:
... def __getattr__(sel f, att_name, *args):
... print "%s%s" % (att_name, str(tuple(*args )))
...
>>> f = Foo()


The problem is that the call to f.bar happens in two stages: the
interpreter calls getattr(f, "foo") to get a function, and then it
calls that function. When __getattr__ is called, you can't tell what
the parameters of the function call will be, or even if it'll be called
at all - someone could have run "print f.bar".

Instead, you can make __getattr__ return a function. Then *that*
function will be called as f.bar, and you can print out its arguments
there:

class Foo:
def __getattr__(sel f, attr):
def intercepted(*ar gs):
print "%s%s" % (attr, args)
return intercepted


May 26 '06 #4
Erik Johnson wrote:
Thanks for your reply, Nick. My first thought was "Ahhh, now I see. That's
slick!", but after playing with this a bit...
class Foo: ... def __getattr__(sel f, attr):
... def intercepted(*ar gs):
... print "%s%s" % (attr, args)
... return intercepted
... f = Foo()
f __repr__()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: __repr__ returned non-string (type NoneType)
my thought is "Oooooh... that is some nasty voodoo there!" Especially
if one wants to also preserve the basic functionality of __getattr__ so that
it still works to just get an attribute where no arguments were given.

I was thinking it would be clean to maintain an interface where you
could call things like f.set_Spam('ham ') and implement that as self.Spam =
'ham' without actually having to define all the set_XXX methods for all the
different things I would want to set on my object (as opposed to just making
an attribute assignment), but I am starting to think that is probably an
idea I should just simply abandon.
Well, you could tweak __getattr__ as follows:
class Foo: .... def __getattr__(sel f, attr):
.... if attr.startswith ('__'):
.... raise AttributeError
.... def intercepted(*ar gs):
.... print "%s%s" % (attr, args)
.... return intercepted

But abandoning the whole idea is probably a good idea. How is defining
a magic set_XXX method cleaner than just setting the attribute? Python
is not C++/Java/C#. Accessors and mutators for simple attributes are
overkill. Keep it simple, you'll thank yourself for it later when
maintaining your code. :-)
I guess I don't quite follow the error above though. Can you explain
exactly what happens with just the evaluation of f?


Sure. (Note, this is greatly simplified, but still somewhat complex.)
The Python interpreter does the following when you type in an
expression:

(1) evaluate the expression, store the result in temporary object
(2) attempt to access the object's __repr__ method
(3) if step 2 didn't raise an AttributeError, call the method, output
the result, and we're done
(4) if __getattr__ is defined for the object, call it with "__repr__"
as the argument
(5) if step 4 didn't raise an AttributeError, call the method, output
the result, and we're done
(6) repeat steps 2 through 5 for __str__
(7) as a last resort, output the default "<class __main__.Foo at
0xDEADBEEF>" string

In your case, the intepreter hit step 4. f.__getattr__(" __repr__")
returned the "intercepte d" function, which was then called. However,
the "interprete d" function returned None. The interpreter was
expecting a string from __repr__, so it raised a TypeError.

Clear as mud, right? Cutting out the __getattr__ trickery, here's a
simplified scenario (gets to step 3 from above):
class Bar(object): ... def __repr__(self):
... return None
... b = Bar()
b

Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: __repr__ returned non-string (type NoneType)

Hope that helps! One other small thing... please avoid top posting.

--Ben

May 26 '06 #5
class Parrot(object):
class _dummy(object):
def __init__(self, obj, name):
self.name = name
self.obj = obj

def __call__(self, *args, **kw):
print "dummy %s for %s" % (self.name, self.obj)
print "called with %s - %s" % (str(args), str(kw))

def __getattr__(sel f, name):
return self._dummy(sel f, name)

hth

May 26 '06 #6
Erik Johnson a écrit :
(snip)
I was thinking it would be clean to maintain an interface where you
could call things like f.set_Spam('ham ') and implement that as self.Spam =
'ham'
If all you want to do is to assign 'ham' to self.spam, just do it - no
need for a setter. And if you worry about possible future needs for
controlling assignement to spam, internally use another name for it or
any other computation at this level, then it will be time to refactor
obj.spam as a property:

class Parrot(object):
def _set_spam(self, value):
self._another_a ttrib = any_computation _here(value)
def _get_spam(self) :
return some_more_proce ssing_here(self ._another_attri b)
spam = property(_get_s pam, _set_spam)

p = Parrot()
p.spam = "ham"
print p.spam
without actually having to define all the set_XXX methods for all the
different things I would want to set on my object (as opposed to just making
an attribute assignment), but I am starting to think that is probably an
idea I should just simply abandon.


indeed.
May 26 '06 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
1415
by: Holger Joukl | last post by:
Hi there, please excuse my rather lengthy post. With introduction of the new style classes, something seems to have changed for __getattr__ hooks, even for classic classes: getattr.py: class A: # classic! def __getattr__(self, attr): print "-->A.__getattr__"
3
1811
by: Chris Curvey | last post by:
Hi all, I have this program class Company: def __init__(self, revenues, costs): self.revenues = revenues self.costs = costs def __getattr__(self, name):
0
6603
by: Gigi | last post by:
Hi, In the Python documentation regarding __getattribute__ (more attribute access for new style classes) it is mentioned that if __getattribute__ is defined __getattr__ will never be called (unless called explicitely). Here is the exact citation: """ The following methods only apply to new-style classes. __getattribute__( self, name)
13
3497
by: Pelmen | last post by:
How can I get rid of recursive call __getattr__ inside this method, if i need to use method or property of the class?
5
6866
by: Dylan Moreland | last post by:
I'm trying to implement a bunch of class methods in an ORM object in order to provide functionality similar to Rails' ActiveRecord. This means that if I have an SQL table mapped to the class "Person" with columns name, city, and email, I can have class methods such as: Person.find_by_name Person.find_by_city_and_name Person.find_by_name_and_city_and_email I have a metaclass generating basic properties such as .name and .city,
7
2334
by: Roc Zhou | last post by:
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:
2
2670
by: Stef Mientki | last post by:
hello, I tried to find an easy way to add properties (attributes) to a number of different components. So I wrote a class, from which all these components are derived. By trial and error I created the code below, which now works, but there is one thing I don't understand: in the line indicated with "<<== 1" I'm not allowed to use for item in self.extra_getters :
4
3944
by: Enrico | last post by:
Hi there, I have the following situation (I tryed to minimize the code to concentrate on the issue): def __getattr__(self, name): print 'A.__getattr__' if name == 'a': return 1 raise AttributeError('%s not found in A' % name) def __getattr__(self, name):
7
1710
by: =?UTF-8?Q?Alexandru_Mo=C8=99oi?= | last post by:
i'm facing the following problem: class Base(object): def __getattr__(self, attr): return lambda x: attr + '_' + x def dec(callable): return lambda *args: 'dec_' + callable(*args) class Derived(Base): what_so_ever = dec(Base.what_so_ever) # wrong, base doesn't have
0
9589
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9423
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10216
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
6675
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5309
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5448
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3965
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3565
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2815
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.