Домашни > The Old Man from Scene #24 > Решения > Решението на Стефан Иванов

Резултати
4 точки от тестове
1 точки от учител

5 точки общо

25 успешни теста
0 неуспешни теста
Код
Скрий всички коментари

  1import re
  2
  3
  4class BridgeKeeper:
  5    def __init__(self, module_name):
  6        self.module_name = module_name
  7        self.module = None
  8
  9    def __enter__(self):
 10        self.module = __import__(self.module_name)
 11        return FilteredModule(self.module)
 12
 13    def __exit__(self, exc_type, exc_value, traceback):
 14        return False
 15
 16
 17class FilteredModule:
 18    def __init__(self, module):
 19        self.module = module
 20
 21    def __getattr__(self, name):
 22        obj = getattr(self.module, name)
 23        if self.answers_first_question(obj) and self.answers_second_question(obj) and self.answers_third_question(obj):
 24            return obj
 25        raise AttributeError(name)
 26
 27    def answers_first_question(self, obj):
 28        name = getattr(obj, "__name__", None)
 29        return isinstance(name, str) and name and name[0].isupper()
 30
 31    def answers_second_question(self, obj):
 32        if not callable(obj):
 33            return False
 34        parameters = self.get_parameters(obj)
 35        parameter_names = [name for name, _ in parameters]
 36
 37        if parameter_names != self.get_real_parameter_names(obj):
 38            return False
 39        possible_arguments = [self.get_values(type_name) for _, type_name in parameters]
 40
 41        for arguments in self.make_combinations(possible_arguments):
 42            try:
 43                obj(*arguments)
 44            except Exception:
 45                return False
 46        return True
 47
 48    def answers_third_question(self, obj):
 49        for name in dir(obj):
 50            if self.is_valid_answer(name):
 51                return True
 52        return False
 53
 54    def get_parameters(self, obj):
 55        docstring = getattr(obj, "__doc__", None)
 56
 57        if not docstring:
 58            return []
 59
 60        match = re.search(
 61            r"Parameters\s*\n----------\s*\n(.*?)(?:\n\s*\n|\Z)",
 62            docstring,
 63            re.DOTALL
 64        )
 65
 66        if not match:
 67            return []
 68        parameters = []
 69        for line in match.group(1).splitlines():
 70            line = line.strip()
 71            if not line:
 72                continue
 73            name, type_name = line.split(":", 1)
 74            parameters.append((name.strip(), type_name.strip()))
 75        return parameters
 76
 77    def get_real_parameter_names(self, obj):
 78        if hasattr(obj, "__code__"):
 79            code = obj.__code__
 80            return list(code.co_varnames[:code.co_argcount])
 81
 82        if hasattr(obj, "__call__") and hasattr(obj.__call__, "__code__"):
 83            code = obj.__call__.__code__
 84            names = list(code.co_varnames[:code.co_argcount])
 85            if names and names[0] == "self":
 86                names = names[1:]
 87            return names
 88        return []
 89
 90    def get_values(self, type_name):
 91        parts = self.split_union(type_name)
 92        values = []
 93        for part in parts:
 94            values.append(self.get_value(part))
 95        return values
 96
 97    def get_value(self, type_name):
 98        type_name = type_name.strip()
 99
100        if type_name == "int":
101            return 1
102        if type_name == "float":
103            return 1.0
104        if type_name == "str":
105            return "a"
106        if type_name == "bool":
107            return True
108
109        list_match = re.fullmatch(r"list\[(.+)\]", type_name)
110        if list_match:
111            return [self.get_values(list_match.group(1))[0]]
112
113        tuple_match = re.fullmatch(r"tuple\[(.+)\]", type_name)
114        if tuple_match:
115            return (self.get_values(tuple_match.group(1))[0],)
116
117        set_match = re.fullmatch(r"set\[(.+)\]", type_name)
118        if set_match:
119            return {self.get_values(set_match.group(1))[0]}
120
121        dict_match = re.fullmatch(r"dict\[(.+),\s*(.+)\]", type_name)
122        if dict_match:
123            key_type = dict_match.group(1)
124            value_type = dict_match.group(2)
125            key = self.get_values(key_type)[0]
126            value = self.get_values(value_type)[0]
127            return {key: value}
128
129        return None
130
131    def split_union(self, type_name):
132        parts = []
133        current = ""
134        depth = 0
135
136        for symbol in type_name:
137            if symbol == "[":
138                depth += 1
139            elif symbol == "]":
140                depth -= 1
141
142            if symbol == "|" and depth == 0:
143                parts.append(current.strip())
144                current = ""
145            else:
146                current += symbol
147
148        parts.append(current.strip())
149        return parts
150
151    def make_combinations(self, values):
152        if not values:
153            return [[]]
154
155        result = []
156        for value in values[0]:
157            for combination in self.make_combinations(values[1:]):
158                result.append([value] + combination)
159        return result
160
161    def is_valid_answer(self, name):
162        if name.startswith("__") and name.endswith("__"):
163            return False
164        if re.search(r"[aeiouAEIOU]{4,}", name):
165            return False
166        match = re.search(r"[a-zA-Z](?=[^a-zA-Z]*$)", name)
167        return match is not None and match.group(0).isupper()

.........................
----------------------------------------------------------------------
Ran 25 tests in 0.002s

OK

Дискусия
История
Това решение има само една версия.