Conditions | 14 |
Total Lines | 55 |
Lines | 0 |
Ratio | 0 % |
Tests | 21 |
CRAP Score | 14.3828 |
Changes | 4 | ||
Bugs | 0 | Features | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like Message.__init__() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | """StarStruct class.""" |
||
16 | 1 | def __init__(self, name, fields, mode=starstruct.modes.Mode.Native, alignment=1): |
|
17 | """ |
||
18 | Initialize a StarStruct object. |
||
19 | |||
20 | Creates 2 internal items, a format string which is used to call the |
||
21 | struct module functions for packing and unpacking data, and a |
||
22 | namedtuple instance which is used to organize the data provided to the |
||
23 | pack functions and returned from the unpack functions. |
||
24 | """ |
||
25 | |||
26 | # The name must be a string, this is provided to the |
||
27 | # collections.namedtuple constructor when creating the namedtuple class. |
||
28 | 1 | if not name or not isinstance(name, str): |
|
29 | 1 | raise TypeError('invalid name: {}'.format(name)) |
|
30 | |||
31 | 1 | self._name = name |
|
32 | 1 | self.mode = mode |
|
33 | 1 | self.alignment = alignment |
|
34 | |||
35 | # The structure definition must be a list of |
||
36 | # ('name', 'format', <optional>) |
||
37 | # tuples |
||
38 | 1 | if not isinstance(fields, list) \ |
|
39 | or not all(isinstance(x, tuple) for x in fields): |
||
40 | raise TypeError('invalid fields: {}'.format(fields)) |
||
41 | |||
42 | 1 | if not isinstance(mode, starstruct.modes.Mode): |
|
43 | 1 | raise TypeError('invalid mode: {}'.format(mode)) |
|
44 | |||
45 | # Create an ordered dictionary (so element order is preserved) out of |
||
46 | # the individual message fields. Ensure that there are no duplicate |
||
47 | # field names. |
||
48 | 1 | self._elements = collections.OrderedDict() |
|
49 | 1 | for field in fields: |
|
50 | 1 | if field[0] not in self._elements: |
|
51 | 1 | if isinstance(field[0], str): |
|
52 | 1 | self._elements[field[0]] = Element.factory(field, mode, alignment) |
|
53 | 1 | elif isinstance(field[0], bytes): |
|
54 | 1 | self._elements[field[0].decode('utf-8')] = Element.factory(field, mode, alignment) |
|
55 | else: |
||
56 | raise NotImplementedError |
||
57 | else: |
||
58 | raise TypeError('duplicate field {} in {}'.format(field[0], fields)) |
||
59 | |||
60 | # Validate all of the elements of this message |
||
61 | 1 | for elem in self._elements.values(): |
|
62 | 1 | elem.validate(self._elements) |
|
63 | |||
64 | # Give each element information about the other elements |
||
65 | 1 | elem._elements = self._elements |
|
66 | |||
67 | # Now that the format has been validated, create a named tuple with the |
||
68 | # correct fields. |
||
69 | 1 | named_fields = [elem.name for elem in self._elements.values() if elem.name] |
|
70 | 1 | self._tuple = StarTuple(self._name, named_fields, self._elements) |
|
71 | |||
186 |
Generally, there is nothing wrong with usage of
*
or**
arguments. For readability of the code base, we suggest to not over-use these language constructs though.For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.