【问题标题】:How do I make an imported function call a new function?如何让导入的函数调用新函数?
【发布时间】:2012-10-21 12:13:46
【问题描述】:

经过几天的搜索和尝试不同的代码,我仍然无法找出我的问题。因此,我在这里发布了这个问题。

对于这个问题,我使用的是 Python 2.7.2 具体来说,我正在使用组合将一个类的功能导入另一个类。导入类的函数包括一个基于raw_input 的简单if 语句。根据用户的输入,if 语句应该以某种方式调用或至少有助于调用与输入对应的新函数。但是,此函数将位于正在导入的类的一部分中,而不是在导入的类中。

我在这里使用了两个 .py 文件,每个类一个,它们位于同一个文件夹中。

这是第一个文件(main.py),其中包括主类:

# importing class from file in same folder
from class_decision import Decision

class Main_Compositor(object):

    def __init__(self):
        # using composition to call the function of the imported class
        self.door_decision = Decision()

    def comp_door(self):
        self.door_decision.user_text()

        if door == "left":
            left_door()
        elif door == "right":
            right_door()
        else:
            print "incorrect input"

    def left_door(self):
        print "you're in the left room"

    def right_door(self):
        print "you're in the right room"


# instantiating
A_Compositor = Main_Compositor()

# calling A_Compositor's function comp_door()
A_Compositor.comp_door()

这里是 class_decision.py 文件,它的类正在被导入:

class Decision(object):

    def user_text(self):
        print "which door do you open:"
        print "left or right?"

        door = raw_input("> ")

        if door == "left":
            print "you have chosen the left door"
            return door
        elif door == "right":
            print "you have chosen the right door"
            return door
        else:
            print "you must choose a door"
            self.user_text()

如您所见,我正在尝试使用Return 让主类知道变量door。这可能是对Return 的错误使用。我也尝试过使用getattr,但没有成功。如果这个问题被问了很多,我很抱歉。我的类似问题似乎都与数组有关,我无法通过他们的回答真正找出我的问题。感谢您的帮助。

【问题讨论】:

  • 您的最后一个self.user_text() 应该是return self.user_text()。要解决您的问题,我认为您可以使用door = self.door_decision.user_text()
  • 谢谢,搅拌机。这似乎可以解决问题。
  • 作为一个次要的挑剔,您可能不应该调用实例A_Compositor,因为在其他任何地方您都遵循标题大写用于类,小写用于变量的命名约定。
  • 哦,好吧。我想既然A_Compositor 是一个类的实例,它也应该有类得到的大写字母。
  • 不,类实例是变量,就像整数一样。 (实际上,它有点复杂——变量只是名称,任何名称都可以包含整数、类实例,甚至是类本身……但你可能还不想学。)

标签: python function python-2.7 return


【解决方案1】:

但是,此函数将位于正在导入的类的一部分中,而不是正在导入的类中。

首先,这里有些混乱。您几乎总是在模块或脚本的顶层进行导入,而不是在类中——在相同的代码中肯定是这种情况——所以没有“正在导入的类”。至于“导入的类”,Python 实际上导入的是模块,而不是类。是的,你可以从一个模块中导入一个类……但是谈论导入类仍然令人困惑。此外,正如 Mark Amery 指出的那样,您有一个名为 class_decision 的模块这一事实意味着您认为类和模块之间必须存在紧密耦合,这在其他语言中可能是正确的,但在 Python 中则不然。几乎没有一个很好的理由来拥有一个具有这样名称的模块。

但我想我理解了这个问题:在class_decision.Decision.user_text 中,您想动态调用main_compositor.Main_Compositor.left_door()main_compositor.Main_Compositor.right_door(),而无需导入main_compositor

事实上,您希望它与任何 Compositor 对象一起使用,无论它是否为 Main_Compositor

执行此操作的一种方法(如 Eric 的回答中所述)是将“动作”从 Decision 方法移至调用者。只需报告(通过return)应该采取什么行动,并让调用者采取该行动。

