Reglas de importación de paquetes de Python3

Para reimpresión, indique la fuente.
win10 + Python 3.6.3

Una vez que se utiliza la estructura de archivos de múltiples capas , es fácil encontrar pits de importación . Jaja.

1. Comprender algunos conceptos básicos

1. Módulo, paquete
** Módulo módulo: ** Generalmente, es un archivo con el sufijo .py . Otros tipos de archivos que pueden utilizarse como módulos incluyen ".pyo", ".pyc", ".pyd", ".so" y ".dll", pero los principiantes de Python rara vez los utilizan.
El módulo se puede considerar como una clase de herramienta, que puede compartir u ocultar detalles del código. Coloque el código relacionado en un módulo para que el código sea más fácil de usar y comprender, y deje que el codificador se concentre en la lógica de alto nivel.
El módulo puede definir funciones, clases, variables y también puede contener código ejecutable. Hay 3 tipos de fuentes de módulos:
①módulos incorporados de Python (biblioteca estándar); ②módulos de
terceros; ③módulos personalizados
.

Paquete:  para evitar conflictos de nombres de módulos, Python introduce un método para organizar módulos según directorios, llamados paquetes. Un paquete es una carpeta que contiene módulos de Python.
Escriba la descripción de la imagen aquí
Cuando hay una carpeta siguiente,    init    .py , la carpeta está destinada a un paquete (paquete), una pluralidad de módulos (Módulo1) que forman un todo bajo, y estos módulos (Módulo1) están disponibles a través del mismo paquete (paquete) Importar otros códigos.

Donde    el    archivo  init .py para el paquete de tejidos (Package), facilita la gestión de referencia entre los distintos módulos, controla el comportamiento del paquete introducido.
El archivo no puede escribir nada, es decir, es un archivo vacío (cuando está vacío, no se puede hacer nada con el formulario de importación [el paquete]), y puede existir, lo que equivale a una marca.
Pero para usar este formulario desde la redacción de import * pacakge_1, en necesidad   init   .py el add:    All     = ['FILE_A', 'FILE_B'] y allí file_a.py inferior file_b.py # package_1, cuando se introduzca    init    El archivo .py ser ejecutado.
Pero no se recomienda en    los    módulos de escritura init .py para garantizar que el archivo sea simple. Pero, ¿puede    el init    .py importar los módulos que necesitamos, para evitar inducciones, fáciles de usar.

Entre ellos,    todo    es una variable importante que se utiliza para especificar qué módulos (módulos) se importarán al [alcance actual] cuando se importe este paquete *. Los módulos que no están en la lista de    todos    no serán referenciados por otros programas. Puede reescribir   todo   , como    all     = ['nombre del módulo 1 del paquete actual', 'nombre del módulo 1'], si esto está escrito, se importará de acuerdo con el nombre del módulo en la lista.

En la importación difusa, el formulario es como el de la importación de paquetes *, * está definido por __all__.

Importe con precisión, como desde la importación de paquetes *, import package.class.

   La ruta    también es una variable común, una lista y, por defecto, solo hay un elemento, la ruta del paquete actual. La modificación de la    ruta    puede cambiar la ruta de búsqueda en el paquete.

Cuando introdujimos un paquete (Package) (se cargará    el    módulo de definición init .py , y luego ejecutará el otro código), en realidad se introducirá    el    archivo init .py (importar, el archivo se ejecuta automáticamente, ayuda Vamos a importar varios módulos en el paquete). Podemos reintroducir    el init    .py con otros paquetes (paquete) o módulos o clases personalizadas.

2. sys.modules, espacio de nombres, atributos incorporados del módulo
2.1
Explicación oficial de sys.modules : La vinculación de
sys.modules  es un diccionario que asigna los nombres de los módulos (module_name) a los módulos cargados (módulos). Se puede usar para forzar la recarga de módulos. Tan pronto como se inicie Python, se cargará en la memoria.
Cuando importamos nuevos módulos, sys.modules registrará automáticamente el módulo; cuando importamos el módulo por segunda vez, Python lo buscará en el diccionario directamente para acelerar la ejecución.

Es un diccionario , por lo que tiene todos los métodos del diccionario, como sys.modules.keys (), sys.modules.values ​​(), sys.modules ['os']. Pero no reemplace el diccionario fácilmente ni elimine un elemento del diccionario, ya que puede hacer que Python no se ejecute.

<span style="color:#000000"><code>import sys
print(sys.modules)#打印,查看该字典具体内容。
</code></span>
  • 1
  • 2

