timeit

Програмиране с Python

Курс във Факултета по Математика и Информатика към СУ

Решение на Аритметични изрази от Христо Ралев

Обратно към всички решения

Към профила на Христо Ралев

Резултати

  • 9 точки от тестове
  • 0 бонус точки
  • 9 точки общо
  • 18 успешни тест(а)
  • 1 неуспешни тест(а)

Код

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import operator
import itertools

primitive_types = int, float, complex


class Expression:

    def __init__(self, expression):
        self.expression = expression
        self.variable_names = tuple(itertools.chain(
            *[expr.variable_names for expr in self.expression if isinstance(expr, Expression)]))

    def evaluate(self, **variables):
        lhs, op, rhs = self.expression
        if not(isinstance(lhs, primitive_types)):
            lhs = lhs.evaluate(**variables)
        if not(isinstance(rhs, primitive_types)):
            rhs = rhs.evaluate(**variables)

        self.value = op.evaluate(lhs, rhs)
        return self.value

    def __str__(self):
        return '({})'.format(' '.join([str(expr) for expr in self.expression]))

    def __oper(self, other, expressionOp, primitiveOp):
        if isinstance(other, primitive_types):
            return primitiveOp(self, create_constant(other))
        return create_expression((self, expressionOp, other))

    def __roper(self, other, expressionOp, primitiveOp):
        if isinstance(other, primitive_types):
            return primitiveOp(create_constant(other), self)
        return create_expression((other, expressionOp, self))

    def __add__(self, other):
        return self.__oper(other, plus, operator.add)

    def __sub__(self, other):
        return self.__oper(other, minus, operator.sub)

    def __mul__(self, other):
        return self.__oper(other, times, operator.mul)

    def __truediv__(self, other):
        return self.__oper(other, div, operator.truediv)

    def __radd__(self, other):
        # same as self + other in evaluating, but different in printing
        return self.__roper(other, plus, operator.add)

    def __rsub__(self, other):
        return self.__roper(other, minus, operator.sub)

    def __rmul__(self, other):
        # same as self * other in evaluating, but different in printing
        return self.__roper(other, times, operator.mul)

    def __rtruediv__(self, other):
        return self.__roper(other, div, operator.truediv)


class Constant(Expression):

    def __init__(self, value):
        self.value = value
        self.variable_names = ''

    def evaluate(self, **kwargs):
        return self.value

    def __str__(self):
        return str(self.value)


class Variable(Expression):

    def __init__(self, name):
        self.name = name
        self.variable_names = self.name

    def evaluate(self, **args):
        return args.get(self.name, '')

    def __str__(self):
        return self.name


class Operator(Expression):

    def __init__(self, symbol, function):
        self.symbol = symbol
        self.function = function
        self.variable_names = ''

    def evaluate(self, lhs, rhs):
        return self.function(lhs, rhs)

    def __str__(self):
        return self.symbol


def create_expression(expression_structure):
    actual_expr_str = ()
    for expr in expression_structure:
        if hasattr(expr, '__iter__'):
            expr = create_expression(expr)
        actual_expr_str += expr,
    return Expression(actual_expr_str)


def create_constant(value):
    return Constant(value)


def create_variable(name):
    return Variable(name)


def create_operator(symbol, function):
    return Operator(symbol, function)


plus = create_operator('+', operator.add)
minus = create_operator('-', operator.sub)
times = create_operator('*', operator.mul)
div = create_operator('/', operator.truediv)

Лог от изпълнението

................E..
======================================================================
ERROR: test_variables_and_constants_extra_operators (test.TestNativeOperators)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/data/rails/pyfmi-2016/releases/20160307095126/lib/language/python/runner.py", line 67, in thread
    raise result
TypeError: unsupported operand type(s) for ** or pow(): 'Variable' and 'Variable'

----------------------------------------------------------------------
Ran 19 tests in 0.118s

FAILED (errors=1)

История (5 версии и 3 коментара)

