timeit

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

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

Второ домашно

  1. Ето го и второ домашно. Срокът ви е до 21.03 17:00.

    Примерния тест можете да намерите в GitHub хранилището.

    Напомням, че нямате право да си споделяте решенията. Обяснение от типа "Аз само му показах моето, но той сам си го написа" не важи. Ако имате въпроси по условието или такива от общ характер за решението на домашното - питайте тук.

    Преди всичко се запознайте с това как (не) се предават задачи.

  2. Здравейте,

    имам въпрос за този пример - (x + 3 * (y - 2)).evaluate(x=1, y=4) от домашното. Трябва да се дефинират аритметични операции между Expression/Constant/Variable и int или е допусната грешка, тъй като малко по нагоре от примера е казано "Обектите ни представляващи константи, променливи и изрази трябва да могат да се събират/изваждат/умножават/делят."? Благодаря предварително.

    Илия

  3. Атрибута variable_names има ли значение какво итеруемо ще върне и в какъв ред ще са имената на променливите?

    Изразите трябва да имат атрибут variable_names, който е итеруемо с имената на всички променливи в израза.
    
    >>> added_expression.variable_names == ('x',)
    True
    

    В условието сравнението е с кортеж, тоест ако връщаме списък или множество това ще се приема ли?

  4. @Александър, само числовите литерали, не е нужно да конвертирате стрингове в променливи.

    Иначе примера написан така наистина е объркващ. Каквото и да е итеруемо свърши работа и реда няма значение.

    @Тодор, щом трябва :)

  5. Мисля че 'x', в условието пише:

     create_variable(name) - връща обект, който представлява променлива, аргумента name указва какво да бъде името ѝ.
    

    това име се очаква да върне атрибута variable_names:

    Изразите трябва да имат атрибут variable_names, който е итеруемо с имената на всички променливи в израза.
    

    Най-логично е да се очаква това име да подадеш на evaluate()

  6. @Десислава, каквото @Александър каза.

    Което ме подсеща, че може би не сме обяснили подробно за какво използваме звездичките във форумите. Ако видите отговор със жълт фон (или както би бил представен цветът в предното ви домашно: (255, 253, 208)) на зададен въпрос от ваш колега, това ще рече, че някой от екипа е прегледал този отговор и е потвърдил неговата коректност. С други думи, разглеждайте тези отговори като отговори дадени от нас (екипа зад курса).

    По-конкретно към въпроса на @Десислава:

    Не случайно искаме името да се подаде като аргумент, а не се опитваме да вземем името на променливата, която сочи към нашия нов обект. Не би трябвало да ни интересува какви и колко имена сочат до наш обект, за да определяме държанието му. В реда на нещата е някой да реши да използва твоя код така (поради каквато и да е причина):

    баба = дядо = леля = чичо = стринка = лелинчо = create_variable('x') (това всъщност е валиден питонски код...)

    1. Трябва ли и built-in(int, float etc.) типовете да позволяват операции с нашите типове. Това което имам предвид в условието се вижда, че:

      (x + 3).evaluate(x=2) => 5
      

      Въпроса е дали се очаква и това да работи също:

      (3 + x).evaluate(x=2) => 5
      
    2. Под делене разбираме само / или се очаква и // също да се предефинира?

    3. expression-ите как трябва точно да се форматират като се принтират. Пример:

       four = s.create_constant(4)
       y = s.create_variable('y')
       f = four + (y-2) * 3.5
       str(f) => (4 + ((y - 2) * 3.5)) или (4 + (y - 2) * 3.5)
      
    4. create_expression очакава се да приема tuple от tuple-и или всякакви iterable неща да се очакват?

  7. Здрвейте,

    това, което ми се върти като решение са две неща.

    1. Parser - което е доста играчка и е по-скоро за проект.
    2. Shunting-yard alg за да стигна до RPN и след това е лесно RPN да се изчисли.

    На прав път ли съм или изпускам нещо и решението е доста по-просто ?

  8. Марио пита за //, аз направо питам за всичките: :D

        __add__(self, other)
        __sub__(self, other)
        __mul__(self, other)
        __matmul__(self, other)
        __truediv__(self, other)
        __floordiv__(self, other)
        __mod__(self, other)
        __divmod__(self, other)
        __pow__(self, other)
        __lshift__(self, other)
        __rshift__(self, other)
        __and__(self, other)
        __xor__(self, other)
        __or__(self, other)
    
  9. @Марио

  10. 1. Това трябва да работи
     (3 + x).evaluate(x=2) => 5
    

  11. 2. И аз искам отговор на този въпрос :D

  12. 3. един израз е изграден от (операнд1, оператор, операнд2) и трябва да се форматира по следния начин (операнд1 оператор операнд2)
    four = s.create_constant(4)
    y = s.create_variable('y')
    f = four + (y-2) * 3.5
    

    в случая на f операнд2 е израза (y - 2) * 3.5 и той трябва да спазва горното правило

    >>>str((y - 2) * 3.5)
    ((y - 2) * 3.5)
    >>>str(four + (y-2) * 3.5)
    (4 + ((y - 2) * 3.5))
    

  13. 4. Не съм сигурен дали ще тестват само с tuples, но в условието не е конкретизирано(което мисля, че не е случайно :D)
    create_expression(expression_structure) - връща обект, който представлява аритметичен израз. expression_structure е итеруемо от 
    итеруеми, което описва желания израз.
    
  14. Нещо не ми е ясно. Като си направя нещо такова:

    z = create_variable('z')
    c1 = create_constant(12)
    plus = create_operator('+', lambda lhs, rhs: lhs + rhs)
    mult = create_operator('*', lambda lhs, rhs: lhs * rhs)
    
    tup = (((c1, mult, z), mult, (z, mult, c1)), plus, ((c1, mult, z), mult, (z, mult, c1)))
    expr = create_expression(tup)
    
    print(expr.evaluate(z=3))
    

    Всичко си работи идеално, колкото и да влагам. Обаче не мога да разбера как да се направи това:

    f = four + (y-2) * 3.5, при положение, че f тук няма никакъв тип, аргументът self.value на у е None, и точно както се очаква - това гърми, въпреки че съм предефинирал операторите, защото имаме NoneType. Ако го подам така:

    f = create_expression(four, plus, ...), всичко е ОК. Какво пропускам?

  15. Методите evaluate трябва само да връщат резултат от оценения израз/променлива/константа, както е описано:

    "Изразът, който получаваме от create_expression трябва да има метод evaluate(**variables). Той приема keyword аргументи за стойностите на променливите в израза и връща като резултат стойността на израза при тези стойности."

    или трябва и да печата стойността на оценката си при извикване дори и без print, както е показано в примерите ?

  16. Виж какви тестове е постнал Александър:

    def test_expressions(self):
        four = s.create_constant(4)
        y = s.create_variable('y')
        f = four/2 + 3.5*(y-2)
        d = (3+1j) + y
        z = 15 - 2/four * (12 / f)
        self.assertEqual(d.evaluate(y=2), 5+1j)
        self.assertEqual(f.evaluate(y=2), 2)
        self.assertEqual(f.evaluate(y=0), -5)
        self.assertEqual(z.evaluate(y=2, x=3), 12.0)
    

    тука никъде не виждам create_expression, нито пък итеруемо от итеруеми.

  17. @Даниел, връща си, никъде не е написано да печата, а и нали ни казаха винаги да връщаме, а не да печатаме.

    @Симеон, точно така е, операторите създават Expression, както би направила create_expression.

  18. @Тодор Искаш да кажеш, че например:

    plus = create_operator('+', lambda x,y: x+y)

    ако напиша expr = x plus (4 plus y)

    ще създаде ескрешън от x и екпрешън от (4 plus y)? Хмм, то възможно ли е изобщо да вземеш двете страни, при положение, че не е итеруемо от итеруеми, ами си е просто ... пайтънски израз?

  19. Когато някой ни изпревари и отговори на въпросите ви получава звездичка.

    @Марио Ще тестваме за всичко което е споменала @Десислава.

    @Даниел chill, няма нищо за парсене, изрично сме се постарали да ви подаваме изпарсени структури. :) За това аргумента на create_expression е итеруемо представляващо израза. :)

    @Симеон create_expression((3, plus, (y, minus, 5)) трябва да създаде същия тип обект със същото поведение като 3 + (y - 5), ако приемем, че си си дефинирал y, plus и minus разбира се.

  20. @Симеон Обектите от тип оператор не създават обект израз, но вградените в езика оператори трябва да могат това.

    plus = create_operator('+', lambda x,y: x+y) създава израз, но

    expr = x plus (4 plus y) - не

    exp1 = x + (4 + y) трябва да създаде израз.

  21. "Ако на evaluate бъдат подадени допълнителни именовани аргументи, за които нямаме променливи, това очевидно не трябва да е проблем."

    Това означава ли, че evaluate може да бъде извиквана от обект тип променлива с повече от един именован аргумент и това трябва да връща итеруемо?

  22. "Ще тестваме за всичко което е споменала @Десислава"

    Какво се очаква да върне matmul приложено върху изрази, а не матрици?

    В какъв низ трябва да се конвертира divmod като позлваме print и няма ли да има проблеми ако трябва да evaluate-нем израз като ((x divmod? y) + 2) като divmod връща tuple и няма дефинирано tuple + int?

  23. @Теодор

    Според мен за __matmul__ трябва да се очаква като вход само матрици.

    >>> m1 = create_constant([[1,0,1]])
    >>> m2 = create_constant([[1],[0],[1]])
    >>> f = m1 @ m2
    >>> f.evaluate()
    [[2]]
    >>> ([[3]] @ f).evaluate()
    [[6]]
    >>> (m1 @ 2).evaluate()
    BOOOOM :D
    

    Предполагам че [[1],[2],[3]] трябва да се разглежда като матрица 3x1 (Ако приемем, че за елемент m1[i][j] - i-отговяря за реда а j-за стълба)

    https://docs.python.org/3/whatsnew/3.5.html#pep-465-a-dedicated-infix-operator-for-matrix-multiplication Имай предвид, че оператора не е дефиниран за нито един от builtin типовете на python. Ще трябва сам да си дефинираш умножение на матрици

  24. А divmod все пак има ли смисъл - заради това, което каза @Теодор?

    Освен изброените от @Десислава трябва ли да предефинираме и оператори за сравнение, унарни... Ако може направо някой да пусне списък с всички, които се изискват, ще бъде супер.

Трябва да сте влезли в системата, за да може да отговаряте на теми.