Python & Strypes

Python types

  • int 
  • float
  • str
  • bool
  • None
  • complex
  1. Всяка стойност има тип. Даже функциите.
  2. Всяка стойност е обект от някакъв клас, включително функциите.
  3. Дори типовете са обекти и си имат тип!

Всичко има тип!

Ама как функциите са обекти?

Еми, ей така!

>>> class Panda: 
....    pass 
>>> pandarian = Panda()
>>> type(pandarian)
<class '__main__.Panda'>
>>> type(101)
<class 'int'>
>>> type("Programming 101")
<class 'str'>
>>> type(len)
<class 'builtin_function_or_method'>
>>> type(dir)
<class 'builtin_function_or_method'>

Тоест мога да си направя клас и неговите обекти да се държат като функции?

>>> class Panda:
...     def __call__(self):
...          return "You called e panda! Hello mister panda is here!"
... 
>>> pandarian = Panda()
>>> pandarian()
'You called e panda! Hello mister panda is here!'

__call__ различава функциите от нормалните обекти!

Функциите са обекти.

Дай да преговорим:

  1. Всичко е обект.
  2. Функциите са обекти.
  3. Функциите могат да връщат всякакви обекти.

Следователно...

Функциите могат да връщат други функции!

>>> def take_print():
...     print("I will return a print function!")
...     return print
... 
>>> my_print = take_print()
I will return a print function!
>>> type(my_print)
<class 'builtin_function_or_method'>
>>> my_print("Hello World!")
Hello World!

Днес научихме:

  1. Функциите са обекти. Те могат да приемат за аргумент и да връщат други функции.

Области на видимост

  1. Всеки блок от код (функция) си има своя област на видимост, в която стоят локално дефинираните променливи!
     
  2. Ако една функция не може да намери дадена променлива в локалния си скоуп, търси в глобалния за променлива със същото име
>>> global_var = "Le me global"
>>> def much_function():
...     print(global_var)
... 
>>> much_function()
Le me global

Примери:

>>> global_var = "Le me global"
>>> def much_function():
...     print(global_var)
... 
>>> much_function()
Le me global
>>> global_var = "Le me global"
>>> def much_function():
...     global_var = "Le me local"
...     print(global_var)
... 
>>> much_function()
Le me local

Влагане на фукнции

  1. Можем да дефинираме функция в функция

  2. Вложената функция вижда променливите в скоупа на обвиващата функция!
def get_kangaroo(size):
    print(size) # 50

    def get_baby_kangaroo():
        size = 10
        print(size) # 10

    get_baby_kangaroo()
    print(size) # 50

get_kangaroo(50)

Днес научихме:

  1. Функциите са обекти. Те могат да приемат за аргумент и да връщат други функции.
  2. Как работи скоупа на променливите.
  3. Можем да дефинираме функция в функция.

Така може да си правим Closures 

Closures:

Имаме closure, когато вложена функция достъпва променлива, дефинирана в обграждаща функция

def get_quadratic_function(a, b, c):

    def quadratic_function(x):
        return a * x ** 2 + b * x + c

    return quadratic_function

func = get_quadratic_function(1, 2, 3)
print(func(1)) # 6
print(func(2)) # 11
print(func(3)) # 18

Проблем:

Ние сме огромен телеком и хората идват при нас за да си плащат телефона, интернета и телевизията.

def pay_net(months, user_id):
    print("{} payed Internet for {} months".format(user_id, motnhs))
    save_to_database(motnhs, user_id)


def pay_tv(months, user_id):
    print("{} payed TV for {} months".format(user_id, motnhs))
    save_to_database(motnhs, user_id)


def pay_phone(months, user_id):
    print("{} payed Phone for {} months".format(user_id, motnhs))
    save_to_database(motnhs, user_id)


pay_net(1, "ivaylo@hackbulgaria.com")
pay_phone(2, "radorado@hackbulgaria.com")
pay_tv(1, "toni@hackbulgaria.com")

Ами промоциите:

