python __getattr__ help - PullRequest
       23

python __getattr__ help

1 голос
/ 16 января 2011

Читая книгу, я наткнулся на этот код ...

# 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 __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)

Он делает то, что я хочу, но я не понимаю функцию __getattr__ в классе Manager.Я знаю, что он делегирует все другие атрибуты из класса Person.но я не понимаю, как это работает.например почему из Person класса?как я явно не говорю это.человек (модуль отличается от человека (класс)

Любая помощь высоко ценится:)

Ответы [ 3 ]

2 голосов
/ 16 января 2011
  1. В вашем __init__ вы создаете экземпляр Person объекта, который присваивается self.person.

  2. Затем вы переопределяете поиск атрибутов в экземпляре Manager (реализуя __getattr__ для этого класса) и перенаправляете эти атрибуты для поиска в переменной self.person (которая является объектом Person из в данном конкретном случае).

Как упоминал Феликс Клинг в комментариях, было бы разумнее сделать Manager наследником от Person. В приведенном выше коде выглядит, что у менеджера есть человек, в то время как логичнее думать, что менеджер является человеком.

Вы могли бы сделать что-то вроде этого:

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
0 голосов
/ 17 января 2011

Помимо чтения Книги, вы можете обратиться к Книге , где вы могли бы найти довольно четкое объяснение того, как работают __getattr__() методы.

В двух словах, он вызывается, когда нет атрибутов с указанным именем, прикрепленных к объекту, к которому он применяется, а также к классу объекта или любому из его суперклассов.Другими словами, он вызывается, когда все остальное терпит неудачу.

В коде в вашем примере реализация __getattr_() эффективно перенаправляет поиск именованного атрибута на объект self.person, который является экземпляромкласс Person.

Также важно понимать, что __getattr_() - это первый шаг к доступу как к данным, так и к методам, связанным с любым объектом.

0 голосов
/ 16 января 2011

На самом деле, вы говорите это явно - не называя класс, а предоставляя экземпляр этого класса.

В методе init вы связываете self.person с экземпляром Person. Теперь каждый экземпляр Manager будет иметь этот элемент данных.

В __getattr__ вы делегируете встроенную функцию getattr с self.person в качестве первого аргумента. Независимо от типа self.person, он будет искать члена с заданным именем.

...