Вопрос по oop, inheritance, python – Как вы приведете экземпляр к производному классу?

10

Я пытаюсь использовать небольшое наследование в программе 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.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   ответа
1
  • super(UnapprovedUser, self) is wrong it should be super(UnapprovedUser, cls) because in class method you do not have self available

  • I will reiterate your question , in base class you are creating user and somehow you want to return derived class e.g.


   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

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

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

  1. It may mean the user isn't really logged in yet. In that case I'd have a special Anonymous User instance for not logged in users. Since you are moving the DN when approving, this seems more likely to be what you are doing.

  2. It may mean that the user hasn't been approved as a full member or something. This is just a special case of permission handling, and you are probably going to end up wanting to have more permissions later. I'd instead add support for giving the user roles, and making "Approved" a role.

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

У меня есть простая структура каталогов LDAP, в которой я собираюсь хранить пользователей. Ou = Users используется "Approved" пользователи. Приложения, которые ищут в каталоге информацию для входа, смотрят только в ou = Users. У меня также есть способ для пользователя запрашивать доступ к этим приложениям, когда они требуют одобрения администратора, прежде чем они смогут войти в систему. В этом случае они создаются в ou = UnapprovedUsers и перемещаются в ou = Users, использующихapprove() метод. Таким образом, никаких дополнительных уровней не потребуется. Chris Lieb
Хорошо, тогда принцип имеет смысл. (Хотя, конечно, наличие метода одобрения для стандартного пользователя не повредит, поэтому вам могут не понадобиться два разных класса).
9

Вместо "кастинга" я думаю, что вы действительно хотите создать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 Параметр метода класса для создания экземпляров класса, используемого для вызова метода класса.

Именно то, что я искал. Благодарю. Наверное, я никогда не замечал, что вы можете сделать это с помощью параметра cls для метода класса. Chris Lieb
1

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

& Quot; Casting & Quot; это немного двусмысленный термин (отсюда и n различных типов приведения в C ++), но, безусловно, есть что-то вроде хотя бы одной формы приведения в преобразовании Python: type Например: я мог бы представить, что кто-то говорит, что str (x) «бросает» x в str (хотя я думаю, что большинство людей пойдет на более явное «преобразование», а не «приведение»).
Проблема в том, что я возвращаю пользователя, но мне нужно, чтобы он был UnapprovedUser, чтобы я мог вызывать этот метод. Я не хочу дублировать код, если мне это не нужно. Chris Lieb

Похожие вопросы