ホームページ  >  記事  >  バックエンド開発  >  Pythonで学習ノートをインポートする

Pythonで学習ノートをインポートする

高洛峰
高洛峰オリジナル
2017-02-03 16:05:201468ブラウズ

はじめに

Python でモジュールを整理するには 2 つの方法があり、1 つは単純な Python ファイルであり、もう 1 つはパッケージであり、複数の Python ファイルが含まれている必要があります。 __init__.py というファイルがあるため、ディレクトリ名がモジュール名になり、パッケージ内の Python ファイルもパッケージ名を使用してインポートできます

インポート構文

インポート構文には 2 種類あります。

1. モジュールを直接インポートします

import Module
import Module as xx

2. モジュール(下位レベルのモジュール、クラス、関数、変数など)からオブジェクトをインポートします

from Module import Name
from Module immport Name as yy

の構文は、オブジェクトのエイリアスを設定するために使用されます(ここでのオブジェクトはモジュール、クラス、関数などを指します)、オブジェクトをインポートします。名前は現在のファイルの名前空間を導入します

次のディレクトリ構造があると仮定します

├── A.py
└── pkg
 ├── B.py
 └── __init__.py

現在のディレクトリには、次のステートメントは有効です

import A
import pkg
import pkg.B
from pkg import B

説明を簡単にするために、以下に構文の例はありません

インポート手順

Python でロードされたすべてのモジュール情報は、インポート時に sys.modules 構造に保存されます。モジュールをインポートする場合、次の手順が実行されます

Aをインポートする場合は、sys.modulesにすでにAがあるかどうかを確認し、存在しない場合はロードされません。 A

AインポートBからの場合、最初にAのモジュールオブジェクトを作成し、次にAを解析し、そこからBを見つけてAの__dict__に入力します

ネストされたインポート

モジュールをインポートするとき、次のことを心配するかもしれませんモジュールが複数回インポートされるとします。 A、B、C という 3 つのモジュールがあるとします。 A は B と C をインポートする必要があり、B は C をインポートする必要があります。そのため、A は import C を 2 回実行し、1 回は自分自身のインポート用に実行します。ただし、上記のインポート手順によると、2回目のインポート時にモジュールがロードされていることがわかり、インポートは繰り返されます

が、エラーが発生します以下の状況で報告されます

#filename: A.py
from B import BB
class AA:pass
 
#filename: B.py
from A import AA
class BB:pass

この時、A.pyを実行してもB.pyを実行してもImportError例外がスローされます。理由は以下の通りです

ファイル A.py が B import BB から実行され、B.py が最初にスキャンされ、A の名前空間に B のモジュール オブジェクトが作成され、B から BB を見つけようとします

B.py の最初の行をスキャンして、実行 from A import AA 、このとき A.py をスキャンします

A.py の 1 行目をスキャンして B から実行 import BB 手順 1 で B のモジュール オブジェクトが作成されているため、BB が直接取得されます。 B のモジュール オブジェクトの __dict__ から、明らかに BB を取得できないため、例外がスローされます

この状況を解決するには、

B import BB から import B に変更する、またはA import AA を import A に変更します

A.py または B.py の 2 行のコードを交換します


つまり、インポート時に注意する必要があるのは、使用する必要があるときにインポートするようにすることです。

パッケージのインポート


ディレクトリ .py ファイルに __init__ がある場合、そのディレクトリは Python パッケージです

パッケージのインポートは、単一のファイルをインポートするのと同じです:

単一のファイルをインポートする場合、ファイル内のクラス、関数、変数はすべてインポート オブジェクトとして使用できます。

パッケージをインポートする場合、サブパッケージ、パッケージ内のファイル、および __init__ のクラス、関数、変数をインポート オブジェクトとして使用できます。 .pyは全てインポートオブジェクトとして利用可能です

以下のようなディレクトリ構造があるとします

pkg
├── __init__.py
└── file.py

__init__.pyの内容は以下の通り

argument = 0
class A:pass

以下の文を同じディレクトリで実行すればOKですpkg

>>> import pkg
>>> import pkg.file
>>> from pkg import file
>>> from pkg import A
>>> from pkg import argument

しかし、次のステートメントは間違っています

>>> import pkg.A
>>> import pkg.argument

