събота, 17 януари 2009 г.

Модули в python


„ Програмиране с Python“, ФМИ

Стефан Кънев & Николай Бачийски

12.03.2007г.

Елементарен проблем

world.py:


""" A module for playing with the world. """
def destroy():
"""Destroys the world."""
print "The world was destroyed!"

def save(kind):
"""Saves a kind."""
print "All the", kind, "were saved."

Искаме да ползваме горните функции в много програми, а не искаме да копираме кода във всяка от тях.

Елементарно решение

women.py:

import world
world.save('women')
world.destroy()
animals.py:
import world
world.save('animals')
world.destroy()

Работи без проблеми ако трите файла са в една директория.
Чрез модули можем да използваме един и същи код много пъти (code reuse).

Атрибути

  • Обектите имат свързани с тях имена, наречени атрибути, които се достъпват чрез оператора . (точка)
  • Нека разгледаме по-подробно world.destroy()
  • destroy е функция и е атрибут на обекта world, който пък е модул
  • >>> world
  • >>>world.destroy
  • с вградената функция dir можем да видим всички атрибути на обект:
  • >>> dir(world)
    ['__builtins__', '__doc__', '__file__', '__name__', 'destroy', 'save']
    >>> world.__doc__
    ' A module for playing with the world. '
    >>> world.__name__
    'world'

Области от имена (1)

  • Всяка програма е модул сама по себе си и всички глобални имена, са негови атрибути
  • savepoohs.py:
  • import world
    def savePoohs():
    world.save('Poohs')
    insane = True
    print dir()
  • Ще отпечата: [<системни атрибути> 'world', 'savePoohs', 'insane']

Области от имена (2)

  • В различни модули можем да имаме едни и същи имена
  • Всеки модул си има различен набор от имена
  • import pooh
    import piglet
    def breakfast():
    print "Is it already eleven?"
    pooh.breakfast()
    piglet.breakfast()
    breakfast()

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

Търсене на атрибути

  • answer = 42
  • в този случай е ясно, че обектът зад името answer трябва да се търси по стандартния начин (в разните обхвати)
  • pooh.naivete = 42
  • името naivete не трябва да се търси в стандартните обхвати, а трябва да се търси в списъка с атрибути на обекта зад името pooh
  • universe.milkyway.earth.europe.bg.beautify()

Модули и обхвати

  • Глобалните променливи са на практика модулни променливи. Те са глобални само в рамките на модула, в който се намират.
  • mod.py:
  • bottles = 1
    def addBottle():
    global bottles
    bottles += 1
  • bottler.py:
  • import mod
    bottles = 5
    mod.addBottle()
    print bottles, mod.bottles

Използване на модули — import

Чрез вградената фунцкия import ни дава възможност да ползваме код от външни файлове.

Ето какво се случва, ако изпълним import mod:

  1. Намира се файла, в който се намира модула
  2. Кодът се компилира до байт-код (ако е необходимо)
  3. Кодът на модула се изпълнява (дефиниции на функции, друг код)
  4. На името mod се присвоява обекта на изпълнения модул

Търсене на файла

import mod

Търси се в:

  1. текущата директория
  2. променливата на средата PYTHONPATH
  3. системни директории с модули
  4. директории, описани в .pth файлове

Всички по реда на претърсване: списъка sys.path

Модул vs. Програма

  • И в двата случая кодът ни се изпълнява
  • Искаме ако кодът ни е бил изпълнен директно да тестваме модула си
  • Искаме ако кодът ни е бил включен с import само да дефинираме фукнциите си
  • eater.py:
  • def eat(what):
    print what, "was eaten."

    if (__name__ == '__main__'):
    eat('The world as we know it')
  • $ python eater.py
    The world as we know it was eaten.
  • >>> import eater

Пакети от модули

Представете си, че имаме две отделни системи, в които има модул на име game

system1/
game.py
<други модули>
system2/
game.py
<други модули>

Сега напишете система, която използва модулите game и от двете други:

import game
game.play()

Тук вече имаме малък проблем.

Пакети от модули (2)

Би било много удобно ако можехме да разделим двата модула game в отделни пакети:

import system1.game
import system2.game
system1.game.play()
system2.game.play()

Това е възможно при няколко условия:

  • директориите system1 и system2 са някъде из пътя за търсене на python
  • във всяка от тях има файл с име __init__.py

При import на по-сложно име се извършва следното:

  • намира се поредната компонента от пътя (разделени с точки)
  • ако има съответстващ файл — включва се
  • ако е директория — изпълнява се __init__.py в нея

Пакети от модули (3)

С пакети от модули можем с едни замах да import-нем много модули:

forest/pooh.py:

name = 'Pooh'

forest/piglet.py:

name = 'Piglet'

forest/__init__.py:

import pooh
import piglet
user.py:
import forest
print forest.pooh.name
print forest.piglet.name

import

  • import mod — намира се модула и обектът му се присвоява на името mod
  • sys = '/usr/src/sys'
    import os
    def listByExt(path, ext):
    return [d for d in os.listdir(path) if d.endswith('.'+ext)]

    # искаме да отпечатаме sys.path
    import sys
    print sys.path

    # сега да видим всички питонски файлове в /usr/src/sys
    print listByExt(sys, 'py')
    # опс:
    TypeError: coercing to Unicode: need string or buffer, module found

import as

import sys as sysmod
print sysmod.path Почти същото е като:
import sys
sysmod = sys
del sys
sysmod.path
само че ще загубим старата стойност на sys

from mod import names

Понякога е досадно да извикваме всеки път цялото име на накой обект, като universe.milkyway.earth.europe.bg.beautify()



from universe.milkyway.earth.europe.bg import beautify
beautify()

Или даже:


from universe.milkyway.earth.europe.bg import beautify as b
b()

from mod import *

Хубаво ли ви е така:

from mod import a,b,c,d,e,f,g,h,i,j,k,l

И на мен. Затова Python ни позволява да внесем в нашия модул всички имена от някой друг: from mod import *

  • Имената от типа _име не се внасят
  • Имената от типа __име__ не се внасят
  • Ако в mod има списък с име __all__, то се внасят само имената съдържащи се в него

Още разни модулни неща

  • Съществува модул __builtin__, който съдържа всички вградени функции и други имена:
    import __builtin__
    __builtin__.dir = abs
    print dir(-3)
  • модулите се импортират само веднъж:
    >>> import world
    >>> world.save('babas')
    All the babas were saved.
    >>> world.save = 5
    >>> import world
    >>> world.save
    5
    За презареждане трябва да се ползва reload():
    >>> world.save
    5
    >>> reload(world)
    >>> world.save

Няма коментари:

Публикуване на коментар