Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Python i importowanie

18 views
Skip to first unread message

Michal M

unread,
Dec 15, 2009, 4:39:30 PM12/15/09
to
Witam

Ostatnio się bardzo zdziwiłem faktem jak działa importowanie w
Pythonie. Taki przykład:

module1.py
------------------------
class Test1(object):
my_var = 'a'

@staticmethod
def change():
Test1.my_var = 'b'
=============
module2.py
-----------------------
import module1

module1.Test1.change()
print module1.Test1.my_var
============
module3.py
----------------------
from module1 import Test1

print Test1.my_var
===========

Zakładając, że wszystko się wykonuje w jednym programie. Najpierw
module2 ustawia zmienną instancji klasy Test1 na wartość 'b'.
Tak więc w module3 spodziewałem się ujrzeć 'b', a jest 'a'.
Wygląda to tak, że from .... import rzeczywiście importuje do swojej
przestrzeni czyli hmm... tak jakby robił kopię obiektu.
Czytając wszelakie materiały nie widziałem (lub przegapiłem, lub nie
zrozumiałem) wzmiankę o takim zachowaniu.

Teraz pytanie, co zrobić, aby w module3 mieć dostęp do TEGO SAMEGO
obiektu Test1 co w module1 i w module2 ale nie musieć pisać za każdym
razem module1.Test1.my_var.

Pozdrawiam
Michał

Łukasz Rekucki

unread,
Dec 15, 2009, 6:15:00 PM12/15/09
to
On Dec 15, 10:39 pm, Michal M <mier...@swietochlowice.org> wrote:
> Witam
>
> Ostatnio się bardzo zdziwiłem faktem jak działa importowanie w
> Pythonie. Taki przykład:
>
> module1.py
> ------------------------
> class Test1(object):
>     my_var = 'a'
>
>     @staticmethod
>     def change():
>         Test1.my_var = 'b'
> =============
> module2.py
> -----------------------
> import module1
>
> module1.Test1.change()
> print module1.Test1.my_var
> ============
> module3.py
> ----------------------
> from module1 import Test1
>
> print Test1.my_var
> ===========
>
> Zakładając, że wszystko się wykonuje w jednym programie.
Ok, ale co jest w tym programie, bo liczy się kolejność importowania
tych modułów.

> Najpierw module2 ustawia zmienną instancji klasy Test1 na wartość 'b'.
> Tak więc w module3 spodziewałem się ujrzeć 'b', a jest 'a'.
> Wygląda to tak, że from .... import rzeczywiście importuje do swojej
> przestrzeni czyli hmm... tak jakby robił kopię obiektu.

Nie. Import .. from .. jedynie dodaje do słownika odpowiednie nazwy,
które prowadzą do tych samych obiektów. Z tego co pamiętam, istnieje
sposób żeby python zaimportował to samo 2 razy, ale nie jest to aż
takie proste. Moduł ten musiałby być dostępny pod dwoma różnymi
nazwami.

Rob Wolfe

unread,
Dec 16, 2009, 4:48:17 AM12/16/09
to

Michal M napisał(a):

Twierdzisz, ze masz np. program `main.py` postaci:
import module2
import module3

i raz widzisz 'a' a raz 'b'?

>
> Teraz pytanie, co zrobić, aby w module3 mieć dostęp do TEGO SAMEGO
> obiektu Test1 co w module1 i w module2 ale nie musieć pisać za każdym
> razem module1.Test1.my_var.

To jest i musi byc ten sam obiekt, o czym mozesz sie latwo przekonac
wyswietlajac sobie wszedzie "id(Test1)".

RW

silver

unread,
Dec 16, 2009, 5:23:47 AM12/16/09
to
W dniu 16.12.2009 10:48, Rob Wolfe pisze:
>
>

>
> Twierdzisz, ze masz np. program `main.py` postaci:
> import module2
> import module3
>
> i raz widzisz 'a' a raz 'b'?
>

Ja zrozumia�em �e robi tak:
1. Pisze program module1.py i tworzy tam jak�� zmienn�
2. Tworzy program module2.py w kt�rym importuje module1.py
3. W programie module2.py zmienia zmiennďż˝ w module1.py
4. W programie module3.py importuje module2.py i pr�buje odczyta�
zmienn�, kt�r� z modu�u module1.py i ma mie� tak� warto�� na jak�
zmieniďż˝ w module.2py