ImportError: xxx という名前のモジュールはありません。 import A.B を実行するときは、 A と B の両方がモジュール (ファイルまたはパッケージ) でなければなりません

相対インポートと絶対インポート


絶対インポートの形式は import A.B または from A import B で、相対インポートの形式は from . import B または from ..A import B、. は現在のモジュールを表し、 .. は上位レベルのモジュールを表します。 、...上位レベルのモジュールなどを表します。複数のパッケージがある場合、あるパッケージの内容を別のパッケージからインポートする必要がある場合があります。これにより、絶対インポートが生成されます。これは、エラーが発生する可能性が最も高い場合です。具体的な例で説明しましょう

ディレクトリの構造。は次のとおりです

app
├── __inti__.py
├── mod1
│ ├── file1.py
│ └── __init__.py
├── mod2
│ ├── file2.py
│ └── __init__.py
└── start.py

app/start.py の内容は import mod1.file1 です


app/mod1/file1.py 内容は ..mod2 import file2 からです

分析を容易にするために、次を追加しますすべての py ファイル (__init__.py を含む) を追加します。 print __file__, __name__

app/mod1/file1.py で python file1.py を実行するか、app で python mod1/file1 を実行します。エラーが報告されます ValueError: 非パッケージで相対インポートが試行されました

アプリで python -m mod1.file1 または python start.py を実行すると、エラーが報告されます ValueError: トップレベルのパッケージを超えて相対インポートが試行されました

具体的な理由後で説明しますので、最初に見てみましょう モジュールをインポートするときのルールをいくつか示します

パッケージ構造を明示的に指定しない場合、Python は __name__ に基づいてパッケージ内のモジュールの構造を決定します。最上位モジュールであり、構造がありません。A.B.C 構造の場合、最上位モジュールは A です。

基本的にはこの原則に従います

絶対インポートの場合、モジュールはその最上位モジュールと同じレベルにある独自のサブモジュールまたはモジュールとサブモジュールのみをインポートできます

相対インポートの場合、モジュールはパッケージ構造であり、その最上位モジュール内のモジュールのみをインポートできます


ディレクトリ構造は次のとおりです

A
├── B1
│ ├── C1
│ │ └── file.py
│ └── C2
└── B2

其中A,B1,B2,C1,C2都为包,这里为了展示简单没有列出__init__.py文件,当file.py的包结构为A.B1.C1.file(注意,是根据__name__来的,而不是磁盘的目录结构,在不同目录下执行file.py时对应的包目录结构都是不一样的)时,在file.py中可采用如下的绝对的导入

import A.B1.C2
import A.B2

和如下的相对导入

from .. import C2
from ... import B2

什么情况下会让file.py的包结构为A.B1.C1.file呢,有如下两种

在A的上层目录执行python -m A.B1.C1.file, 此时明确指定了包结构

在A的上层目录建立文件start.py,在start.py里有import A.B1.C1.file,然后执行python start.py,此时包结构是根据file.py的__name__变量来的

再看前面出错的两种情况,第一种执行python file1.py和python mod1/file1.py,此时file.py的__name__为__main__ ,也就是说它本身就是顶层模块,并没有包结构,所以会报错

第二种情况,在执行python -m mod1.file1和python start.py时,前者明确告诉解释器mod1是顶层模块,后者需要导入file1,而file1.py的__name__为mod1.file1,顶层模块为也mod1,所以在file1.py中执行from ..mod2 import file2时会报错 ,因为mod2并不在顶层模块mod1内部。通过错误堆栈可以看出,并不是在start.py中绝对导入时报错,而是在file1.py中相对导入报的错

那么如何才能偶正确执行呢,有两种方法,一种是在app上层目录执行python -m app.mod1.file1,另一种是改变目录结构,将所有包放在一个大包中,如下

   
app
├── pkg
│ ├── __init__.py
│ ├── mod1
│ │ ├── __init__.py
│ │ └── file1.py
│ └── mod2
│ ├── __init__.py
│ └── file2.py
└── start.py

start.py内容改成import pkg.mod1.file1,然后在app下执行python start.py

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家学习或者使用python能带来一定的帮助,如有疑问大家可以留言交流。

更多python中import学习备忘笔记相关文章请关注PHP中文网!

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。