Python:如何通过作为参数传递的类对象来调用类方法

时间:2015-02-15 06:21:31

标签: python

我想将一个类作为参数传递给另一个类,然后调用我传递的类的方法,但是我得到了不同的错误。我从this开始,但我的代码一直给我错误。

考虑以下情况:

class A:
    A_class_var = "I am an A class variable"

    def __init__(self):
        self.A_inst_var = "I am an A instance variable"

    def GetClassVar(self):
        return A_class_var

    def GetInstVar(self):
        return self.A_inst_var

class B:

    def __init__(self, cls):
        print cls.GetClassVar()
        print cls.GetInstVar()

1)当我调用b = B(A)时,我得到一个“未绑定的方法”,必须使用A实例作为第一个参数调用GetClassVar()(不得取而代之)。“所以我认为GetClassVar()和GetInstVar()期望一个A实例,并尝试将cls添加到B __init__中两个调用的参数中。同样的错误。

2)当我尝试调用b = B(A())时,我收到错误“全局名称A_class_var”未定义。

3)当我尝试调用a = A()后跟b = B(a)时,我得到了与#2相同的错误。

4)当我尝试在上面链接的SO回答中提出建议时,即将B的定义更改为:

class B:
    def __init__(self, cls):
        self.my_friend = cls

    def GetFriendsVariables(self):
        print my_friend.GetClassVar()
        print my_friend.GetInstVar()

然后调用b = B(A)后跟b.GetFriendsVariables()(也跟着我链接了)我在GetFriendsVariables中收到错误“未定义全局名称my_friend”。

我真的很想了解如何正确地将类作为参数传递,以便我可以访问这些类的变量和方法,并且很想理解为什么我上面的各种尝试都不起作用(然而我发送的SO链接呢?)

非常感谢!

3 个答案:

答案 0 :(得分:4)

好。这里有很多要点! :)

  • 1)您是对的,GetClassVarGetInstVar确实需要A个实例。除非你这样做,否则你永远不会通过打电话给它来工作:

    class A:
    
        @classmethod
        def GetClassVar(cls):
            return cls.A_class_var # use `cls.` to get the variable
    

    如果您不熟悉,classmethod装饰器将允许您自动将该类作为第一个参数传递(而不是实例)。因此,现在可以保证调用前面带有类名的方法(如cls.GetClassVar())。


  • 2)由于口译员说的原因,你完全得到了这个错误。全局命名空间中没有声明A_class_var。请记住,它位于课程A内。这里有两个解决方案(一个是更隐式,另一个更明确)。

    <强>隐式:

    def GetClassVar(self):
        return self.A_class_var
    

    这是有效的,因为当您指定实例属性时,实例会搜索自己的__dict__,如果找不到该属性,则会搜索该类&#39; __dict__

    <强>显

    def GetClassVar(self):
        return self.__class__.A_class_var
    

    如您所见,可以直接从实例获取类对象。这将直接在类内部搜索属性,而不是先检查它是否存在于实例中。这样做的另一个好处是更清晰,并避免了实例和类属性名称可能相同的问题。

    更明确 :(扩展用户6502&#39;

    def GetClassVar(self):
        return A.A_class_var
    

    就个人而言,我并不喜欢这样做。不得不重复上课的名字对我来说感觉不对,但根据你的情况,这可能不是一件坏事。


  • 3)由于我刚刚概述的相同原因,您收到错误。

  • 4)由于与上述相同的原因,这再次没有好转。但是,您确实需要解决此问题:

    class B:
        def __init__(self, cls):
            self.my_friend = cls
    
        def GetFriendsVariables(self):
            print my_friend.GetClassVar() # should be: self.my_friend.GetClassVar()
            print my_friend.GetInstvar() # should be: self.my_friend.GetInstvar()
    

    请注意,您仍需要将my_friend变量添加到self.之前。但正如我告诉你的那样,这样称呼会得到相同的结果。问题在于您如何定义方法GetClassVar()。您将看到如果您使用@classmethod装饰器(或传递实例并将属性提取更改为我上面给出的两个解决方案中的任何一个 - 隐式或显式形式) ,它会开始工作。 ;)

答案 1 :(得分:0)

直接调用可能不起作用,但您可以使用getattr和hasattr使其正常工作。

class A:
    A_class_var = "I am an A class variable"

    def __init__(self):
        self.A_inst_var = "I am an A instance variable"

    @staticmethod  # If it's a classmethod, use the staticmethod to decorate the method
    def GetClassVar(cls):
        return cls.A_class_var

    def GetInstVar(self):
        return self.A_inst_var


class B:
    def __init__(self, cls):
        if hasattr(cls, "GetClassVar"):
            func = getattr(cls, "GetClassVar")
            func(cls)
        b = cls()
        b.GetInstVar()

if __name__ == '__main__':
    b  = B(A)

答案 2 :(得分:0)

Python范围规则与C ++不同。更具体地说,在访问实例成员时,您必须明确使用self.<membername>,在访问类成员时还必须明确使用<classname>.<membername>

class A:
    A_class_var = "I am an A class variable"

    def __init__(self):
        self.A_inst_var = "I am an A instance variable"

    def GetClassVar(self):
        return A.A_class_var

    def GetInstVar(self):
        return self.A_inst_var

class B:
    def __init__(self, cls):
        print cls.GetClassVar()
        print cls.GetInstVar()

通过这个小的更改A.A_class_var,代码可以按预期工作