Importy w pythonie dzia�aj� podobnie do header�w w C++. To nie jest
rzeczywisty import rezyduj�cego gdzie� w pami�ci modu�u. To jest de
facto rozszerzenie przestrzeni nazw do kt�rej masz dost�p. Obiekt klasy
Test1 w module2.py jest zupe�nie innym obiektem ni� obiekt w module3.py
Nic dziwnego, �e masz inne warto�ci.

Aby zrobi� to co ty chcesz musia�by� si� zaciekawi� komunikacj�
mi�dzyprocesow�. Zajrzyj do modu�u multiprocessing

--
Pozdrawiam,
silver

silver

unread,
Dec 16, 2009, 5:25:29 AM12/16/09
to
W dniu 16.12.2009 10:48, Rob Wolfe pisze:
>
>

>


> Twierdzisz, ze masz np. program `main.py` postaci:
> import module2
> import module3
>
> i raz widzisz 'a' a raz 'b'?
>

Ja zrozumia�em �e robi tak:
1. Pisze program module1.py i tworzy tam jak�� zmienn�
2. Tworzy program module2.py w kt�rym importuje module1.py
3. W programie module2.py zmienia zmiennďż˝ w module1.py
4. W programie module3.py importuje module2.py i pr�buje odczyta�

zmienn�, kt�r� zmieni� w module module1.py i ma mie� tak� warto�� na

Message has been deleted

Michal M

unread,
Dec 16, 2009, 6:29:38 AM12/16/09
to
Dokładnie tak. Te trzy pliki działały jako jeden program (tak jak w
javie) i jak wstawiałem do module3

from module1 import Lang

to widziałem 'a', a jak wstawiałem

import module1

to widziałem 'b'.

Dlatego moje zdziwienie, bo wyglądało jakby te dwa nie powodowały
tylko udostępnienia obiektu w przestrzeni nazw lokalnego modułu ale
importowały (kopiowały) cały obiekt do tego modułu i tworzyły
instancję. Wtedy obiekt Lang z module1 nie byłby tym samym co ten
zaimportowany w module3.

ALE... dzisiaj dziwnym trafem nie mogę odtworzyć tej sytuacji (ten sam
kod, nie zmieniany) i wszystko działa jak Wy i Ja przewidujecie. Wobec
tego wypada mi tylko przeprosić za zamieszanie i podziękować za
odpowiedzi.


i0cus

unread,
Dec 16, 2009, 6:33:33 AM12/16/09
to
On 16 Gru, 11:23, silver <sil...@niematakiegoemaila.pl> wrote:
> W dniu 16.12.2009 10:48, Rob Wolfe pisze:
>
>
>
> > Twierdzisz, ze masz np. program `main.py` postaci:
> > import module2
> > import module3
>
> > i raz widzisz 'a' a raz 'b'?
>
> Ja zrozumiałem że robi tak:
> 1. Pisze program module1.py i tworzy tam jakąś zmienną
> 2. Tworzy program module2.py w którym importuje module1.py
> 3. W programie module2.py zmienia zmienną w module1.py
> 4. W programie module3.py importuje module2.py i próbuje odczytać
> zmienną, którą z modułu module1.py i ma mieć taką wartość na jaką
> zmienił w module.2py

I fajnie by było, ale OP napisał też:

> Zakładając, że wszystko się wykonuje w jednym programie.

No więc na moje oko dopasowałeś swoją wersję wyjaśnienia do błędu
opisanego przez użytkownika. ;-)

A mnie błąd użytkownika wygląda na (1) brak importu modułu 2, ew. (2)
za kulisami dzieje się coś, co sprawia, że jednak dostaje świeże
instancje Test1(). Python dość uparcie traktuje moduły jako singletony
i wydaje mi się, że przedstawiony przykład zbytnio spłyca obraz
sytuacji (a przede wszystkim nie oddaje opisanego zachowania -- jeśli
zaimportowany zostanie moduł 2 i moduł 3, to wartości są 'b', gdyż
moduł 1 jest ładowany jednokrotnie).


> --
> Pozdrawiam,
> silver

William Bonawentura

unread,
Dec 17, 2009, 2:41:46 AM12/17/09
to

