Elegantly assign variables of unknown length

(Sorry, the name is pretty obscure. I could not find a good one.)

Say I have a url like this (it is the root):

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

and I'm trying to break it down 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 I will say that I do not know how long the url will be displayed (it can be "/ forums / support /", "/ forums / support / windows /", etc.) (but I know that it wonโ€™t be deeper than 5 levels). Can anyone think of an elegant way of assigning these values โ€‹โ€‹without letting any part assign None ? (Ie for "/ forums / support / windows /", thread attributes and posts will be None)

I know I can 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 it is obviously supernatural and unpleasantly labor intensive. Can anyone think of a more elegant solution while keeping the class signature the same? (I could convert the __init__ function to take the keyword parameters, the default is None , but I would like to be able to just pass the URL and evaluate the class myself)

Thanks!

+4
source share
4 answers

Use unpacking sequence:

 >>> 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') 
+7
source

You can add the setter method to your class, which sets the appropriate default values:

 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 
+3
source

I suggest using itertools.izip_longest (renamed zip_longest in Python 3) to create a dictionary by creating name, value tuples when filling in None for any missing values:

 import itertools names = ["root", "section", "subsection", "thread", "post"] values = url.strip("/").split("/") name_value_dict = dict(itertools.izip_longest(names, values)) 

Now you can use the dictionary directly, if you need to create member variables on an object, you can use dict.update to combine it into an existing dictionary:

 self.__dict__.update(name_value_dict) 
+3
source

A fancier method other than moooeeeep would have to use namedtuple . (Or rather, a subclass of one with default values.)

 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('/')) 

And then...

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

Source: https://habr.com/ru/post/1489346/


All Articles