优雅地分配未知长度的变量

时间:2013-07-02 18:59:57

标签: python

(对不起。标题很不清楚。我想不出一个好的。)

说我有一个这样的网址(它是root-relative):

"/forums/support/windows/help_i_deleted_sys32/6/"

我试图把它分成这样的类结构:

class Forum_Spot:
    def __init__(self, url):
        parts = url.strip("/").split("/")
        #parts is now ["forums", "support", "windows", "help...", "6"]

        self.root = "forums"
        self.section = "support"
        self.subsection = "windows"
        self.thread = "help..."
        self.post = "6"

但是说我不知道​​网址到底有多长(可能是“/ forums / support /”,“/ forums / support / windows /”等)(但我知道它不会是任何深度超过5级)。任何人都可以想出一种优雅的方式来分配这些值,让任何未分配的部分都是None吗? (即“/ forums / support / windows /”,线程和帖子属性为None)

我知道我可以这样做:

class Forum_Spot:
    def __init__(self, url):
        parts = url.strip("/").split("/")
        #parts is now ["forums", "support", "windows", "help...", "6"]

        if len(parts) > 0:
            self.root = parts[0]
        else:
            self.root = None
        if len(parts) > 1:
            self.section = parts[1]
        else:
            #etc

但这显然是超级优雅和令人讨厌的劳动密集型。任何人都可以想到更优雅的解决方案,保持班级签名相同吗? (我可以转换__init__函数来获取关键字参数,默认为None,但我希望能够直接传入URL并让类自己解决这个问题)< / p>

谢谢!

4 个答案:

答案 0 :(得分:7)

使用序列解包:

>>> strs =  "/forums/support/"
>>> spl =strs.strip('/').split('/')
>>> a,b,c,d,e = spl + [None]*(5-len(spl))
>>> a,b,c,d,e
('forums', 'support', None, None, None)

>>> strs = "/forums/support/windows/"
>>> spl =strs.strip('/').split('/')
>>> a,b,c,d,e = spl + [None]*(5-len(spl))
>>> a,b,c,d,e
('forums', 'support', 'windows', None, None)

>>> strs = "/forums/support/windows/help_i_deleted_sys32/6/"
>>> spl =strs.strip('/').split('/')
>>> a,b,c,d,e = spl + [None]*(5-len(spl))
>>> a,b,c,d,e
('forums', 'support', 'windows', 'help_i_deleted_sys32', '6')

答案 1 :(得分:3)

您可以在类中添加一个设置适当默认值的setter方法:

class Forum_Spot:
    def __init__(self, url):
        parts = url.split('/')[1:]
        # use function argument unpacking:
        self.set_url(*parts)

    def set_url(self, root, section=None, subsection=None, thread=None, post=None):
        self.root = root
        self.section = section
        self.subsection = subsection
        self.thread = thread
        self.post = post

答案 2 :(得分:3)

我建议使用itertools.izip_longest(在Python 3中重命名为zip_longest)通过创建name, value元组来构建字典,并为None填写任何缺失值:< / p>

import itertools

names = ["root", "section", "subsection", "thread", "post"]
values = url.strip("/").split("/")

name_value_dict = dict(itertools.izip_longest(names, values))

现在您可以直接使用字典,如果需要在对象上创建成员变量,可以使用dict.update将其合并到现有字典中:

self.__dict__.update(name_value_dict)

答案 3 :(得分:1)

比moooeeeep更好的方法是使用namedtuple。 (或者更确切地说,是具有默认值的子类。)

from collections import namedtuple

class _Path(namedtuple('Path', 'root section subsection thread post')):
    def __new__(cls, root=None, section=None, subsection=None, thread=None, post=None):
        # add default values
        return super(_Path, cls).__new__(cls, root, section, subsection, thread, post)

Path = lambda s: _Path(*s.strip('/').split('/'))

然后......

>>> Path("/forums/support/")
_Path(root='forums', section='support', subsection=None, thread=None, post=None)