U�ytkownik "Michal M" <mmie...@tycowaterworks.pl> napisa� w wiadomo�ci
news:52950de7-b700-40e0...@x15g2000vbr.googlegroups.com...
> ALE... dzisiaj dziwnym trafem nie mogďż˝ odtworzyďż˝ tej sytuacji (ten sam
> kod, nie zmieniany) i wszystko dzia�a jak Wy i Ja przewidujecie. Wobec
> tego wypada mi tylko przeprosi� za zamieszanie i podzi�kowa� za
> odpowiedzi.

Nie piszesz przypadkiem pod Unixem ? Efekt jaki opisujesz mo�e by�
spowodowany sytuacjďż˝, gdy interpreter nie potrafi nadpisaďż˝ lub utworzyďż˝ .pyc
i ka�dy import powoduje parsowanie .py.

Rob Wolfe

unread,
Dec 17, 2009, 6:29:25 AM12/17/09
to
"William Bonawentura" <ne...@ipartners.pl> writes:

Nic podobnego. Kod i tak jest �adowany tylko raz.

RW

Radomir Dopieralski

unread,
Dec 17, 2009, 12:52:57 PM12/17/09
to
At Wed, 16 Dec 2009 11:23:47 +0100, silver wrote:

> Importy w pythonie działają podobnie do headerów w C++. To nie jest
> rzeczywisty import rezydującego gdzieś w pamięci modułu. To jest de
> facto rozszerzenie przestrzeni nazw do której masz dostęp. Obiekt klasy
> Test1 w module2.py jest zupełnie innym obiektem niż obiekt w module3.py
> Nic dziwnego, że masz inne wartości.

To nie tak. Modul jest jeden - w obrebie jednego programu - zaimportowanie
go wiele razy i tak zawsze zwroci ten sam obiekt, chyba ze sie zrobi
jakies sztuczki z __import__. Include w C i pochodnych dziala kompletnie
inaczej.

Radomir Dopieralski, http://sheep.art.pl

Sebastian Kaliszewski

unread,
Dec 18, 2009, 5:11:07 AM12/18/09
to
silver wrote:
> W dniu 16.12.2009 10:48, Rob Wolfe pisze:
> >
> >
>
> >
> > Twierdzisz, ze masz np. program `main.py` postaci:
> > import module2
> > import module3
> >
> > i raz widzisz 'a' a raz 'b'?
> >
> Ja zrozumia�em �e robi tak:
> 1. Pisze program module1.py i tworzy tam jak�� zmienn�
> 2. Tworzy program module2.py w kt�rym importuje module1.py
> 3. W programie module2.py zmienia zmiennďż˝ w module1.py
> 4. W programie module3.py importuje module2.py i pr�buje odczyta�
> zmienn�, kt�r� zmieni� w module module1.py i ma mie� tak� warto�� na
> jakďż˝ zmieniďż˝ w module.2py
>
> Importy w pythonie dzia�aj� podobnie do header�w w C++.

Bzdura.

> To nie jest
> rzeczywisty import rezyduj�cego gdzie� w pami�ci modu�u. To jest de
> facto rozszerzenie przestrzeni nazw do kt�rej masz dost�p. Obiekt klasy
> Test1 w module2.py jest zupe�nie innym obiektem ni� obiekt w module3.py
> Nic dziwnego, �e masz inne warto�ci.
>
> Aby zrobi� to co ty chcesz musia�by� si� zaciekawi� komunikacj�
> mi�dzyprocesow�.

Co???

> Zajrzyj do modu�u multiprocessing
>

Co ma piernik do wiatraka?


pzdr
\SK
--
"Never underestimate the power of human stupidity" -- L. Lang
--
http://www.tajga.org -- (some photos from my travels)

Sebastian Kaliszewski

unread,
Dec 18, 2009, 5:13:17 AM12/18/09
to
Michal M wrote:
> Dok�adnie tak. Te trzy pliki dzia�a�y jako jeden program (tak jak w
> javie)

Co to znaczy tak jak w Javie?


Poka� ca�o�� -- co importuje co.

Czyli co i gdzie importuje module2 oraz module3.

[...]


