Как вы приведете экземпляр к производному классу? - PullRequest
11 голосов
/ 13 июля 2009

Я пытаюсь использовать небольшое наследование в программе Python, над которой я работаю. У меня есть базовый класс User, который реализует все функциональные возможности пользователя. Я добавляю концепцию неутвержденного пользователя, которая похожа на пользователя, с добавлением одного метода.

В классе User есть несколько методов, которые возвращают объект User. Это не будет работать, когда я создаю подкласс, так как в конечном итоге UnapprovedUser вернет User, что, помимо прочего, не позволит мне вызывать этот метод.

class User(object):
    base_dn = 'ou=Users,dc=example,dc=org'

    @classmethod
    def get(cls, uid):
        ldap_data = LdapUtil.get(uid + ',' + self.base_dn)
        return User._from_ldap(ldap_data)

class UnapprovedUser(User):
    base_dn = 'ou=UnapprovedUsers,dc=example,dc=org'

    def approve(self):
        new_dn = '' # the new DN
        LdapUtil.move(self.dn, new_dn)

Методы get() и _from_ldap() одинаковы для обоих классов, хотя метод get() в UnapprovedUser должен возвращать объект UnapprovedUser, а не User.

Как я могу привести один из экземпляров User, полученных из User.get(), в UnapprovedUser?

Я хочу сделать что-то вроде:

class UnapprovedUser(User):
    # continued from before

    @classmethod
    def get(cls, uid):
        user = super(UnapprovedUser, cls).get(uid)
        return (UnapprovedUser) user # invalid syntax

чтобы я мог обернуть метод от родителя и просто привести возвращенное значение к правильному классу. Опять же, если вы сделаете это таким образом, родитель может использовать свое значение для self.base_dn, что сломает все.

Ответы [ 4 ]

9 голосов
/ 13 июля 2009

Вместо "приведения" я думаю, что вы действительно хотите создать UnapprovedUser вместо User при вызове UnapprovedUser.get(). Для этого:

Измените User.get, чтобы фактически использовать переданный аргумент cls:

@classmethod
def get(cls, uid):
    ldap_data = LdapUtil.get(uid + ',' + self.base_dn)
    return cls._from_ldap(ldap_data)

Вам нужно будет сделать нечто подобное в _from_ldap. Вы не перечислили код для _from_ldap, но я предполагаю, что в какой-то момент он делает что-то вроде:

result = User(... blah ...)

Вы хотите заменить это на:

result = cls(... blah ...)

Помните: в Python объект класса является вызываемым, который создает экземпляры этого класса. Таким образом, вы можете использовать параметр cls метода класса для создания экземпляров класса, используемого для вызова метода класса.

1 голос
/ 13 июля 2009
  • super (UnapprovedUser, self) не так, это должно быть super (UnapprovedUser, cls), потому что в методе класса у вас нет self доступного

  • Я повторю ваш вопрос: в базовом классе вы создаете пользователя и каким-то образом хотите вернуть производный класс, например


   class User(object):

       @classmethod
       def get(cls, uid):
           return User()

   class UnapprovedUser(User):

       @classmethod
       def get(cls, uid):
           user = super(UnapprovedUser, cls).get(uid)
           return user # invalid syntax

   print UnapprovedUser.get("XXX")

печатает объект пользователя вместо объекта UnapprovedUser здесь вы хотите, чтобы UnapprovedUser.get возвращал UnapprovedUser, для этого вы можете создать фабричную функцию, которая вернет соответствующего пользователя и затем заполнит его ldap


    class User(object):

        @classmethod
        def get(cls, uid):
            return cls.getMe()

        @classmethod
        def getMe(cls):
            return cls()

    class UnapprovedUser(User):

        @classmethod
        def get(cls, uid):
            user = super(UnapprovedUser, cls).get(uid)
            return user 

    print UnapprovedUser.get("XXX")

печатает объект UnapprovedUser

1 голос
/ 13 июля 2009

В методе класса класс передается в параметре cls. Так что вместо User.something делайте cls.something. Готово!

Тем не менее, я не уверен, что сделал бы это с двумя типами пользователей. Я не уверен на 100%, что вы имеете в виду под словом «Одобрено», мне кажется, это одна из двух вещей.

  1. Это может означать, что пользователь еще не вошел в систему. В этом случае у меня был бы специальный экземпляр Anonymous User для не авторизованных пользователей. Поскольку вы перемещаете DN при утверждении, скорее всего, это то, что вы делаете.

  2. Это может означать, что пользователь не был утвержден в качестве полноправного члена или что-то в этом роде. Это всего лишь особый случай обработки разрешений, и вы, вероятно, в конечном итоге захотите получить больше разрешений позже. Вместо этого я бы добавил поддержку для предоставления пользовательских ролей и создания роли «Утверждено».

Если вы имеете в виду что-то еще с одобренным, не стесняйтесь игнорировать это. : -)

1 голос
/ 13 июля 2009

Python - это язык с динамической типизацией, поэтому понятия «приведение» не существует. Если объект уже является UnapprovedUser, то вы уже можете вызывать все методы, существующие в этом классе, без приведения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...