The following is in python 2.7 with MySQLdb 1.2.3.
I needed a class wrapper to add some attributes to objects which didn't support it (classes with __slots__
and/or some class written in C) so I came out with something like this:
class Wrapper(object):
def __init__(self, obj):
self._wrapped_obj = obj
def __getattr__(self, obj):
return getattr(self._wrapped_obj, attr)
I was expecting that the dir()
builtin called on my instance of Wrapper
should have returned just the names inherited by object plus wrapped_obj
, and I discovered that this is actually the case for most cases, but not for all. I tried this with a custom old style class, a custom new style class, and some builtin classes, it always worked this way: the only exception that i found is when the wrapped object was an instance of the class _mysql.connection
. In this case, dir()
on my object happens to know also all the method names attached to the wrapped connection object.
I read in the python documentation about dir
, and this behaviour appears to be legit: dir
is supposed to return a list of "interesting names", not the "real" content of the instance. But I really can't figure how it does this: it actually understands the implementation of my __getattr__
and resolves to the attached item? If this is true, why only with that connection
class and not for instance with a simpler dict
?
Here is some pasted code as an example of this curious behaviour:
>>> from _mysql import connection
>>> c = connection(**connection_parameters)
>>> c
<_mysql.connection open to '127.0.0.1' at a16920>
>>>
>>> dir(c)
['affected_rows', 'autocommit', 'change_user', 'character_set_name', 'close', 'commit', 'dump_debug_info', 'errno', 'error', 'escape', 'escape_string', 'field_count', 'get_character_set_info', 'get_host_info', 'get_proto_info', 'get_server_info', 'info', 'insert_id', 'kill', 'next_result', 'ping', 'query', 'rollback', 'select_db', 'set_character_set', 'set_server_option', 'shutdown', 'sqlstate', 'stat', 'store_result', 'string_literal', 'thread_id', 'use_result', 'warning_count']
>>>
>>> w = Wrapper(c)
>>> dir(w)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_wrapped_obj', 'affected_rows', 'autocommit', 'change_user', 'character_set_name', 'close', 'commit', 'dump_debug_info', 'errno', 'error', 'escape', 'escape_string', 'field_count', 'get_character_set_info', 'get_host_info', 'get_proto_info', 'get_server_info', 'info', 'insert_id', 'kill', 'next_result', 'ping', 'query', 'rollback', 'select_db', 'set_character_set', 'set_server_option', 'shutdown', 'sqlstate', 'stat', 'store_result', 'string_literal', 'thread_id', 'use_result', 'warning_count']
>>>
>>> d = Wrapper({})
>>> dir(d)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_wrapped_obj']
>>>
__getattr__Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self ). name is the attribute name. This method should return the (computed) attribute value or raise an AttributeError exception.
Dunder or magic methods in Python are the methods having two prefix and suffix underscores in the method name. Dunder here means “Double Under (Underscores)”. These are commonly used for operator overloading. Few examples for magic methods are: __init__, __add__, __len__, __repr__ etc.
Magic methods in Python are the special methods that start and end with the double underscores. They are also called dunder methods. Magic methods are not meant to be invoked directly by you, but the invocation happens internally from the class on a certain action.
Python setattr() and getattr() goes hand-in-hand. As we have already seen what getattr() does; The setattr() function is used to assign a new value to an object/instance attribute. Syntax. Use a different Browser.
object. __getattr__ (self, name) Is an object method that is called if the object’s properties are not found. This method should return the property value or throw AttributeError. Note that if the object property can be found through the normal mechanism, it will not be called. __getattr__ method. class Frob:... def __init__ (self, bamf):...
In a nutshell magic method do magic to python programming by reducing complexity. This is a guide on Python Magic Method. Here we discuss the introduction to Python Magic Method, it’s components and advantages, as well as some examples.
But using the __ getattr__ magic method, we can intercept that inexistent attribute lookup and do something so it doesn’t fail: But if the attribute does exist, __getattr__ won’t be invoked:
As you can see above, the int class includes various magic methods surrounded by double underscores. For example, the __add__ method is a magic method which gets called when we add two numbers using the + operator. Consider the following example.
There are two deprecated attributes in Python 2, object.__members__
and object.__methods__
; these were aimed at supporting dir()
on extension types (C-defined objects):
object.__methods__
Deprecated since version 2.2: Use the built-in functiondir()
to get a list of an object’s attributes. This attribute is no longer available.
object.__members__
Deprecated since version 2.2: Use the built-in function dir() to get a list of an object’s attributes. This attribute is no longer available.
These were removed from Python 3, but because your connection object (at leasts in the older version you are using) still provides a __methods__
attribute that is found through your __getattr__
hook and used by dir()
here.
If you add a print
statement to the __getattr__
method you'll see the attributes being accessed:
>>> class Wrapper(object):
... def __init__(self, obj):
... self._wrapped_obj = obj
... def __getattr__(self, obj):
... print 'getattr', obj
... return getattr(self._wrapped_obj, attr)
...
>>> dir(Wrapper({}))
getattr __members__
getattr __methods__
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_wrapped_obj']
For new-style objects, the newer __dir__
method supported by dir()
is properly looked up on the type only so you don't see that being accessed here.
The project HISTORY file suggests the attributes were removed in the big Python 3 compatibility update for 1.2.4 beta 1.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With