> ALE... dzisiaj dziwnym trafem nie mogďż˝ odtworzyďż˝ tej sytuacji (ten sam
> kod, nie zmieniany) i wszystko dzia�a jak Wy i Ja przewidujecie. Wobec
> tego wypada mi tylko przeprosi� za zamieszanie i podzi�kowa� za
> odpowiedzi.

Mo�e jednak co� nie by�o tak samo. Np zapomnia�e� zrobi� "save" w
edytorze (to si� cz�sto zdarza)

Michal M

unread,
Dec 20, 2009, 4:10:52 PM12/20/09
to
Ok, ten sam problem się powtórzył. Tym razem podam dokładnie przykład.

module1.py
log = None

module2.py
class Log(object):
def __init__(self):
pass
def m(self):
print "ok"

module3.py
import module1
import module2
import module4

module1.log = module2.Log()
t = module4.Test()
t.use_m()

module4.py
from module1 import log

class Test(object):
def __init__(self):
pass
def use_m(self):
log.m()


Uruchamiam moduł 3. Ja to widzę tak:
1. importuje moduły 1, 2 i 3 (czyli udostępnia ich przestrzeń poprzez
nazwę modułu w module 3)
2. pod zmienną log w module 1 podstawia instancję klasy Log z modułu 2
3. Pod zmienną t podstawia instancję klasy Test z modułu 4 i próbuje
wykonać jej metodę use_m()
W tym miejscu otrzymuję błąd: AttributeError: 'NoneType' object has no
attribute 'm'

Teraz powiedzmy, że moduł 4 zmienię tak:

module4.py
import module1

class Test(object):
def __init__(self):
pass
def use_m(self):
module1.log.m()

Czyli wg mnie powinno być to samo, tyle że zamiast bezpośrednio do log
mam dostęp poprzez module1.log.
Zastanawiałem się, czy może samo log.m() nie widzi jako zmiennej
lokalnej i nie potrzeba dodać global log ale też nie pomaga.
Proszę o wyjaśnienie.

Pozdrawiam
Michał

marmarprog

unread,
Dec 20, 2009, 4:16:16 PM12/20/09
to
On 16 Gru, 11:25, silver <sil...@niematakiegoemaila.pl> wrote:
> W dniu 16.12.2009 10:48, Rob Wolfe pisze:
>  >
>  >
>
>  >
>  > Twierdzisz, ze masz np. program `main.py` postaci:
>  > import module2
>  > import module3
>  >
>  > i raz widzisz 'a' a raz 'b'?
>  >
> Ja zrozumiałem że robi tak:
> 1. Pisze program module1.py i tworzy tam jakąś zmienną
> 2. Tworzy program module2.py w którym importuje module1.py
> 3. W programie module2.py zmienia zmienną w module1.py
> 4. W programie module3.py importuje module2.py i próbuje odczytać
> zmienną, którą zmienił w module module1.py i ma mieć taką wartość na
> jaką zmienił w module.2py
>
> Importy w pythonie działają podobnie do headerów w C++. To nie jest
> rzeczywisty import rezydującego gdzieś w pamięci modułu. To jest de
> facto rozszerzenie przestrzeni nazw do której masz dostęp. Obiekt klasy
> Test1 w module2.py jest zupełnie innym obiektem niż obiekt w module3.py
> Nic dziwnego, że masz inne wartości.
>
> Aby zrobić to co ty chcesz musiałbyś się zaciekawić komunikacją
> międzyprocesową. Zajrzyj do modułu multiprocessing
>
> --
> Pozdrawiam,
> silver

Po wpisaniu takiego kodu

import module2
import module3


from module1 import Test1
print Test1.my_var

otrzymuje:
b
b
b

Wiec nie wiem w czym jest problem zwłaszcza tych bredni o nie
rzeczywistym importowaniu.

marmarprog

unread,
Dec 20, 2009, 5:02:33 PM12/20/09
to

Python tak działa.
Zmienne można powiedzieć są etykietowane przez nazwę. Oznacza to że
jeżeli użyjemy instrukcji przypisania to przypiszemy danej etykiecie
nowy obiekt np.
log=None # obiekt None otrzymuje etykietę log
b=log # obiekt None otrzymuje nowa etykietę b
# teraz jeśli napiszę
log=3 # obiekt 3 otrzymuje etykietę log ale etykieta b nadal odnosi
sie do obiektu None (tak samo )

