【问题标题】:Python - Returning list/ arry from functionPython - 从函数返回列表/数组
【发布时间】:2013-09-11 17:29:27
【问题描述】:

我正在编写一个小程序来列出可用的 USB 设备。我创建了一个带有函数的单独文件,以便可以随时从其他脚本访问它。此函数的主要目标是返回列表/数组作为输出。如果我使用 print 命令,它会成功打印可用设备的列表。但是,当我使用 return 命令时,它只会重新启动第一个检测到的设备。我已经解决了来自 SO 的其他类似问题,但找不到任何有效的解决方案。这是我尝试使用 dbus 的代码。任何帮助都会得到帮助。

#!/usr/bin/python2.7
import dbus

def find_usb(self):
    bus = dbus.SystemBus()
    ud_manager_obj = bus.get_object("org.freedesktop.UDisks", "/org/freedesktop/UDisks")
    ud_manager = dbus.Interface(ud_manager_obj, 'org.freedesktop.UDisks')

    for dev in ud_manager.EnumerateDevices():
        device_obj = bus.get_object("org.freedesktop.UDisks", dev)
        device_props = dbus.Interface(device_obj, dbus.PROPERTIES_IFACE)
        if device_props.Get('org.freedesktop.UDisks.Device', "DriveConnectionInterface") == "usb" and device_props.Get('org.freedesktop.UDisks.Device', "DeviceIsPartition"):
            if device_props.Get('org.freedesktop.UDisks.Device', "DeviceIsMounted"):
                device_file = device_props.Get('org.freedesktop.UDisks.Device', "DeviceFile")
                #print device_file
                return device_file

            else:
                print "Device not mounted"
find_usb("")

【问题讨论】:

  • 没有使用过 dbus,但据我所知,返回 device_file,你只是在第一次执行时返回,它不会让循环遍历所有可用的结果。在此处使用列表,这将起作用。 device_file 到底是什么?名称似乎令人困惑。请澄清一下?
  • device_file 是插入的usb的分区。在上面的脚本中,它只是一个字符串。当你执行脚本时,你会得到这样的输出“/dev/sdc1”

标签: python function return


【解决方案1】:

您将返回您匹配的第一个设备。而是建立一个列表并返回该列表:

def find_usb(self):
    bus = dbus.SystemBus()
    ud_manager_obj = bus.get_object("org.freedesktop.UDisks", "/org/freedesktop/UDisks")
    ud_manager = dbus.Interface(ud_manager_obj, 'org.freedesktop.UDisks')

    found = []

    for dev in ud_manager.EnumerateDevices():
        device_obj = bus.get_object("org.freedesktop.UDisks", dev)
        device_props = dbus.Interface(device_obj, dbus.PROPERTIES_IFACE)
        if device_props.Get('org.freedesktop.UDisks.Device', "DriveConnectionInterface") == "usb" and device_props.Get('org.freedesktop.UDisks.Device', "DeviceIsPartition"):
            if device_props.Get('org.freedesktop.UDisks.Device', "DeviceIsMounted"):
                device_file = device_props.Get('org.freedesktop.UDisks.Device', "DeviceFile")
                #print device_file
                found.append(device_file)

            else:
                print "Device not mounted"

    return found

return 语句立即结束函数;通过在循环中添加return,您此时退出函数并提前结束循环。

另一种方法是通过使用yield statement 将其设为生成器函数,以生成匹配项;然后,您可以只循环一次 self.find_usb() 的结果,但您将按需生成设备文件:

def find_usb(self):
    bus = dbus.SystemBus()
    ud_manager_obj = bus.get_object("org.freedesktop.UDisks", "/org/freedesktop/UDisks")
    ud_manager = dbus.Interface(ud_manager_obj, 'org.freedesktop.UDisks')

    for dev in ud_manager.EnumerateDevices():
        device_obj = bus.get_object("org.freedesktop.UDisks", dev)
        device_props = dbus.Interface(device_obj, dbus.PROPERTIES_IFACE)
        if device_props.Get('org.freedesktop.UDisks.Device', "DriveConnectionInterface") == "usb" and device_props.Get('org.freedesktop.UDisks.Device', "DeviceIsPartition"):
            if device_props.Get('org.freedesktop.UDisks.Device', "DeviceIsMounted"):
                device_file = device_props.Get('org.freedesktop.UDisks.Device', "DeviceFile")
                #print device_file
                yield device_file

            else:
                print "Device not mounted"

    return found

