【问题标题】:What are functions within functions called in Python?Python中调用的函数中的函数是什么?
【发布时间】:2019-06-14 21:19:18
【问题描述】:

这将是一个非常n00b的问题......

在 python 中,我想编写一些函数来检索几种不同类型设备的软件版本和系统正常运行时间。我可以为每个需求编写一个函数,但我不想那样做。我想在函数中编写函数,所以我可以用点号来调用它们。

以下是我希望创建的函数示例:

get(device)   # Determine device type and get software version and uptime
get.version(device)   # Determine device type and get software version 
get.uptime(device)    # Determine device type and get device up time
get.cisco.version(device)   # Get software version for a Cisco device
get.cisco.uptime(device)   # Get device up time for a Cisco device
get.arris.version(device)   # Get software version for an Arris device
get.arris.uptime(device)   # Get device up time for an Arris device
get.motorola.version(device)   # Get software versino for a Motorola device
get.motorola.uptime(device)   # Get device up time for a Motorola device

所以,我会编写一个“get”函数,并在其中编写一个“version”、“uptime”、“cisco”、“arris”和“motorola”函数。在这些函数中,我会编写更多函数。

这在 Python 中叫什么?它是如何实施的?我只需要知道我在寻找什么,这样我就可以在文档中找到它并进行学习。

【问题讨论】:

  • 它们被称为“嵌套”函数,有时也被称为“本地”函数。
  • 你实际上不能在python中嵌套函数,不正确。如果您在 python 控制台上尝试它,您会发现尝试从外部函数外部访问嵌套函数会产生 AttributeError。
  • x/y 问题:似乎您可以使用属于该类的类和函数来做到这一点。在这种情况下,可以查看abc.AbstractBaseClass 并有几个类(cisco、arris 等)从您的抽象实现继承。

标签: python


【解决方案1】:

将这些概念化为嵌套方法声明有点奇怪,除非您使用限制性的 lambda,否则这在 python 中无法正常工作。这是您通常使用类来实现的功能类型,因为嵌套这些 确实 工作。因此,让我们将其实现为类!唯一的障碍是 get() 需要有点 hacky 才能让它按照你想要的方式工作,但我们可以解决这个问题。

class get:
    # inner class cisco
    class cisco:
        @staticmethod
        def version(device):
            # do stuff

        @staticmethod
        def uptime(device):
            # do stuff

    # inner class motorola
    class motorola:
        ...

    # inner class arris
    class arris:
        ...

    # and now we define the stuff for the get class itself
    # (after the inner classes, because we need them to be defined
    # before we refer to them in the below methods

    def __new__(cls, device):
        # this is *supposed* to return a new instance of a `get`. 
        # We can override that behavior and have it return other things when `get()` is invoked
        return (get.version(device), get.uptime(device))

    @staticmethod
    def version(device):
        # do stuff

    @staticmethod
    def uptime(device):
        # do stuff

这允许以下所有操作按预期运行:

get(device)
get.version(device)
get.cisco.uptime(device)

缺点是您必须显式地编写所有这些方法。如果您要嵌套这样的类,则不能将类 get 用作 get.ciscoget.motorola 或其他东西的超类。

我还在上面使用了@staticmethod,它允许您将方法放在类中,而无需使用额外的(隐式)clsself 参数。你可以替换

@staticmethod
def version(device)

@classmethod
def version(cls, device)

它的行为或多或少是一样的。

【讨论】:

    【解决方案2】:

    您可以使用嵌套函数,但这不是一个好主意。您可以使用前缀名称命名函数

    【讨论】:

      【解决方案3】:

      有多种方法可以做到这一点,这些嵌套函数的术语取决于您如何做到这一点。最直接的方法是将函数定义为 lambda:

      a = lambda dev: "a"
      a.b = lambda dev: "b"
      a.b.c = lambda dev: "c"
      
      print(a("foo"), a.b("bar"), a.b.c("baz"))
      

      输出:

      a b c
      

      这是一个稍微不那么做作的例子作为概念证明,尽管我没有声称这是一个好的设计(我想嵌套字典会更好,你的“后端”(字典)应该是即使您尝试这样做,也会以不同的方式组织)。

      devices = {"baz": "some device"}
      versions = {
          "motorola": "morotola thing",
          "arris": "arris thing",
          "cisco": "cisco thing"
      }
      cisco_versions = {"foo": "cisco foo thing"}
      
      get = lambda dev: devices[dev]
      get.version = lambda dev: versions[dev]
      get.cisco = lambda: ""
      get.cisco.version = lambda dev: cisco_versions[dev]
      
      print(get("baz"))
      print(get.version("arris"))
      print(get.cisco.version("foo"))
      

      输出:

      some device
      arris thing
      cisco foo thing
      

      您也可以按照Green Cloak Guy 的建议使用包含静态方法和嵌套类的类,但无论哪种方式,fluent interface 对客户来说仍然值得怀疑。我认为可以肯定地说它不是特别 Pythonic。

      【讨论】:

        猜你喜欢
        • 2020-10-10
        • 1970-01-01
        • 1970-01-01
        • 2018-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-19
        • 1970-01-01
        相关资源
        最近更新 更多