Pisząc
module1.log= ...
modyfikujesz tylko etykiete w przestrzeni nazw modułu modul1. tylko
importy wykonane po tej instrukcji będą widzieć ta zmianę.
Ale dosyć tych bredni.
Jeżeli chcesz zamiast module1.log.m() pisać log.m() zrezygnuj z
module2 i napisz w module1

class Log(object):
def __init__(self):
pass
def m(self):
print "ok"

log = None

potem piszesz w dowolmym module
from module1 import log

oczywiście jeśli napiszesz potem "gdzieś" module1.log=... to znów
"gdzieś" odnosić się bedziesz do innego obiektu.
i możesz z obiektu log pakować i doczytywać cokolwiek:

log.xxx=3

a winnym module

print log.xxx

Michal M

unread,
Dec 20, 2009, 5:40:04 PM12/20/09
to

Dzięki za odpowiedź. To nie brednie to pomaga mi zrozumieć to
zachowanie (choć jeszcze tego nie ogarniam). Mnie to po prostu
wyglądało, że log jest importowane do przestrzeni module4 i zmiana
przypisania do tej zmiennej w module 1 nie jest odzwierciedlana w
module4. Inaczej jest jeśli odwołuję się przez module1.log. Wtedy
odwołuję się do zmiennej właśnie w tamtej przestrzeni nazw (module1).
Nie wiem czy to wyjaśnienie jest zbieżne z tym co ty napisałeś (i
prawidłowe) ale tłumaczy to zachowanie i jest tym co chciałem na
początku przekazać w pierwszym poście.
Ze względu na to, że projekt będzie pewnie trochę większy, zrozumienie
tego ma dla mnie duże znaczenie. Dlatego też, nie chciałbym przenosić
log do modułu w którym jest Log bo chciałbym takie rzeczy trzymać
razem w jednym module aby się później nie pogubić (gdzie ja to
umieściłem.)

Jeszcze raz dziękuję za wyjaśnienie i pozdrawiam.

Łukasz Rekucki

unread,
Dec 20, 2009, 8:26:12 PM12/20/09
to
Używanie terminów zmienna i przestrzeń nazw wydaje mi się myląca.
Podstawą jest zrozumienie, że "log" w Pythonie nie jest zmienną, a
jedynie nazwą wskazującą na jakiś obiekt. Tak więc sytuacja wygląda
tak:

0) zaczynasz wykonywanie module3
1) import module1
1.1) do słownika modułu module1 dodawana jest nazwa "log" wskazująca
na obiekt None
2) import module2
2.1) wykonywane jest ciało klasy Log
2.2) do nazwy Log w module2 przypisywana jest nowo utworzona klasa Log
3) import module4
3.1) from module1 import log
3.1.1) moduł "module1" jest już zaimportowany, więc odczytywane jest
na jaki obiekt wskazuję nazwa "log" w jego słowniku (jest to None)
3.1.2) w słowniku module4 tworzona jest nowa nazwa i wskazuje ona na
None
3.2) Tworzona jest klasa Test (analogicznie do klasy Log)
4) module1.log = module2.Log() # nazwa log w słowniku module1
wskazuję teraz na nowy obiekt klasy Log. Słownik module4 jest
niezmieniony.
5) t = module4.Test()
6) t.use_m()
6.1) log nie jest lokalne dla use_m, więc jest globalne. Globalnym
kontekstem dla use_m() jest module4. module4.log wskazuję na None ->
błąd.

Michal M

unread,
Dec 21, 2009, 3:39:31 AM12/21/09
to

Czyli
from module1 import log
Tworzy nową zmienną (etykietkę jak wy to nazywacie) w przestrzeni
(słowniku) module4 i podstawia pod nią referencję (akurat None, bo się
jeszcze nie wykonało podstawienie instancji Log).
Natomiast
import module1
module1.log
Wskazuje na tą samą zmienną którą zmieniam w module1.
Innymi słowy, po
from module1 import log
mam dwie etykietki log i są one niezależne od siebie.
Muszę z tym uważać
Rozwiązaniem wygodnym byłoby zapisanie w module 4
import module1
log = module1.log
... gdyby nie to, że w każdej funkcji musiałbym dodać
global log
tak?
Wtedy gra nie warta świeczki.

No cóż... każdy język ma swoje udziwnienia. :)