2.2 Espacio de nombres
Como un dict, la clave es el nombre de la variable y el valor es el valor de la variable.

  • Cada función tiene su propio espacio de nombres, llamado espacio de nombres local , que registra las variables de la función.
  • Cada módulo de módulo tiene su propio espacio de nombres, llamado espacio de nombres global , que registra las variables del módulo, incluidas funciones, clases, módulos importados, variables a nivel de módulo y constantes .
  • El espacio de nombres integrado contiene funciones integradas y excepciones, a las que puede acceder cualquier módulo.

Cuando cierta parte del código de Python accede a la variable x, Python buscará la variable en todos los espacios de nombres en el orden:

  1. el espacio de nombres local es la función o método de clase actual. Si lo encuentra, deje de buscar;
  2. el espacio de nombres global es el módulo actual. Si lo encuentra, deje de buscar;
  3. espacio de nombres incorporado Python asumirá que la variable x es una función o variable incorporada. Si la variable x no es una función incorporada o una variable incorporada, Python informará un error NameError.
  4. Para los cierres, si la variable no se puede encontrar en el espacio de nombres local, el siguiente objetivo de búsqueda es el espacio de nombres local de la función principal.

Ejemplo: código namespace_test.py

<span style="color:#000000"><code>def func(a=1):
	b = 2
	print(locals())#打印当前函数(方法)的局部命名空间
	'''
	locs = locals()#只读,不可写。将报错!
	locs['c'] = 3
	print(c)
	'''
	return a+b
func()
glos = globals()
glos['d'] = 4
print(d)

print(globals())#打印当前模块namespace_test.py的全局命名空间
</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

Las funciones integradas locals () y globals () devuelven un diccionario. Diferencia: el primero es de solo lectura, el segundo se puede escribir.

El espacio de nombres  se refleja en from module_name import e import module_name: la palabra clave from es una parte del módulo o paquete importado.

  1. from module_A import X: La función / variable del módulo se importará al espacio de nombres del módulo actual, no es necesario usar module_A.X para acceder.
  2. import module_A: Modules_A en sí se importa, pero su espacio de nombres original se guarda, por lo que es necesario utilizar module_A.X para acceder a sus funciones o variables.

2.3 Atributos integrados del módulo

  1.    El nombre    ejecuta el módulo directamente, el valor del    nombre    es    principal    ; el módulo de importación, el valor del    nombre    es el nombre del módulo.
  2.    archivo    ruta absoluta del módulo actual
  3.    dictar   
  4.    Doc   
  5.    paquete   
  6.    camino   

3. Importación absoluta, importación relativa
Escriba la descripción de la imagen aquí
3.1 Importación absoluta : Todas las importaciones de módulos comienzan desde el "nodo raíz". La ubicación del nodo raíz está determinada por la ruta en sys.path, y el directorio raíz del proyecto suele estar automáticamente en sys.path. Si desea que el programa se ejecute en todas partes, debe modificar manualmente sys.path.
Ejemplo 1: Importar paquete B / subpaquete B1 / módulo b1.py en c.py

<span style="color:#000000"><code>import sys,os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))#存放c.py所在的绝对路径

sys.path.append(BASE_DIR)

from B.B1 import b1#导入B包中子包B1中的模块b1
</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Ejemplo 2: Importar módulo b2.py en b1.py

<span style="color:#000000"><code>from B.B1 import b2#从B包中的子包B1中导入模块b2
</code></span>
  • 1

3.2 Importación relativa : solo hay que preocuparse por la posición del módulo en relación con su directorio actual. No se puede ejecutar directamente dentro del paquete (se informará del error). No importa dónde esté el nodo raíz, la posición relativa de los módulos en el paquete es correcta.
código b1.py

<span style="color:#000000"><code>#from . import b2 #这种导入方式会报错。
import b2#正确
b2.print_b2()
</code></span>
  • 1
  • 2
  • 3

código b2.py

<span style="color:#000000"><code>def print_b2():
	print('b2')
</code></span>
  • 1
  • 2

Ejecute b1.py e imprima: b2.

Al usar la importación relativa, puede encontrar ValueError: Intento de importación relativa más allá del paquete de nivel superior
Solución: Consulte este artículo, enlace .

3.3 Importar un paquete por separado: al importar un nombre de paquete por separado , no se importarán todos los submódulos contenidos en el paquete.
c.py importa el módulo b2 del subpaquete B1 del paquete del mismo nivel de directorio B y ejecuta el método print_b2 () del módulo b2:
código c.py

