Naming: According to PEP8, you should make all these names snake_case. This is good, but the important bits here are:
- Do the same thing consistently
- Have a clear word seperator.
Basically, this means you can use snake_case, camelCase, or even TitleCase, but the last one is generally used only for classes. I'm personally partial to camelCase for functions/methods and snake_case for variables, but snake_case for both is more common, and that's what I'll be using here.
Most important, naming should be meaningful. What does this function do? It parses a list of strings, and returns part of those strings. You've called these strings names
, so we'll use something like that.
Also, keep names short. This makes it easier to read.
You first build a list, append to it, convert to a set, then convert to a list again to make them unique. In this case, I'd recommend to start out with a set. The role of this function is to figure out unique prefixes though - not full names.
def get_prefixes(long_names):
short_names = set() # set instead of list.
for name in long_names:
short_names.add(name[:3]) # Just slice a string if prefix length is constant.
return list(unique_names) # Use sorted() instead of list if you care about that.
# Can return right away. No need to reassign it first.
What else is easily noticeable? This is a rather straightforward loop. Python has a special tool to make this operation a bit easier: list/set/dict/generator comprehensions. Making this a set comprehension later cast to a list:
def get_prefixes(long_names):
return list({name[:3] for name in long_names})
# If you insist on regex:
def get_prefixes(long_names):
return list({re.search(r"[A-Z]{1}[a-z]{2}", name) for name in long_names})
That's a lot more shorter, and others reading your code can read it easier.
@Austin Hastings here goes into stdlib usage. If you're looking for performance, that's what you should do. If you're looking to write good production code, that's what you should do. However, I'm going to assume part of this is learning how to code, so I'll rewrite this function.
def uniquepattern(names):
[other stuff happens]
for singlepattern in unique_names:
dct['%s' % singlepattern] = []
Why do string % formatting here? There's no reason, since that list already contains strings and only strings. You can just use it as key. Or even better, combine it with the dict declaration:
dct = {key, [] for key in unique_names}
Now lets have a look at filling that dict:
for singelelist in names: # Spelling error here.
number = re.search(r"[A-Z]{1}[a-z]{2}", singelelist)
number = number.group()
for singlepattern in unique_names:
if number == singlepattern:
dct[singlepattern].append(singelelist)
That's a double iteration. I really can't figure out why we need that, since we can easily grab the prefixes from the names themselves:
for name in names:
dct[name[:3]].append(name)
And even if we need to use regexes to accomodate for variable prefix length, it's easy:
for name in names:
dct[re.search(r"[A-Z]{1}[a-z]{2}", name).group()].append(name)
This single loop means that we don't use unique_names
more than once, which means we can merge it into where it's used.
So for the entire function we get a much more modest:
def name_sorter(names):
dct = {key: [] for key in get_prefixes(names)}
for name in names:
dct[name[:3]].append(name)
return dct
And they say python code can't be concise...
So our full script would become:
def get_prefixes(long_names):
return list({name[:3] for name in long_names})
def name_sorter(names):
dct = {key: [] for key in get_prefixes(names)}
for name in names:
dct[name[:3]].append(name)
return dct
if __name__ == "__main__":
scaffold_names_list = ['Spp1Aa1', 'Spp1Aa1', 'Spp2Aa1', 'Spp3Aa1', 'Spp4Aa1', 'Spp5Aa1']
patterns = name_sorter(scaffold_names_list)
print(patterns)
Note that I included a if __name__ == "__main__":
guard. This means that other scripts can import this file without actually running any code, only making the functions available. But if any script is executed directly, python sets the __name__
variable to the string "__main__"
, and it is executed. This is widely considered good practice.