Cara menggunakan python __getattr__ classmethod

Magic Methods are a broad and general term that refers to “special” methods in a Python class. There is no single definition for all of them, as their use is diverse. For example, a few common and well-known magic methods include:

  • class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.does_not_exist # 'DOES_NOT_EXIST' d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE' 3 that serves as the object initializer (sometimes incorrectly referred to as constructor)
  • class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.does_not_exist # 'DOES_NOT_EXIST' d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE' 4 that provides a “string representation” of your object
  • class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.does_not_exist # 'DOES_NOT_EXIST' d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE' 5 that allows you to “overload” the + operator.

What do all these methods have in common? Well, obviously they all start and end with double underscores (class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.does_not_exist # 'DOES_NOT_EXIST' d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE' 6). But aside from that, what makes them “magic methods” is that they’re invoked somehow “specially”. We don’t manually invoke these methods; Python is the one doing it. For example, we don’t do class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.does_not_exist # 'DOES_NOT_EXIST' d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE' 7, we do class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.does_not_exist # 'DOES_NOT_EXIST' d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE' 8.

There are many magic methods, but as we will focus on class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.does_not_exist # 'DOES_NOT_EXIST' d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE' 9and class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 0 in this post.

__getattr__

Let’s start with class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 1. This method will allow you to “catch” references to attributes that don’t exist in your object. Let’s see a simple example to understand how it works:

class Dummy(object): passd = Dummy() d.does_not_exist # Fails with AttributeError

In this example, the attribute access fails (with an class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 2) because the attribute class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 3 doesn’t exist.

But using the __getattr__ magic method, we can intercept that inexistent attribute lookup and do something so it doesn’t fail:

class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.does_not_exist # 'DOES_NOT_EXIST' d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE'

But if the attribute does exist, class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 1 won’t be invoked:

class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python"

__getattribute__

class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 0 is similar to class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 1, with the important difference that class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 0 will intercept EVERY attribute lookup, doesn’t matter if the attribute exists or not. Let me show you a simple example:

class Dummy(object): def __getattribute__(self, attr): return 'YOU SEE ME?'d = Dummy() d.value = "Python" print(d.value) # "YOU SEE ME?"

In that example, the class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 8 object already has an attribute class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 9. But when we try to access it, we don’t get the original expected value (“Python”); we’re just getting whatever class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 0 returned. It means that we’ve virtually lost the class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 9 attribute; it has become “unreachable”.

If you ever need to use class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 0 to simulate something similar to class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 1 you’ll have to do some more advanced Python handling:

class Dummy(object): def __getattribute__(self, attr): __dict__ = super(Dummy, self).__getattribute__('__dict__') if attr in __dict__: return super(Dummy, self).__getattribute__(attr) return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" print(d.does_not_exist) # "DOES_NOT_EXIST"

A more realistic example

It’s not common to just randomly catch every attribute lookup. We generally use class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 1 with a clear objective in mind: whenever we want to provide some dynamic access to our objects. A good example could be extending the base Python tuple to add it some Scala flavor to it. In Scala, tuples are created really similarly to Python:

val a_tuple = ("z", 3, "Python", -1)

But they’re accessed in a different way:

println(a_tuple._1) // “z” println(a_tuple._3) // “Python”

Each element in the tuple is accessed as an attribute, with the first element being the attribute class Dummy(object): def __getattribute__(self, attr): return 'YOU SEE ME?'d = Dummy() d.value = "Python" print(d.value) # "YOU SEE ME?" 5, the second class Dummy(object): def __getattribute__(self, attr): return 'YOU SEE ME?'d = Dummy() d.value = "Python" print(d.value) # "YOU SEE ME?" 6, and so on.

In that example, you can see how we’re catching missing attributes with class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 1, but if that attribute is not in the form of class Dummy(object): def __getattribute__(self, attr): return 'YOU SEE ME?'d = Dummy() d.value = "Python" print(d.value) # "YOU SEE ME?" 8 (where class Dummy(object): def __getattribute__(self, attr): return 'YOU SEE ME?'d = Dummy() d.value = "Python" print(d.value) # "YOU SEE ME?" 9 is an integer), we just raise the class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 2 manually.

We can easily extend our common Python tuple to match this behavior, the code is really simple:

class Tuple(tuple): def __getattr__(self, name): def _int(val): try: return int(val) except ValueError: return False if not name.startswith('_') or not _int(name[1:]): raise AttributeError("'tuple' object has no attribute '%s'" % name) index = _int(name[1:]) - 1 return self[index] t = Tuple(['z', 3, 'Python', -1]) print(t._1) # 'z' print(t._2) # 3 print(t._3) # 'Python' t = Tuple(['z', 3, 'Python', -1]) assert t._1 == 'z' assert t._2 == 3 assert t._3 == 'Python' assert t._4 == -1

getattr()

class Dummy(object): def __getattribute__(self, attr): __dict__ = super(Dummy, self).__getattribute__('__dict__') if attr in __dict__: return super(Dummy, self).__getattribute__(attr) return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" print(d.does_not_exist) # "DOES_NOT_EXIST" 1is one of Python’s built-in functions, its role is to get the properties of the object.

  • Object object
  • Name attribute name
  • Default The default value is returned when the property does not exist

Example:

class Foo: def __init__(self, x): self.x = x f = Foo(10) getattr(f, 'x') f.x # 10 getattr(f, 'y', 'bar') # 'bar'

__getattr__

class Dummy(object): def __getattribute__(self, attr): __dict__ = super(Dummy, self).__getattribute__('__dict__') if attr in __dict__: return super(Dummy, self).__getattribute__(attr) return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" print(d.does_not_exist) # "DOES_NOT_EXIST" 2Is an object method that is called if the object’s properties are not found.

This method should return the property value or throw class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 2.

Note that if the object property can be found through the normal mechanism, it will not be called.class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 1method.

Example:

class Frob:... def __init__(self, bamf): self.bamf = bamf def __getattr__(self, name): return 'Frob does not have `{}` attribute.'.format(str(name)) f = Frob("bamf") f.bar # 'Frob does not have `bar` attribute.' f.bam # f'bamf'

__getattribute__

This method is called unconditionally when accessing the properties of an object. This method only works for new classes.
The new class is a class that integrates from object or type.

If the class is also defined at the same timeclass Dummy(object): def __getattribute__(self, attr): __dict__ = super(Dummy, self).__getattribute__('__dict__') if attr in __dict__: return super(Dummy, self).__getattribute__(attr) return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" print(d.does_not_exist) # "DOES_NOT_EXIST" 5), it will not be calledclass Dummy(object): def __getattribute__(self, attr): __dict__ = super(Dummy, self).__getattribute__('__dict__') if attr in __dict__: return super(Dummy, self).__getattribute__(attr) return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" print(d.does_not_exist) # "DOES_NOT_EXIST" 6 unlessclass Dummy(object): def __getattribute__(self, attr): __dict__ = super(Dummy, self).__getattribute__('__dict__') if attr in __dict__: return super(Dummy, self).__getattribute__(attr) return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" print(d.does_not_exist) # "DOES_NOT_EXIST" 7 shows the callclass Dummy(object): def __getattribute__(self, attr): __dict__ = super(Dummy, self).__getattribute__('__dict__') if attr in __dict__: return super(Dummy, self).__getattribute__(attr) return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" print(d.does_not_exist) # "DOES_NOT_EXIST" 6Or thrown class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 2. The method should return the property value or throw class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 2. To avoid infinite recursion in methods, you should always use the methods of the base class to get the properties:

class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.does_not_exist # 'DOES_NOT_EXIST' d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE' 0

grammar:val a_tuple = ("z", 3, "Python", -1) 1

Example:

class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.does_not_exist # 'DOES_NOT_EXIST' d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE' 1

__ get __

val a_tuple = ("z", 3, "Python", -1) 2The method is one of the descriptor methods. Descriptors are used to transform access object properties into call descriptor methods.

Example:

class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.does_not_exist # 'DOES_NOT_EXIST' d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE' 2

Conclusion

Magic Methods are a great mechanism to extend the basic features of Python classes and objects and provide more intuitive interfaces. You can provide dynamic attribute lookups with class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 1 for those missing attributes that you want to intercept. But be careful with class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.value = "Python" print(d.value) # "Python" 0, because it might be tricky to implement correctly without losing attributes in the Python void.

Postingan terbaru

LIHAT SEMUA