Христо обнови решението на 19.03.2016 14:38 (преди над 1 година)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
class Expression():

    def __init__(self, expression):
        self.expression = expression
        self.variable_names = tuple(
            [var.__str__() for var in self.expression if isinstance(var, Variable)])

    def evaluate(self, **variables):
        lhs, op, rhs = self.expression
        if type(lhs) != int:
            lhs = lhs.evaluate(**variables)
        if type(rhs) != int:
            rhs = rhs.evaluate(**variables)

        self.value = op.evaluate(lhs, rhs)
        return self.value

    def __str__(self):
        lhs, op, rhs = self.expression
        if type(lhs) == tuple:
            lhs = create_expression((lhs[0], lhs[1], lhs[2]))

        if type(rhs) == tuple:
            rhs = create_expression((rhs[0], rhs[1], rhs[2]))
        self.expression = lhs, op, rhs

        return '(' + ' '.join([expr.__str__() for expr in self.expression]) + ')'

    def __radd__(self, other):
        return self + other

    def __add__(self, other):
        if type(other) == int or type(other) == float:
            return self + create_constant(other)
        return create_expression((self, plus, other))

    def __rsub__(self, other):
        return self - other

    def __sub__(self, other):
        if type(other) == int or type(other) == float:
            return self - create_constant(other)
        return create_expression((self, minus, other))

    def __mul__(self, other):
        if type(other) == int or type(other) == float:
            return self * create_constant(other)
        return create_expression((self, times, other))

    def __rmul__(self, other):
        return self * other

    def __rdiv__(self, other):
        return self / other

    def __div__(self, other):
        if type(other) == int or type(other) == float:
            return self / create_constant(other)
        return create_expression((self, div, other))

    def __rtruediv__(self, other):
        return self / other

    def __truediv__(self, other):
        if type(other) == int or type(other) == float:
            return self / create_constant(other)
        return create_expression((self, div, other))


class Constant(Expression):

    def __init__(self, value):
        Expression.__init__(self, ())
        self.value = value

    def evaluate(self, **kwargs):
        return self.value

    def __str__(self):
        return str(self.value)


class Variable(Expression):

    def __init__(self, name):
        self.name = name

    def evaluate(self, **args):
        return args.get(self.name, '')

    def __str__(self):
        return self.name


class Operator(Expression):

    def __init__(self, symbol, function):
        # Expression.__init__(self, ())
        self.symbol = symbol
        self.function = function

    def evaluate(self, lhs, rhs):
        return self.function(lhs, rhs)

    def __str__(self):
        return self.symbol


def create_expression(expression_structure):
    return Expression(expression_structure)


def create_constant(value):
    return Constant(value)


def create_variable(name):
    return Variable(name)


def create_operator(symbol, function):
    return Operator(symbol, function)


plus = create_operator('+', lambda lhs, rhs: lhs + rhs)
minus = create_operator('-', lambda lhs, rhs: lhs - rhs)
times = create_operator('*', lambda lhs, rhs: lhs * rhs)
div = create_operator('*', lambda lhs, rhs: lhs / rhs)
  • Ако даден клас не наследява от нищо, няма нужда от празните скоби в дефиницията му.
  • Сравнявай типове с isinstance вместо с type. Ако все пак някъде ти трябва да използваш type (каквото не е положението в това домашно) използвай оператора is.
  • Въпросният if се повтаря в дефиницията на почти всички оператори. Намери начин да избегнеш това повторение.
  • var е лошо име. Всички имена в езика са променливи :)
  • Предпочитай str(x) пред x.__str__()
  • Предпочитай str.format() пред конкатениране на низове.

Христо обнови решението на 20.03.2016 17:41 (преди над 1 година)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import operator

primitive_types = int,  float, complex