但是,如果您想编写一个通用的 Decision 可以与几十个不同的合成器类中的任何一个一起使用,您不希望在这些类中的每一个中都复制 if choice == "left"… 逻辑。

请记住,每当您尝试使某些内容更通用或更抽象时,都会使编写和思考变得更加困难。如果您实际上并不需要这种灵活性,请不要编写它 - 使用 Eric 的答案,或者只是将两个类合并为一个。

但是如果你确实需要Decision.user_text 是通用的,并且对任何合成器调用它采取行动,你怎么做?

嗯,在 Python 或大多数其他语言中没有“调用我的对象”的概念。必须有人告诉方法要与哪个对象交谈。调用方法将self 的引用传递给user_text,或者包含对象将self 的引用传递给Decision 构造函数。这通常被称为“后向指针”(因为在旧语言中它实际上是一个指针,但在 Python 中则无关紧要)。

一旦您知道要与哪个对象对话,与它对话就变得微不足道了。如果你习惯了像 C++ 或 Java 这样的静态语言,那不是真的——你必须做一些棘手的事情,比如定义一个所有合成器都必须支持的接口,或者使用反射(比如getattr)来寻找按名称命名的方法。但是 Python 不是静态的。如果你有一个对象,它应该支持某种方法,你可以在它上面调用那个方法。

其实你可以从方法调用语法中看到两面:something.right_door()。您需要 something 对象,否则您无法调用该方法;一旦你有了它,调用该方法就是在其中放置一个点。

那么,您如何决定是将合成器传递给Decision 对象的构造函数,还是传递给user_text 的每个调用?这是基本类设计的一部分:Decision 的每个实例是否在其整个生命周期中都在单个合成器上工作?然后在构造函数中传递它。如果没有,请在方法调用中传递它。

这是后者的样子:

class Main_Compositor(object):
    ...
    def comp_door(self):
        self.door_decision.user_text(self)

class Decision(object):

    def user_text(self, compositor):
        print "which door do you open:"
        print "left or right?"

        door = raw_input("> ")

        if door == "left":
            print "you have chosen the left door"
            compositor.left_door()
        elif door == "right":
            print "you have chosen the right door"
            compositor.right_door()
        else:
            print "you must choose a door"
            self.user_text()

如果您想将后向指针存储为Decision 的一部分,则如下所示:

class Main_Compositor(object):

    def __init__(self):
        # using composition to call the function of the imported class
        self.door_decision = Decision(self)

    ...

class Decision(object):

    def __init__(self, compositor):

        self.compositor = compositor

    def user_text(self):
        print "which door do you open:"
        print "left or right?"

        door = raw_input("> ")

        if door == "left":
            print "you have chosen the left door"
            self.compositor.left_door()
        elif door == "right":
            print "you have chosen the right door"
            self.compositor.right_door()
        else:
            print "you must choose a door"
            self.user_text()

这里要记住的一件事是,它可能会混淆哪个对象是这里的所有者,哪个对象有反向引用。除了混淆人类读者,你甚至可以混淆解释器,导致内存泄漏。 (您可能需要查看weakref...)这是灵活性的代价之一。

值得注意的是,在您的示例中,实际上有一个您可以使用的全局变量。但这通常不是一个好的设计。在这种特殊情况下,使用全局变量不会获得额外的灵活性(只能有一个合成器),因此使 Decision 更复杂并没有获得任何好处。

