0

Python has a magic __getattr__ method that allows custom values to be returned:

class A(object):
    def __getattr__(self, name):
        return name

B = A()
print B.foo  # 'foo'

However, calling A.foo has no similar effect, because A is not an instance.

Using metaclasses, Google App Engine raises this error on instantiation:

File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 913, in __init__
key_name.__class__.__name__)
    BadKeyError: Name must be string type, not tuple

Assuming the referenced question is correctly implemented, what other ways can a magic class __getattr__ be implemented?

Community
  • 1
  • 1
Brian
  • 7,394
  • 3
  • 25
  • 46

2 Answers2

2

The metaclass solution should work, here is an example:

class GetAttrMeta(type):
    def __getattr__(self, name):
        return name

class A(object):
    __metaclass__ = GetAttrMeta

print A.foo  # 'foo'

Or with Python 3.x:

class GetAttrMeta(type):
    def __getattr__(self, name):
        return name

class A(object, metaclass=GetAttrMeta):
    pass

print(A.foo)  # 'foo'
Andrew Clark
  • 202,379
  • 35
  • 273
  • 306
  • That was tried (as cited, question 3155436), but Google's `db.Model` object, which I did extend using `class A(db.Model):`, conflicts in some way with the metaclass extension `type`, leading to the error shown above. – Brian Aug 04 '12 at 16:36
  • You should try to check if `db.Model` has a different metaclass than type - and extend that instead of `type`. – jsbueno Sep 07 '12 at 22:42
1

Not sure if this answers your question, but maybe checkout property descriptors ..

class RevealAccess(object):
"""A data descriptor that sets and returns values
   normally and prints a message logging their access.
"""

def __init__(self, initval=None, name='var'):
    self.val = initval
    self.name = name

def __get__(self, obj, objtype):
    print 'Retrieving', self.name
    return self.val

def __set__(self, obj, val):
    print 'Updating' , self.name
    self.val = val

>>> class MyClass(object):
    x = RevealAccess(10, 'var "x"')
    y = 5
>>> MyClass.x
Retrieving var "x"
10
>>> MyClass().x
Retrieving var "x"
10
>>> 
>>> m = MyClass()
>>> m.x
Retrieving var "x"
10
>>> m.x = 20
Updating var "x"
>>> m.x
Retrieving var "x"
20
>>> m.y
5
cwa
  • 1,092
  • 9
  • 12