class Expression:

    def __init__(self, expression):
        self.expression = expression
        self.variable_names = tuple(
            [str(expr) for expr in self.expression if isinstance(expr, Variable)])

    def evaluate(self, **variables):
        lhs, op, rhs = self.expression
        if not(isinstance(lhs, primitive_types)):
            lhs = lhs.evaluate(**variables)
        if not(isinstance(rhs, primitive_types)):
            rhs = rhs.evaluate(**variables)

        self.value = op.evaluate(lhs, rhs)
        return self.value

    def __str__(self):
        lhs, op, rhs = self.expression
        if hasattr(lhs, '__iter__'):
            lhs = create_expression((lhs[0], lhs[1], lhs[2]))

        if hasattr(rhs, '__iter__'):
            rhs = create_expression((rhs[0], rhs[1], rhs[2]))
        self.expression = lhs, op, rhs

        return '({})'.format(' '.join([str(expr) for expr in self.expression]))

    def __oper(self, other, expressionOp, primitiveOp):
        if isinstance(other, primitive_types):
            return primitiveOp(self, create_constant(other))
        return create_expression((self, expressionOp, other))

    def __roper(self, other, expressionOp, primitiveOp):
        if isinstance(other, primitive_types):
            return primitiveOp(create_constant(other), self)
        return create_expression((other, expressionOp, self))

    def __add__(self, other):
        return self.__oper(other, plus, operator.add)

    def __sub__(self, other):
        return self.__oper(other, minus, operator.sub)

    def __mul__(self, other):
        return self.__oper(other, times, operator.mul)

    def __truediv__(self, other):
        return self.__oper(other, div, operator.truediv)

    def __radd__(self, other):
        return self + other

    def __rsub__(self, other):
        return self.__roper(other, minus, operator.sub)

    def __rmul__(self, other):
        return self * other

    def __rtruediv__(self, other):
        return self.__roper(other, div, operator.truediv)


class Constant(Expression):

    def __init__(self, value):
        self.value = value

    def evaluate(self, **kwargs):
        return self.value

    def __str__(self):
        return str(self.value)


class Variable(Expression):

    def __init__(self, name):
        self.name = name

    def evaluate(self, **args):
        return args.get(self.name, '')

    def __str__(self):
        return self.name


class Operator(Expression):

    def __init__(self, symbol, function):
        self.symbol = symbol
        self.function = function

    def evaluate(self, lhs, rhs):
        return self.function(lhs, rhs)

    def __str__(self):
        return self.symbol


def create_expression(expression_structure):
    return Expression(expression_structure)


def create_constant(value):
    return Constant(value)


def create_variable(name):
    return Variable(name)


def create_operator(symbol, function):
    return Operator(symbol, function)


plus = create_operator('+', operator.add)
minus = create_operator('-', operator.sub)
times = create_operator('*', operator.mul)
div = create_operator('/', operator.truediv)

Благодаря за бързия коментар, поправих нещата :)
Може ли само малко повече обяснение за последната точка
В конкретния случай не е ли по-добре да се използва конкатенация - с нея май кодът е по-четим?

Христо обнови решението на 20.03.2016 20:06 (преди над 1 година)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import operator
import itertools

primitive_types = int,  float, complex


class Expression:

    def __init__(self, expression):
        self.expression = expression
        self.variable_names = tuple(itertools.chain(
            *[expr.variable_names for expr in self.expression if isinstance(expr, Expression)]))

    def evaluate(self, **variables):
        lhs, op, rhs = self.expression
        if not(isinstance(lhs, primitive_types)):
            lhs = lhs.evaluate(**variables)
        if not(isinstance(rhs, primitive_types)):
            rhs = rhs.evaluate(**variables)

        self.value = op.evaluate(lhs, rhs)
        return self.value

    def __str__(self):
        lhs, op, rhs = self.expression
        if hasattr(lhs, '__iter__'):
            lhs = create_expression((lhs[0], lhs[1], lhs[2]))

        if hasattr(rhs, '__iter__'):
            rhs = create_expression((rhs[0], rhs[1], rhs[2]))
        self.expression = lhs, op, rhs

        return '({})'.format(' '.join([str(expr) for expr in self.expression]))

    def __oper(self, other, expressionOp, primitiveOp):
        if isinstance(other, primitive_types):
            return primitiveOp(self, create_constant(other))
        return create_expression((self, expressionOp, other))

    def __roper(self, other, expressionOp, primitiveOp):
        if isinstance(other, primitive_types):
            return primitiveOp(create_constant(other), self)
        return create_expression((other, expressionOp, self))

    def __add__(self, other):
        return self.__oper(other, plus, operator.add)

    def __sub__(self, other):
        return self.__oper(other, minus, operator.sub)

    def __mul__(self, other):
        return self.__oper(other, times, operator.mul)

    def __truediv__(self, other):
        return self.__oper(other, div, operator.truediv)

    def __radd__(self, other):
        # same as self + other in evaluating, but different in printing
        return self.__roper(other, plus, operator.add)

    def __rsub__(self, other):
        return self.__roper(other, minus, operator.sub)

    def __rmul__(self, other):
        # same as self * other in evaluating, but different in printing
        return self.__roper(other, times, operator.mul)

    def __rtruediv__(self, other):
        return self.__roper(other, div, operator.truediv)