<span style="color:#000000"><code>import B
B.B1.b2.print_b2()
</code></span>
  • 1
  • 2

Ejecute c.py, se informará un error.

Solución : código
B /    init    .py

<span style="color:#000000"><code>from . import B1#其中的.表示当前目录
</code></span>
  • 1

Código B / B1 /    init    .py

<span style="color:#000000"><code>from . import b2
</code></span>
  • 1

En este punto, ejecute c.py e imprima correctamente: b2.

3.4 Extra
① Un archivo .py llama a la clase en otro archivo .py.
Por ejemplo, a.py (clase A), b.py (clase B), a.py llama a la clase B en b.py con: from b import B
②La clase en un archivo .py hereda la clase en otro archivo .py . Por ejemplo, a.py (clase A), b.py (clase B), la clase A en a.py hereda la clase B en b.py.

<span style="color:#000000"><code>from b import B
class A(B):
pass
</code></span>
  • 1
  • 2
  • 3

2. Mecanismo operativo de Python: ¿comprende qué hace Python cuando ejecuta la declaración de importación (importando un módulo integrado (propio de Python) o de terceros (ya en sys.path))?

paso1: crea un nuevo objeto de módulo vacío (puede contener varios módulos);
paso2: inserta el objeto de módulo en sys.modules; paso3
: carga el código del módulo (si es necesario, compila primero);
paso4: ejecuta el código correspondiente en el nuevo módulo.

Al ejecutar el paso 3, primero busque la ubicación del programa del módulo. Si el nombre del módulo importado es mod_1, el intérprete debe encontrar el archivo mod_1.py. El orden de búsqueda es:
ruta actual (o sys.path especificado en el directorio actual) - - -> PYTHONPATH -----> Ruta predeterminada relacionada con la configuración de instalación de Python.

Para aquellos que no están en sys.path, debe evitar importar submódulos de paquetes personalizados con importación, y usar la importación absoluta o relativa desde ... importar ..., y la importación relativa de paquetes solo puede usar el formulario from.

1. Importación "estándar", importación superior
Escriba la descripción de la imagen aquí
Con los conocimientos básicos anteriores, es fácil comprender este mapa mental. Al usar las variables o funciones del módulo, será útil.

2. Importación anidada

2.1 Orden importación-importación
Escriba la descripción de la imagen aquí

PD: El espacio de nombres local de cada módulo es independiente . Es decir:  después de importar el
módulo de prueba al módulo A, solo se puede acceder al módulo A, no al módulo B. Aunque el módulo B se ha cargado en la memoria, para acceder a él, el módulo B debe importarse explícitamente en el módulo de prueba. En realidad imprime locals (), solo moduleA en el diccionario, no moduleB.

2.2 La importación de bucle / importación-importación anidada
Escriba la descripción de la imagen aquí
es como la declaración ClassB de importación del módulo B , de acuerdo con el mecanismo de importación interno de Python , realice los pasos de subdivisión:

  1. Busque el símbolo "moduleB" en sys.modules;
  2. Si el símbolo "móduloB" existe, se obtiene el objeto de módulo correspondiente al símbolo "móduloB", el objeto correspondiente al símbolo "ClaseB" se obtiene
    del    dict__. Si "ClassB" no existe, lanza una excepción "ImportError: can't import name'classB '"
  3. Si el símbolo "móduloB" no existe, cree un nuevo objeto de módulo. Sin embargo, el    dict    del nuevo objeto de módulo está vacío en este momento . Luego ejecute las declaraciones en el archivo moduleB.py para completar el    dict    .

Resumen: desde moduleB import ClassB tiene dos procesos , primero desde module, luego import ClassB.
Escriba la descripción de la imagen aquí

Por supuesto, cambie la declaración moduleA.py de moduleB import ClassB a: import moduleB, y se informará un error cuando la declaración moduleB.py de moduleA import ClassA se ejecute por segunda vez: ImportError: no se puede importar el nombre 'classA'

Para resolver este método de importación circular:
Ejemplo: al instalar una tarjeta de red inalámbrica, debe descargar el controlador
de latarjeta de redde Internet; alinstalar un software de compresión, el programa de instalación de software comprimido descargado de Internet es un archivo comprimido.
Método 1 -----> Importación diferida: escriba la declaración de importación en el método / función y limite su alcance al local. (Este método puede causar problemas de rendimiento)
Método 2 ----->Cambiarde x import y para importar el formulario xy
Método 3 -----> Organizar el código (código de refactorización): cambiar el diseño del código, que se puede combinar o separados Compitiendo por los recursos.
Combine -----> escriba todo en un archivo .py;
separe -> extraiga los recursos que deben importarse a un archivo .py de terceros.
En resumen, convierta el bucle en unidireccional.

