开发者

python __getattr__ help

开发者 https://www.devze.com 2023-02-04 07:05 出处:网络
Reading a Book, i came across this code... # module person.py class Person: def __init__(self, name, job=None, pay=0):

Reading a Book, i came across this code...

# module person.py

class Person:

    def __init__(self, name, job=None, pay=0):
        self.name = name
        self.job  = job
        self.pay  = pay

    def lastName(self):
        return self.name.split()[-1]

    def giveRaise(self, percent):
        self.pay = int(self.pay *(1 + percent))

    def 开发者_如何学Python__str__(self):
        return "[Person: %s, %s]" % (self.name,self.pay)

class Manager():
    def __init__(self, name, pay):
        self.person = Person(name, "mgr", pay)

    def giveRaise(self, percent, bonus=.10):
        self.person.giveRaise(percent + bonus)

    def __getattr__(self, attr):
        return getattr(self.person, attr)

    def __str__(self):
        return str(self.person)

It does what I want it to do, but i do not understand the __getattr__ function in the Manager class. I know that it Delegates all other attributes from Person class. but I do not understand the way it works. for example why from Person class? as I do not explicitly tell it to. person(module is different than Person(class)

Any help is highly appreciated :)


  1. In your __init__ you instantiate a Person object which gets assigned to self.person.

  2. You then override attribute lookups on the Manager instance (by implementing __getattr__ for this class) and redirect these attributes to be looked up on the self.person variable instead (which is the Person object from 1 in this particular case).

Like Felix Kling mentioned in the comments, it would make more sense to make Manager inherit from Person. In the current code above, it looks like the manager has a person while it's more logical to think that the manager is a person.

You could do something like this:

class Person(object):

    def __init__(self, name, job=None, pay=0):
        self.name = name
        self.job = job
        self.pay = pay

    def give_raise(self, percent):
        self.pay = int(self.pay *(1 + percent))

    def __str__(self):
        return "[Person: %s, %s]" % (self.name, self.pay)

class Manager(Person):

    def __init__(self, name, pay):
        super(Manager, self).__init__(name, "mgr", pay)

    def give_raise(self, percent, bonus=.10):
        self.pay = int(self.pay * (1 + (percent + bonus)))

# example usage
John = Person("John", "programmer", 1000)
Dave = Manager("Dave", 2000)
print John, Dave
John.give_raise(.20)
Dave.give_raise(.20)
print John, Dave


Actually, you do tell it explicitly - not by naming the class, but by providing an instance of that class.

In the init method, you bind self.person to an instance of Person. Now, every Manager instance will have this data member.

In __getattr__, you are delegating to the getattr builtin with self.person as the first argument. Regardless of the type of self.person, it will look for a member with the given name.


Beside reading a Book, you might want to consult The Book where you could have found a pretty clear explanation of how __getattr__() methods work.

In a nutshell, it gets called when there are no attributes of the specified name attached to the object it's being applied to, and also not to the object class or any of it's superclasses. In other words, it called when all else fails.

In the code in your example, the implementation of __getattr_() effectively redirects the search for the named attribute onto the self.person object, which is an instance of the Person class.

It also important to understand that __getattr_() is the first step in accessing both the data and the methods associated with any object.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号