class Constant(Expression):

    def __init__(self, value):
        self.value = value
        self.variable_names = ''

    def evaluate(self, **kwargs):
        return self.value

    def __str__(self):
        return str(self.value)


class Variable(Expression):

    def __init__(self, name):
        self.name = name
        self.variable_names = self.name

    def evaluate(self, **args):
        return args.get(self.name, '')

    def __str__(self):
        return self.name


class Operator(Expression):

    def __init__(self, symbol, function):
        self.symbol = symbol
        self.function = function
        self.variable_names = ''

    def evaluate(self, lhs, rhs):
        return self.function(lhs, rhs)

    def __str__(self):
        return self.symbol


def create_expression(expression_structure):
    return Expression(expression_structure)


def create_constant(value):
    return Constant(value)


def create_variable(name):
    return Variable(name)


def create_operator(symbol, function):
    return Operator(symbol, function)


plus = create_operator('+', operator.add)
minus = create_operator('-', operator.sub)
times = create_operator('*', operator.mul)
div = create_operator('/', operator.truediv)

Факт е, че в някои случаи конкатенирането на низове и по-четимо. В случая, можеш да го направиш далеч по-елегантно с str.format. Нещото, което не ми харесва в твоята имплементация на __str__ е, че мутираш атрибут на обекта, за да го представиш като низ. Това е кофти идея.

Също така, гледайки primitive_types = int, float, complex ме подсеща, че освен за isinstance можеше да ти кажа и за numbers.Number. Всички числа в езика наследяват от този тип, само и единствено в името на isinstnace провекра за число :)

Христо обнови решението на 21.03.2016 12:57 (преди над 1 година)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import operator
import itertools

primitive_types = int,  float, complex


class Expression:

    def __init__(self, expression):
        self.expression = expression
        self.variable_names = tuple(itertools.chain(
            *[expr.variable_names for expr in self.expression if isinstance(expr, Expression)]))

    def evaluate(self, **variables):
        lhs, op, rhs = self.expression
        if not(isinstance(lhs, primitive_types)):
            lhs = lhs.evaluate(**variables)
        if not(isinstance(rhs, primitive_types)):
            rhs = rhs.evaluate(**variables)

        self.value = op.evaluate(lhs, rhs)
        return self.value

    def __str__(self):
        return '({})'.format(' '.join([str(expr) for expr in self.expression]))

    def __oper(self, other, expressionOp, primitiveOp):
        if isinstance(other, primitive_types):
            return primitiveOp(self, create_constant(other))
        return create_expression((self, expressionOp, other))

    def __roper(self, other, expressionOp, primitiveOp):
        if isinstance(other, primitive_types):
            return primitiveOp(create_constant(other), self)
        return create_expression((other, expressionOp, self))

    def __add__(self, other):
        print('add')
        return self.__oper(other, plus, operator.add)

    def __sub__(self, other):
        print('sub')
        return self.__oper(other, minus, operator.sub)

    def __mul__(self, other):
        print('mul')
        return self.__oper(other, times, operator.mul)

    def __truediv__(self, other):
        return self.__oper(other, div, operator.truediv)

    def __radd__(self, other):
        print('radd')
        # same as self + other in evaluating, but different in printing
        return self.__roper(other, plus, operator.add)

    def __rsub__(self, other):
        print('rsub')
        return self.__roper(other, minus, operator.sub)

    def __rmul__(self, other):
        print('rmul')
        # same as self * other in evaluating, but different in printing
        return self.__roper(other, times, operator.mul)

    def __rtruediv__(self, other):
        return self.__roper(other, div, operator.truediv)


class Constant(Expression):

    def __init__(self, value):
        self.value = value
        self.variable_names = ''

    def evaluate(self, **kwargs):
        return self.value

    def __str__(self):
        return str(self.value)


