4

(Sorry. The title's pretty unclear. I couldn't come up with a good one.)

Say I have a url like so (it's root-relative):

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

and I'm trying to split this into a class structure like this:

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"

but say I don't know how long exactly the url will be (it could be "/forums/support/", "/forums/support/windows/", etc) (but I do know it won't be any deeper than 5 levels). Can anybody think of an elegant way to assign these values, letting any parts not assigned be None? (I.e. for "/forums/support/windows/", the thread and post attributes would be None)

I know I could do this:

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

but this is obviously superinelegant and obnoxiously labor-intensive. Can anybody think of a more elegant solution, keeping the class signature the same? (I could convert the __init__ function to take keyword parameters, defaulting to None, but I'd like to be able to just pass in the url and have the class figure it out on its own)

Thanks!

4

4 回答 4

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')
于 2013-07-02T19:03:22.553 回答
3

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

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)
于 2013-07-02T23:36:58.267 回答
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
于 2013-07-02T19:10:26.673 回答
1

一种比 moooeeeeep 更好的方法是使用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)
于 2013-07-02T20:18:14.017 回答