Conditions | 13 |
Total Lines | 59 |
Lines | 0 |
Ratio | 0 % |
Tests | 41 |
CRAP Score | 13 |
Changes | 5 | ||
Bugs | 0 | Features | 1 |
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 Dictionary.update_value() 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 | """Converter classes for builtin container types.""" |
||
32 | 1 | def update_value(self, data, *, auto_track=True): |
|
33 | 1 | cls = self.__class__ |
|
34 | 1 | value = cls.create_default() |
|
35 | |||
36 | # Convert object attributes to a dictionary |
||
37 | 1 | attrs = common.attrs[cls].copy() |
|
38 | 1 | if isinstance(data, cls): |
|
39 | 1 | dictionary = {} |
|
40 | 1 | for k, v in data.items(): |
|
41 | 1 | if k in attrs: |
|
42 | 1 | dictionary[k] = v |
|
43 | 1 | for k, v in data.__dict__.items(): |
|
44 | 1 | if k in attrs: |
|
45 | 1 | dictionary[k] = v |
|
46 | else: |
||
47 | 1 | dictionary = to_dict(data) |
|
48 | |||
49 | # Map object attributes to types |
||
50 | 1 | for name, data2 in dictionary.items(): |
|
51 | |||
52 | 1 | try: |
|
53 | 1 | converter = attrs.pop(name) |
|
54 | 1 | except KeyError: |
|
55 | 1 | if auto_track: |
|
56 | 1 | converter = standard.match(name, data2, nested=True) |
|
57 | 1 | common.attrs[cls][name] = converter |
|
58 | else: |
||
59 | 1 | msg = "Ignored unknown nested file attribute: %s = %r" |
|
60 | 1 | log.warning(msg, name, data2) |
|
61 | 1 | continue |
|
62 | |||
63 | 1 | try: |
|
64 | 1 | attr = self[name] |
|
65 | 1 | except KeyError: |
|
66 | 1 | attr = converter.create_default() |
|
67 | |||
68 | 1 | if all((isinstance(attr, converter), |
|
69 | issubclass(converter, Container))): |
||
70 | 1 | attr.update_value(data2, auto_track=auto_track) |
|
71 | else: |
||
72 | 1 | attr = converter.to_value(data2) |
|
73 | |||
74 | 1 | value[name] = attr |
|
75 | |||
76 | # Create default values for unmapped types |
||
77 | 1 | for name, converter in attrs.items(): |
|
78 | 1 | value[name] = converter.create_default() |
|
79 | 1 | msg = "Default value for missing nested object attribute: %s = %r" |
|
80 | 1 | log.info(msg, name, value[name]) |
|
81 | |||
82 | # Execute custom __init__ validations |
||
83 | 1 | try: |
|
84 | 1 | cls(**value) |
|
|
|||
85 | 1 | except TypeError as exception: |
|
86 | 1 | log.warning("%s: %s", cls.__name__, exception) |
|
87 | |||
88 | # Apply the new value |
||
89 | 1 | self.clear() |
|
90 | 1 | self.update(value) |
|
91 | |||
215 |
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.