class Variable(Expression):

    def __init__(self, name):
        self.name = name
        self.variable_names = self.name

    def evaluate(self, **args):
        return args.get(self.name, '')

    def __str__(self):
        return self.name


class Operator(Expression):

    def __init__(self, symbol, function):
        self.symbol = symbol
        self.function = function
        self.variable_names = ''

    def evaluate(self, lhs, rhs):
        return self.function(lhs, rhs)

    def __str__(self):
        return self.symbol


def create_expression(expression_structure):
    actual_expr_str = ()
    for expr in expression_structure:
        if hasattr(expr, '__iter__'):
            expr = create_expression(expr)
        actual_expr_str += expr,
    return Expression(actual_expr_str)


def create_constant(value):
    return Constant(value)


def create_variable(name):
    return Variable(name)


def create_operator(symbol, function):
    return Operator(symbol, function)


plus = create_operator('+', operator.add)
minus = create_operator('-', operator.sub)
times = create_operator('*', operator.mul)
div = create_operator('/', operator.truediv)

Христо обнови решението на 21.03.2016 13:04 (преди над 1 година)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import operator
import itertools

primitive_types = int, float, complex


class Expression:

    def __init__(self, expression):
        self.expression = expression
        self.variable_names = tuple(itertools.chain(
            *[expr.variable_names for expr in self.expression if isinstance(expr, Expression)]))

    def evaluate(self, **variables):
        lhs, op, rhs = self.expression
        if not(isinstance(lhs, primitive_types)):
            lhs = lhs.evaluate(**variables)
        if not(isinstance(rhs, primitive_types)):
            rhs = rhs.evaluate(**variables)

        self.value = op.evaluate(lhs, rhs)
        return self.value

    def __str__(self):
        return '({})'.format(' '.join([str(expr) for expr in self.expression]))

    def __oper(self, other, expressionOp, primitiveOp):
        if isinstance(other, primitive_types):
            return primitiveOp(self, create_constant(other))
        return create_expression((self, expressionOp, other))

    def __roper(self, other, expressionOp, primitiveOp):
        if isinstance(other, primitive_types):
            return primitiveOp(create_constant(other), self)
        return create_expression((other, expressionOp, self))

    def __add__(self, other):
        return self.__oper(other, plus, operator.add)

    def __sub__(self, other):
        return self.__oper(other, minus, operator.sub)

    def __mul__(self, other):
        return self.__oper(other, times, operator.mul)

    def __truediv__(self, other):
        return self.__oper(other, div, operator.truediv)

    def __radd__(self, other):
        # same as self + other in evaluating, but different in printing
        return self.__roper(other, plus, operator.add)

    def __rsub__(self, other):
        return self.__roper(other, minus, operator.sub)

    def __rmul__(self, other):
        # same as self * other in evaluating, but different in printing
        return self.__roper(other, times, operator.mul)

    def __rtruediv__(self, other):
        return self.__roper(other, div, operator.truediv)


class Constant(Expression):

    def __init__(self, value):
        self.value = value
        self.variable_names = ''

    def evaluate(self, **kwargs):
        return self.value

    def __str__(self):
        return str(self.value)


class Variable(Expression):

    def __init__(self, name):
        self.name = name
        self.variable_names = self.name

    def evaluate(self, **args):
        return args.get(self.name, '')

    def __str__(self):
        return self.name


class Operator(Expression):

    def __init__(self, symbol, function):
        self.symbol = symbol
        self.function = function
        self.variable_names = ''

    def evaluate(self, lhs, rhs):
        return self.function(lhs, rhs)

    def __str__(self):
        return self.symbol


def create_expression(expression_structure):
    actual_expr_str = ()
    for expr in expression_structure:
        if hasattr(expr, '__iter__'):
            expr = create_expression(expr)
        actual_expr_str += expr,
    return Expression(actual_expr_str)


def create_constant(value):
    return Constant(value)


def create_variable(name):
    return Variable(name)


def create_operator(symbol, function):
    return Operator(symbol, function)


plus = create_operator('+', operator.add)
minus = create_operator('-', operator.sub)
times = create_operator('*', operator.mul)
div = create_operator('/', operator.truediv)