【讨论】:

  • 为什么有人对这个答案投了反对票、反对票、反对票、反对票和反对票,而没有留下任何评论?
  • 感谢您的来信,阿巴纳特。我没有对你投反对票。我在我的第一个脚本的底部给出了一个Main_Compositor 的实例,带有A_Compositor = Main_Compositor()。你说得对,这里有些混乱。我才真正开始编程。
  • @Streeting:评论不是给你的,而是给一直在玩按钮的人……
  • 好吧,您的Decision 对象可以访问全局A_Compositor 对象,但这可能是个坏主意,因为所有通常的原因都是全局变量不好。如果Decision 或其方法需要与合成器交互,则应直接授予它们访问需要与之交互的合成器的权限。 (PS,作为初学者并不丢人;我们都曾在某个时候,你显然想学习,所以你不会很长时间。)
  • @abarnet 嘿。对不起,我的反对票。对此有两种想法,并且在改变主意的同时一直在写作。两个原因。首先,他在这里说他正在“导入”Decision 类是合法的。确实,这正是 Python 所说的:'from class_decision import Decision'。我同意 OP 似乎有些混乱,但我怀疑这源于不理解,与某些严格的 OO 语言不同,在 Python 中,模块和类之间没有一对一的关系——尤其是。给定“class_decision”模块名称。我觉得你的评论并没有找到问题的根源。
【解决方案2】:
def user_text(self):
    print "which door do you open:"
    print "left or right?"

    door = raw_input("> ")

    if door == "left":
        print "you have chosen the left door"
        return door
    elif door == "right":
        print "you have chosen the right door"
        return door
    else:
        print "you must choose a door"
        return self.user_text()  # don't forget to return in the recursion case
def comp_door(self):
    choice = self.door_decision.user_text()  # actually use the returned result

    if choice == "left":
        self.left_door()
    elif choice == "right":
        self.right_door()
    else:
        print "incorrect input"

【讨论】:

  • 这行得通,它最终可能是一个更好的设计,但它并没有告诉 OP 如何从“导入的类”调用“导入类”上的方法——这是完全可行的,一旦你理解了他所说的这些术语的意思。
  • @abarnert:我完全不明白 OP 在问什么。他们认为自己想做的事情的一个例子会有所帮助。
  • 谢谢,埃里克。我试了一下你的代码,但似乎我需要在调用left_door()right_door() 之前添加self 才能使其工作。
  • 我认为他想要做的是让决策对象的方法调用任何合成器调用它的方法。如果我是对的(从 OP 获得一些确认或矛盾会很好),这是一种间接获得相同效果的方法,只需传递一个合成器可以打开的字符串(OP 接近在他的示例代码中自己做对了)。但他也可以直接得到同样的效果。
  • 对不起,阿巴纳特,我对编程很陌生,所以我不确定你在问什么。为了指定我要查找的内容,我尝试在 comp_door(self) 中使用 if 语句,从 self.door_decision.user_text() 获取返回的变量,并根据该变量决定接下来调用哪个函数。 door 变量应该是 "left""right"。根据它是哪个字符串,调用left_door(self)right_door(self)
【解决方案3】:

在这里使用类没有意义,因为只有 一个 方法。

只需将Decision 变成一个函数。

【讨论】:

  • 这个答案没有回答问题,但它仍然是合理的建议。与像 Java 这样迂腐的面向对象语言不同,在 Python 中,不需要创建一个简单的类作为传递函数的工具。而是直接传递函数!
  • 感谢您的来信,罗兰。是的,可能没有必要像我一样写它。问题是,我只是在做不同的练习来更好地了解 Python。我在上面发布的代码是稍微复杂一点的脚本的简化版本。我只是想我会为我遇到的问题做一个简单的版本。
  • 您似乎在制作一种基于文本的冒险游戏?为简单起见,请考虑将知识折叠到数据中。所以程序逻辑可以简单而健壮。 (这称为表示规则)您可以例如创建一个由Node 对象组成的图表。每个节点都包含一个可能的选择列表(要采取的路线、要选择的对象、动作),每个动作与其他节点的连接。然后,运行冒险只是遍历节点图的问题。
  • 谢谢,马克和罗兰。 Roland,是的,我正在创建一个基于文本的冒险游戏。我没有听说过折叠知识的行为、表示规则或Node 对象。我一定会调查这些。
  • Node 这个名字是我编的。该概念的技术术语是有限状态机
猜你喜欢
  • 2022-07-01
  • 2015-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-02
相关资源
最近更新 更多