Dziękuję wszystkim za wyjaśnienia.

Michal M

unread,
Dec 21, 2009, 3:44:28 AM12/21/09
to
Przepraszam, że odpowiadam sobie ale nie mogłem wyedytować
poprzedniego postu.

Jeszcze takie pytanie. Gdybym zrobił tak:

module4.py

class Test(object):
def __init__(self):
from module1 import log
pass
def use_m(self):
log.m()


Czyli zaimportował de facto log po podstawieniu pod niego instancji
Log, to powinno działać? Jeśli umieszczę import w funkcji to
zaimportuje do słownika głównego modułu czy do lokalnego funkcji? Da
się tak w ogóle?
(nie jestem tutaj w stanie sprawdzić)

Bart Ogryczak

unread,
Dec 21, 2009, 6:05:50 AM12/21/09
to
On Dec 20, 10:10 pm, Michal M <mmier...@tycowaterworks.pl> wrote:
> Tym razem podam dokładnie przykład.


Ok, to co tak naprawdę robisz:

>>> m1 = {'log': None}
>>> m2 = {'Log': 'klasa Log'}
>>> m4 = {'log': m1['log']}
>>> m1['log'] = m2['Log']
>>> m1, m2, m4
({'log': 'klasa Log'}, {'Log': 'klasa Log'}, {'log': None})

Michal M

unread,
Dec 21, 2009, 7:54:37 AM12/21/09
to

Prosto, zwięźle i jasno. Nic dodać, nic ująć. Dziękuję. :)

Michal M

unread,
Jan 10, 2010, 9:53:43 AM1/10/10
to
Siedzę w tym Pythonie już jakiś czas i niestety co chwilę stwierdzam,
że to importowanie jest zdrowo po....

przykład:

p1.m2
----------
import m1
import p2.m3

print m1.A.counter
a = m1.A()
print m1.A.counter
p2.m3.get()

p1.m1
---------
class A(object):
counter = 0
def __init__(self):
A.counter = 1

p2.m3
---------
import p1.m1

def get():
print "w def m3: " + str(p1.m1.A.counter)


Po uruchomieniu m2:
0
1
w def m3: 0

Długo kombinowałem jak sprawić aby w m3 widział obiekt A taki jakim
jest naprawdę. i w końcu wyszło, że trzeba przerobić m2:

p1.m2
---------

import p1.m1
import p2.m3

print p1.m1.A.counter
a = p1.m1.A()
print p1.m1.A.counter
p2.m3.get()


Teraz wynik jak oczekiwano:
0
1
w def m3: 1

Tylko, że przy pisaniu większego programu z setkami modułów
rozrzuconych po różnych paczkach to staje się horrorem. Już teraz ok.
80% czasu zajmuje mi kombinowanie z importowaniem aby wszędzie było
widziane to co ma być. Już nie mówię o zmorze cyklicznych odwołań
pomiędzy modułami.

Jest na to jakiś sposób, żeby to opanować?
Jakieś rady?
Tak, próbowałem i ciągle próbuję to zrozumieć ale co chwila się łapie
na tym, że już mi się wydawało, że wszystko ok i znowu coś nie działa.


Łukasz Rekucki

unread,
Jan 10, 2010, 11:06:31 AM1/10/10
to
Jeśli masz moduł p1.m2 i chcesz zaimportować moduł p1.m1, to
powinieneś zawsze pisać "import p1.m1". To, że "import m1" w ogóle
działa, to jest efekt uboczny i takie zachowanie jest "Deprecated". W
py3k w ogóle nie znalazł by takiego modułu. W 99% przypadków jeśli
twój program wymaga cyklicznych odwołań, to jest z nim coś nie tak.

Bart Ogryczak

unread,
Jan 11, 2010, 7:38:20 AM1/11/10
to

Coś jest totalnie nie tak z architekturą twoich modułów.
Ja bym zrobił na przykład tak:

p2.m3
---------

class A:
"""abstrakcyjna klasa do nadpisania przez inny moduł"
__init__():
raise NotImplementedError

def get():
counter = A()
    print "w def m3: " + str(counter)

p1.m2
----------
import m1
import p2.m3

print m1.A.counter
a = m1.A()
print m1.A.counter

p2.m3.A = m1.A
p2.m3.get()


0 new messages