Сеща ме се, че трябва да поддържаме промоции. Плати X месеца получаваш 1 безплатен.

Слагаме още 1 параметър!

def pay_net(months, user_id, promotion_months):
    if months >= promotion_months:
        months += 1

    print("{} payed Internet for {} months".format(user_id, motnhs))
    save_to_database(motnhs, user_id)


def pay_tv(months, user_id, promotion_months):
    if months >= promotion_months:
        months += 1

    print("{} payed TV for {} months".format(user_id, motnhs))
    save_to_database(motnhs, user_id)


def pay_phone(months, user_id, promotion_months):
    if months >= promotion_months:
        months += 1

    print("{} payed Phone for {} months".format(user_id, motnhs))
    save_to_database(motnhs, user_id)

pay_net(1, "ivaylo@hackbulgaria.com", 3)
pay_phone(2, "radorado@hackbulgaria.com", 2)
pay_tv(1, "toni@hackbulgaria.com", 2)

Проблеми:

  1. Всеки път ще трябва да се сещаме каква беше промоцията за конкретната услуга.
  2. Ако предлагахме 100 услуги във всички функции ли щяхме да бъркаме?

Използваме новите знания за да "декорираме" функцията

def get_promotion(func, promotion_months):
    def promotion(months, user_id):
        if months >= promotion_months:
            months += 1
        return func(months, user_id)
    return promotion


def pay_net(months, user_id):
    print("{} payed Internet for {} months".format(user_id, months))
    save_to_database(months, user_id)


def pay_tv(months, user_id):
    print("{} payed TV for {} months".format(user_id, months))
    save_to_database(months, user_id)


def pay_phone(months, user_id):
    print("{} payed Phone for {} months".format(user_id, months))
    save_to_database(months, user_id)

pay_net = get_promotion(pay_net, 3)
pay_phone = get_promotion(pay_phone, 3)
pay_tv = get_promotion(pay_tv, 2)


pay_net(1, "ivaylo@hackbulgaria.com")
pay_phone(2, "radorado@hackbulgaria.com")
pay_tv(1, "toni@hackbulgaria.com")
  • Малко странно се създават нашите функции
  • Ами ако някой забрави да ги декорира, къде отиват промоциите?
pay_net = get_promotion(pay_net, 3)
pay_phone = get_promotion(pay_phone, 3)
pay_tv = get_promotion(pay_tv, 2)

В Python има синтаксис за това!

def get_promotion(func):
    def promotion(months, user_id):
        if months >= 3: # 3 is hardcoded
            months += 1
        return func(months, user_id)
    return promotion

@get_promotion
def pay_net(months, user_id):
    print("{} payed Internet for {} months".format(user_id, months))
    save_to_database(months, user_id)

pay_net(5, "radorado@hackbulgaria.com")

Можем и да подаваме аргументи на декораторите!

def get_promotion(promotion_months):
    def accepter(func):
        def decorated(months, user_id):
            if months >= promotion_months:
                months += 1
            return func(months, user_id)
        return decorated
    return accepter

@get_promotion(3)
def pay_net(months, user_id):
    print("{} payed Internet for {} months".format(user_id, months))
    save_to_database(months, user_id)

pay_net(5, "radorado@hackbulgaria.com")

Декоратори

Essentially, decorators work as wrappers, modifying the behavior of the code before and after a target function execution, without the need to modify the function itself, augmenting the original functionality, thus decorating it.

Можем и повече от един декоратор!

Първо се извиква най-вътрешния декоратор!

@notify_via_email
@get_promotion(3)
def pay_net(months, user_id):
    print("{} payed Internet for {} months".format(user_id, months))
    save_to_database(months, user_id)

Декоратори в живия живот!

  • classmethod — прави метода класов 
  • staticmethod — прави метода статичен
  • property
  • https://wiki.python.org/moin/PythonDecoratorLibrary
  • Djano likes decorators

Python Strypes Training - Decorators

By Hack Bulgaria

Python Strypes Training - Decorators

  • 1,426