Wprowadzenie część 3

Generatory

range vs xrange


In [1]:
range(2), xrange(2)


Out[1]:
([0, 1], xrange(2))

In [2]:
def gen(r):
    for i in xrange(r):
        yield i ** 2

In [3]:
generator = gen(5)
generator


Out[3]:
<generator object gen at 0x109245550>

In [4]:
list(generator)


Out[4]:
[0, 1, 4, 9, 16]

In [5]:
generator = (i ** 2 for i in xrange(5))
generator


Out[5]:
<generator object <genexpr> at 0x1092458c0>

In [6]:
list(generator)


Out[6]:
[0, 1, 4, 9, 16]

In [1]:
def gen_squares(up_to=100000):
    s = 0
    for sq in (i**2 for i in xrange(up_to)):
        s += sq
    return s

def squares(up_to=100000):
    s = 0
    for sq in [i**2 for i in xrange(up_to)]:
        s += sq
    return s

In [2]:
%memit gen_squares()


peak memory: 25.87 MiB, increment: 0.16 MiB

In [3]:
%memit squares()


peak memory: 30.41 MiB, increment: 4.50 MiB

Moduły

Architektura programu w Pythonie

a.py - plik najwyższego poziomu
b.py, c.py - moduły

Trochę teorii

  • instrukcje modułów wykonywane są przy pierwszej operacji importowania
  • przypisania na najwyższym poziomie pliku tworzą atrybuty modułu
  • dostęp do przestrzeni nazw modułu odbywa się za pomoca atrybutu __dict__ lub dir(M), oznacza to ze przestrzenie nazw modułów są słownikami.
  • moduły są jedynym zakresem (lokalne jest w nich globalnym)

Zakres pliku modułu staję się przestrzenią nazw atrybutów obiektu modułu i istnieje po zaimportowaniu.

Co robi python importując?

  1. Odnalezienie pliku modułu
  2. Skompilowanie go do kodu bajtowego (jeśli to konieczne). (sprawdzane po datach)
  3. Wykonanie kodu moduły w celu utworzenia definiowanych przez niego obiektów.

Wyszukiwanie modułu

  1. Katalog główny programu.
  2. Katalogi PYTHONPATH (jesli ustawione)
  3. Katalogi biblioteki standardowej.
  4. Zawartosc plików .pth (jeśli obecne)

In [7]:
import sys
sys.path[-2:]


Out[7]:
['/Library/Python/2.7/site-packages',
 '/usr/local/lib/python2.7/site-packages/IPython/extensions']

Co można zaimportować?

  • Plik z kodem źródłowym o nazwie b.py
  • Plik z kodem bajtowym o nazwie b.pyc
  • Katalog o nazwie b w przypadku importowania pakietów
  • Skompilowany moduł rozszerzenia, zazwyczaj napisany w jezykach C lub C++ i dynamiczne dołaczany w momencie importowania (np. b.so w systemie Linux, b.dll lub b.pyd dla Cygwin i Windows)
  • Skompliowany moduł wbudowany napisany w C i statycznie dołączony do Pythona
  • Komponent pliku ZIP rozpakowywany automatycznie po zaimportowaniu
  • Klase z Javy w Jython’ie
  • Komponent z .NET w IronPython’ie

Jak nazywać?

Moduły powinny być nazywane zgodnie z normalnymi regułami dotyczącymi nazw zmiennych.
Jeśli nazwiemy moduł if.py, nie bedziemy mogli go zaimportowac.

Importowanie


In [ ]:
# %load mod.py

def printer(x):
    print x

ATTR = 1
MUTABLE = [1, 2, 3]

In [12]:
import mod
mod.printer("bla bla")


bla bla

In [13]:
from mod import printer
printer("bla bla")


bla bla
from module import (
    name1, 
    name2,
)

jest odpowiednikiem:

import module
name1 = module.name1
name2 = module.name2
del module

Importowanie odbywa się tylko raz!


In [14]:
import mod
mod.ATTR


Out[14]:
1

In [15]:
mod.ATTR = 231
mod.ATTR


Out[15]:
231

In [16]:
import mod
mod.ATTR


Out[16]:
231

In [ ]:
%%javascript 
IPython.notebook.kernel.restart();


Uwagi


In [ ]:
# %load mod.py

def printer(x):
    print x

ATTR = 1
MUTABLE = [1, 2, 3]

In [1]:
from mod import ATTR, MUTABLE

In [2]:
ATTR = 1
MUTABLE[2] = 12

In [3]:
import mod

In [4]:
mod.ATTR, mod.MUTABLE


Out[4]:
(1, [1, 2, 12])

In [ ]:
# %load a.py