3, bolsa (paquete) se importa
en un archivo mientras que    init    .py documentos, archivos y otros módulos, es decir, la carpeta como una bolsa (paquete). Los paquetes de módulo de importación e importación son básicamente lo mismo, solo importe el paquete cuando, se ejecutará    el init    .py, en lugar de la declaración del módulo.
Además, si ** simplemente se introdujo como paquete [Form: import xxx] **, y el paquete    init    .py no ha inicializado explícitamente la operación del otro, es: en este paquete, el módulo  no se introducirá automáticamente. Por supuesto, el paquete se importará con éxito y el nombre del paquete se colocará en el espacio de nombres local del .py actual.
Escriba la descripción de la imagen aquí
Archivo [D: youcaihua \ test \ PkgDemo \ mod.py] archivo
[D: youcaihua \ test \ PkgDemo \ pkg1 \ pkg1_mod.py] archivo
[D: youcaihua \ test \ PkgDemo \ pkg2 \ pkg2_mod.py], tres archivos El mismo código:

<span style="color:#000000"><code>def getName():
	print(__name__)

if __name__ == '__main__':
	getName()
</code></span>

Archivo [D: youcaihua \ test \ test.py]

<span style="color:#000000"><code>import PkgDemo.mod#1
print(locals(),'\n')
import PkgDemo.pkg1#2
print(locals(),'\n')
import PkgDemo.pkg1.pkg1_mod as m1#3
print(locals(),'\n')
import PkgDemo.pkg2.pkg2_mod#4
PkgDemo.mod.getName()#5
print('调用mod.py----', locals(), '\n')
m1.getName()#6
PkgDemo.pkg2.pkg2_mod.getName()#7
</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Después de ejecutar  # 1  , agregue PkgDemo y PkgDemo.mod a sys.modules. En este momento, puede llamar a cualquier clase o función de PkgDemo.mod. Cuando no puede llamar a ningún módulo en el paquete PkgDemo.pkg1 o pkg2. Pero actualmente solamente  existe PkgDemo en el espacio de nombres local del archivo test.py .

Después de ejecutar  # 2  , simplemente cargue PkgDemo.pkg1 en la memoria y sys.modules tendrá tres módulos: PkgDemo, PkgDemo.mod y PkgDemo.pkg1. Sin embargo, cualquier módulo bajo PkgDemo.pkg1 no se carga automáticamente en la memoria, por lo que en este punto: PkgDemo.pkg1.pkg1_mod.getName () será incorrecto. Actualmente, el espacio de nombres local de test.py sigue siendo solo PkgDemo.

 Después de ejecutar el  # 3 , pkg1_mod se cargará en la memoria y sys.modules tendrá cuatro módulos: PkgDemo, PkgDemo.mod, PkgDemo.pkg1, PkgDemo.pkg1.pkg1_mod, y luego PkgDemo.pkg1.pkg1_mod.getName () se puede ejecutar. Debido al uso de as , el espacio de nombres local actual agregará adicionalmente m1 (como un alias de PkgDemo.pkg1.pkg1_mod) y, por supuesto, PkgDemo.

 Después de que se ejecute  # 4 , PkgDemo.pkg2, PkgDemo.pkg2.pkg2_mod se cargarán en la memoria y habrá PkgDemo, PkgDemo.mod, PkgDemo.pkg1, PkgDemo.pkg1.pkg1_mod, PkgDemo.pkg2, PkgDemo.pkg2 en sys .modules. Hay seis módulos de pkg2_mod, por supuesto: el espacio de nombres local actual sigue siendo sólo PkgDemo, m1.

Los números 5 , 6 y 7 pueden, por supuesto, ejecutarse correctamente.

3. ¿Cómo evitar el error de importación del círculo de Python? ¿Cómo evitar el problema de importación circular de Python?

Diseño de código, problemas de diseño (arquitectura), la solución es: convertir el ciclo en unidireccional. Adopte una importación jerárquica, que requiera mucho tiempo, una importación relativa (se recomienda no exceder dos niveles)

Nota: Si ejecuta Python xx.py en la línea de comando y en el IDE, los resultados pueden ser diferentes.

Para reimpresión, indique la fuente.
Referencia:
especificación oficial

Supongo que te gusta

Origin blog.csdn.net/star871016/article/details/112616857
Recomendado
Clasificación