然而,生成器是一种更先进的技术。

【讨论】:

  • 这里的生成器会更 Pythonic。
  • @thg435:会的;但我担心这对 OP 来说可能有点过头了。
  • 我认为当内存效率成为问题时(例如迭代大型集合),生成器将是合适的。在这种情况下,一个列表可能就足够了。
  • @Martijn Pieters 和 pjama 您的两个解决方案都有效。我没想到在发布后几分钟内你的问题就会得到答案。非常感谢。
【解决方案2】:

您应该创建一个列表变量并将设备附加到它。然后在函数的最后,返回列表。

#!/usr/bin/python2.7
import dbus

def find_usb(self):
    devices = [] # instantiate empty list variable!
    bus = dbus.SystemBus()
    ud_manager_obj = bus.get_object("org.freedesktop.UDisks", "/org/freedesktop/UDisks")
    ud_manager = dbus.Interface(ud_manager_obj, 'org.freedesktop.UDisks')

    for dev in ud_manager.EnumerateDevices():
        device_obj = bus.get_object("org.freedesktop.UDisks", dev)
        device_props = dbus.Interface(device_obj, dbus.PROPERTIES_IFACE)
        if device_props.Get('org.freedesktop.UDisks.Device', "DriveConnectionInterface") == "usb" and device_props.Get('org.freedesktop.UDisks.Device', "DeviceIsPartition"):
            if device_props.Get('org.freedesktop.UDisks.Device', "DeviceIsMounted"):
                device_file = device_props.Get('org.freedesktop.UDisks.Device', "DeviceFile")
                #print device_file
                devices.append(device_file)

            else:
                print "Device not mounted"
    return devices

find_usb("")

【讨论】:

    【解决方案3】:

    即使理解代码的一个大问题是逻辑结构隐藏在很多缩进中。这是一个重写,保留了原始操作,同时允许看到结构。

    #!/usr/bin/python2.7
    import dbus
    
    def find_usb(self):
        ofud = 'org.freedesktop.UDisks' # convenience string for brevity
        bus = dbus.SystemBus()
    
        ud_manager_obj = bus.get_object(ofud, "/org/freedesktop/UDisks")
        ud_manager = dbus.Interface(ud_manager_obj, ofud)
    
        for dev in ud_manager.EnumerateDevices():
            device_obj = bus.get_object(ofud, dev)
            device_props = dbus.Interface(device_obj, dbus.PROPERTIES_IFACE)
            dp_get = device.props.Get   # convenience method for brevity
            if (dp_get(ofud, "DriveConnectionInterface") == "usb" and
                dp_get(ofud, "DeviceIsPartition")):
                if dp_get(ofud, "DeviceIsMounted"):
                    device_file = dp_get(ofud + '.Device', "DeviceFile")
                    print device_file
                    return device_file
                else:
                    print "Device not mounted"
                    return None         # implied
             else:
                 return None            # implied
        return None
    
    find_usb("")
    

    其他人已经充分回答了问题所在,但阅读困难无济于事。部分原因不是你的错,dbus 接口很冗长,但你可以像我对ofuddp_get 所做的那样驯服它。

    PEP-8 Style Guide for PythonPEP-20 The Zen of Python 的存在很大程度上是为了帮助您编写使错误更易于查看的代码。特别是,条件句的深层嵌套可以清理很多:

    if dp_get(ofud, 'DriveConnectionInterface') != 'usb':
        continue
    if dp_get(ofud, 'DeviceIsPartition') and dp_get(oufd, 'DeviceIsMounted'):
         device_file = dp_get(oufd + '.Device', "DeviceFile")
         found.append(device_file)
    

    由于您的原始代码不会对非 USB 设备执行任何操作,因此“快速失败”到循环的下一次迭代并跳过整个缩进级别会更清楚。当然还有其他方法可以使代码的意图更明显,我只是展示了一些。

    可读性很重要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-21
      • 1970-01-01
      • 2014-01-08
      • 1970-01-01
      • 1970-01-01
      • 2019-05-20
      • 1970-01-01
      相关资源
      最近更新 更多