1

I have created a script that stores and edits meta-data in a system. I am now cleaning up my code by defining a class and methods, previously I only used separate functions.

In the script I am storing old and new values of certain types of metadata in lists, which I print out after the script has completed its run. I have defined multiple lists (16 to be exact), which I realized is quite a lot when passing them through a method. I was wondering what is the most pythonic way to approach this.

These are the following list variables that i define in the beginning. In the function/method I append values to them. In the end I print the stored valued out as a report.

split_name = []
split_name_new = []
name = []
name_new = []
meta = []
meta_new = []
series = []
series_new = []
product = []
owner = []
desc = []
desc_new = []
keywords = []
keywords_new = []
no_edit_page =[]
no_edit_page_name = []

In a class i figured it will look something like (if I define all the list separately)

class Metadata_editor():
    def __init__(self,url):

        self.split_name = [] 
        self.split_name_new = []
        self.name = []
        self.name_new = []
        self.meta = []
        self.meta_new = []
        self.series = []
        self.series_new = []
        self.product = []
        self.owner = []
        self.desc = []
        self.desc_new = []
        self.keywords = []
        self.keywords_new = []
        self.no_edit_page =[]
        self.no_edit_page_name = []

        #Ugly solution because the method gets crowded by all the variables passed through
        def data_edit(self, split_name, split_name_new, name, name_new,.. etc):
            #Not the whole method, but just to give some idea..
            #Selenium function that locates meta
            md = driver.find_element_by_xpath("//input[@name='metadata-name']") 
            meta_data = md.get_attribute("value")
            #replace_words translate the word using a dictionary object
            meta_data_new = replace_words(meta_data,c) 
            meta.append(meta_data)
            meta_new.append(meta_data_new)

The solution above I realized would not be ideal.

I found an alternative way that I could use, which is I define a list of lists. The solution would then look something like this (see below). However 'data_list[10]' is not as self-explanatory as for say 'owner'. My question is, is this the 'best' way to solve this, or do you have any other suggestions? I don't really have anything against this solution, but was wondering if there is a more 'pythonic' way to approach this.

class Metadata_editor():
    def __init__(self,url):
        self.data_list=[[] for _ in range(16)] #Creates a list, that contains 16 lists

    # More eloquent solution, as only one variable is passed through. However finding 
    # the right data from data_list is perhaps not as easy before 
    def data_edit(self, data_list): 

        md = driver.find_element_by_xpath("//input[@name='metadata-name']")
        meta_data = md.get_attribute("value")
        meta_data_new = replace_words(meta_data,c)
        data_list[5].append(meta_data)
        data_list[6].append(meta_data_new)
1
  • 1
    Why would you need to pass them as they are part of self? Commented Sep 20, 2019 at 15:26

3 Answers 3

2

You could store it as a dictionary. That would have the advantage of being able to reference the keys by name rather than having to remember the indexes.

class Metadata_editor():
    def __init__(self, url):
       keys = [
            'split_name', 'split_name_new', 'name', 'name_new' 'meta', 'meta_new',
            'series', 'series_new', 'product', 'owner', 'desc', 'desc_new',
            'keywords', 'keywords_new', 'no_edit_page', 'no_edit_page_name',
        ]
        self.data_dict = dict((x, []) for x in keys)

    def data_edit(self):
        md = driver.find_element_by_xpath("//input[@name='metadata-name']")
        meta_data = md.get_attribute("value")
        meta_data_new = replace_words(meta_data,c)
        self.data_dict['meta'].append(meta_data)
        self.data_dict['meta_new'].append(meta_data_new)

A few extra points to note:

  • class names generally follow the UpperCaseCamelCase convention. So Metadata_editor would more conventionally be written as MetadataEditor
  • Using self sets an attribute on the class, it can be accessed in the class using self and the attribute does not need to be passed into the method. I have shown this in the example above, accessing self.data_dict in the data_edit method.
  • You can also use setattr to set attributes to the class as shown in some of the other answers.
Sign up to request clarification or add additional context in comments.

Comments

1

You can initialize multiple lists as below:

class Metadata_editor():
    def __init__(self,list_names):
        [setattr(self,name,[]) for name in list_names]
me = Metadata_editor(['split_name','split_name_new']) # initialize two lists
me.split_name.append(5) # add value to a list
print(me.split_name, me.split_name_new)

>>[5], [ ]


Once set as part of the class via self.list_name, the list(s) can be accessed globally within the class - no longer requiring to be 'passed in'. To initialize lists to specific values, you can do:

def __init__(self,list_names,list_values):
    [setattr(self,name,value) for name,value in zip(list_names,list_values)]

Comments

1

Use setattr:

...
def __init__(self, url):
    names = '''split_name split_name_new name
        name_new meta meta_new series series_new
        product owner desc desc_new keywords
        keywords_new no_edit_page
        no_edit_page_name'''.split()
    for name in names:
        setattr(self, name, [])
...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.