如何将实例强制转换为派生类?

时间:2009-07-13 15:28:24

标签: python oop inheritance

我正在尝试在我正在使用的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()方法相同,但UnapprovedUser中的get()方法需要返回UnapprovedUser对象,而不是用户。

如何将我从User.get()获得的用户实例之一投射到未经批准的用户?

我想做类似的事情:

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值,这会破坏一切。

5 个答案:

答案 0 :(得分: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中,类对象是一个可调用的,用于构造该类的实例。因此,您可以使用classmethod的cls参数来构造用于调用classmethod的类的实例。

答案 1 :(得分:1)

Python是一种动态类型语言,因此不存在“强制转换”的概念。如果对象已经是UnapprovedUser,那么您可以调用该类中存在的所有方法,而无需进行强制转换。

答案 2 :(得分:1)

在类方法中,类在cls参数中传入。因此,而不是User.something做cls.something。完成!

那就是说,我不确定我会用两种类型的用户来做这件事。我不是100%肯定你在这里说“批准”是什么意思,我觉得我是两件事之一。

  1. 这可能意味着用户尚未真正登录。在这种情况下,我有一个特殊的匿名用户实例,用于未登录的用户。由于您在批准时移动DN,因此这似乎更像是您正在做的事情。

  2. 这可能意味着用户尚未被批准为正式会员或其他内容。这只是权限处理的一个特例,您可能最终希望以后拥有更多权限。我会添加对提供用户角色的支持,并使“已批准”成为一个角色。

  3. 如果您的意思是批准的其他内容,请随意忽略这一点。 : - )

答案 3 :(得分:1)

  • super(UnapprovedUser,self)错了它应该是super(UnapprovedUser,cls),因为在类方法中你没有自己的可用

  • 我将重申你的问题,在基类中你正在创建用户,不知何故你想要返回派生类,例如


   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")

它打印User对象而不是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对象

答案 4 :(得分:0)

class A:
 def __init__(self, variable):
    self.a = 10
    self.a_variable = variable

 def do_something(self):
    print("do something A")


class B(A):

 def __init__(self, variable=None):
    super().__init__(variable)
    self.b = 15

 @classmethod
 def from_A(cls, a: A):
    # Create new b_obj
    b_obj = cls()
    # Copy all values of A to B
    # It does not have any problem since they have common template
    for key, value in a.__dict__.items():
        b_obj.__dict__[key] = value
    return b_obj

if __name__ == "__main__":
 a = A(variable="something")
 b = B.from_A(a=a)
 print(a.__dict__)
 print(b.__dict__)
 b.do_something()
 print(type(b))

结果:

{'a': 10, 'a_variable': 'something'}
{'a': 10, 'a_variable': 'something', 'b': 15}
do something A
<class '__main__.B'>