The following code behaves differently in Python 2 and Python 3, and I'm not sure why.
class Dataset(object):
def __getattr__(self, item):
if not item in dir(self):
print(item)
a = Dataset()
a.Hello
The result in Python 3:
> Hello
The result in Python 2:
__members__
__members__
__methods__
...
ad infinitum until a recursion ceiling is reached. What is the difference in the behavior of "dir"?
Edit: And is there a workaround? self.dict is the obvious choice but it doesn't include functions which turns out to be a problem in my code.
Python 3 has an easier syntax compared to Python 2. A lot of libraries of Python 2 are not forward compatible. A lot of libraries are created in Python 3 to be strictly used with Python 3. Python 2 is no longer in use since 2020.
Python dir() Function The dir() function returns all properties and methods of the specified object, without the values. This function will return all the properties and methods, even built-in properties which are default for all object.
Python dir() The function dir python is responsible for returning the valid list of the attributes for the objects in the current local scope. For example: If an object of a method called is named as __dir__(), the function must return a list of attributes that are associated with that function.
In Python 2, print is a statement that does not need a parenthesis. In Python 3, print is a function and the values need to be written in parenthesis.
The documentation for dir
in Python 2.7 and 3.5 seems identical - there are no implementation details. But clearly, dir()
in Python 2 invokes __getattr__
causing the infinite recursion.
However, both documentation sets do say that
Because dir() is supplied primarily as a convenience for use at an interactive prompt, it tries to supply an interesting set of names more than it tries to supply a rigorously or consistently defined set of names, and its detailed behavior may change across releases. For example, metaclass attributes are not in the result list when the argument is a class.
That note about it being a convenience is significant.
If you modify your __getattr__
to look at self.__dict__
instead of using dir()
,the problem goes away.
In [5]: class Dataset(object):
def __getattr__(self, item):
if not item in self.__dict__:
print(item)
...:
In [6]: a = Dataset()
In [7]: a.Hello
Hello
Without examining the source code, I can't say why this happens (although I have some hypotheses), but here is a pretty simple workaround:
class Dataset(object):
def __getattr__(self, item):
try:
super(Dataset, self).__getattr__(item)
except AttributeError:
print(item)
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