def fun():
    print "jestem w a"

In [ ]:
# %load b.py

def fun():
    print "jestem w b"

In [8]:
from a import fun
from b import fun
fun()


jestem w b

In [9]:
import a
import b
a.fun()
b.fun()


jestem w a
jestem w b

Zakresy

1


In [ ]:
# %load moda.py
X = 88


def f():
    global X
    X = 99

In [ ]:
# %load modb.py
X = 11

import moda

moda.f()
print(X, moda.X)

Co zwróci odpalanie modb.py, a co zaimportowanie X z moda?


In [14]:
%run modb.py


(11, 99)

In [ ]:
%%javascript 
IPython.notebook.kernel.restart();



In [38]:
from moda import X
X


Out[38]:
88

2


In [ ]:
# %load mod1.py
x = 1
import mod2
print(x, mod2.x, mod2.mod3.x)

In [ ]:
# %load mod2.py
x = 2
import mod3
print(x, mod3.x)

In [ ]:
# %load mod3.py
x = 3

Co zwróci uruchmienie mod1.py ?


In [9]:
%run mod1.py


(2, 3)
(1, 2, 3)

__init__.py


In [13]:
!tree module/


module/
├── __init__.py
└── dir1
    ├── __init__.py
    └── mod.py

1 directory, 3 files

In [ ]:
# %load module/__init__.py
print "module"
x = 1

In [ ]:
# %load module/dir1/__init__.py
print "dir1"
y = 2

In [ ]:
# %load module/dir1/mod.py
print "mod.py"
z = 3

In [17]:
import module.dir1.mod


module
dir1
mod.py

In [18]:
import module.dir1.mod

In [19]:
module.x


Out[19]:
1

In [20]:
module.dir1.y


Out[20]:
2

In [21]:
module.dir1.mod.z


Out[21]:
3

Importy względne

from . import spam from .. import spam

Nie jest to jednak dobrą praktyką - lepiej pisać importy absolutne - python3 je wymusza :)

__name__


In [ ]:
# %load name.py
print __name__

In [25]:
import name


name

In [26]:
%run name


__main__

Stąd:

if __name__ == '__main__':
   main()

Kolejność funkcji w modułach


In [ ]:
# %load kolejnosc.py
func1()


def func1():
    print(func2())

func1()


def func2():
    return("No witam")

func1()

In [28]:
%run kolejnosc.py


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/Users/nozdi/PyCircle/presentations/wprowadzenie_3/kolejnosc.py in <module>()
----> 1 func1()
      2 
      3 
      4 def func1():
      5     print(func2())

NameError: name 'func1' is not defined

In [ ]:
# %load kolejnosc.py
# func1()


def func1():
    print(func2())

func1()


def func2():
    return("No witam")

func1()

In [30]:
%run kolejnosc.py


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/Users/nozdi/PyCircle/presentations/wprowadzenie_3/kolejnosc.py in <module>()
      5     print(func2())
      6 
----> 7 func1()
      8 
      9 

/Users/nozdi/PyCircle/presentations/wprowadzenie_3/kolejnosc.py in func1()
      3 
      4 def func1():
----> 5     print(func2())
      6 
      7 func1()

NameError: global name 'func2' is not defined

In [ ]:
# %load kolejnosc.py
# func1()


def func1():
    print(func2())

# func1()


def func2():
    return("No witam")

func1()

In [32]:
%run kolejnosc.py


No witam

Referencje


In [ ]:
# %load first.py
x = 1


def printer():
    print(x)

In [ ]:
# %load sec.py
from first import x, printer

x = 88
printer()

Co się stanie jak odpalimy sec.py?


In [35]:
%run sec.py


1

Zadanie

Stwórz bibliotekę do rysowania w konsoli kształtów różnych figur.
Wymagania:

  1. zawiera katalog z modułem/ami w środku
  2. zawiera skrypt wykonawczy który będzie coś wyświetał tylko jeżeli odpali się go bezpośrednio
  3. można narysować o zadanych wymiarach kwadrat, prostokąt, trójkąt, wiatraczek

In [ ]:
from rozwiazania import *

In [35]:
prostokat(4, 10)


##########
##########
##########
##########

In [36]:
kwadrat(5)


#####
#####
#####
#####
#####

In [37]:
trojkat(4)


#    
##   
###  
#### 

In [34]:
wiatraczek(10)


##########         #
 #########        ##
  ########       ###
   #######      ####
    ######     #####
     #####    ######
      ####   #######
       ###  ########
        ## #########
         ###########
###########         
######### ##        
########  ###       
#######   ####      
######    #####     
#####     ######    
####      #######   
###       ########  
##        ######### 
#         ##########