python:__init__.py和from...import的用法总结

本文主旨:

《Pytorch入门与实践》书作者陈云,建议如下格式:

程序文件结构:


__init__.py中代码:

from .alexnet import AlexNet
from .resnet34 import ResNet34
from .squeezenet import SqueezeNet
# from torchvision.models import InceptinV3
# from torchvision.models import alexnet as AlexNet

这样在主函数中就可以这样调用:

from models import AlexNet
或
import models
model = models.AlexNet()
或
import models
model = getattr('models', 'AlexNet')()

其中最后一种写法最为关键,这意味着我们可以通过字符串直接指定使用的模型,而不必使用判断语句,也不必在每次新增加模型后都修改代码。新增模型后只需要在models/__init__.py中加上from .new_module import new_module即可。(注意当前路径下的文件写法".new_module"

所以搜了一些__init__.py 和from...import的相关知识如下:

一、__init__.py 

在Python工程里,当python检测到一个目录下存在__init__.py文件时,python就会把它当成一个模块(module)。Module跟C++的命名空间和Java的Package的概念很像,都是为了科学地组织化工程,管理命名空间。

__init__.py可以是一个空文件,也可以有非常丰富的内容。本文将举一个非常简单的例子,来介绍__init__.py的用法;在本文的最后,我将会再简单介绍__init__.py的设计理念。

1)一个普通的四则运算模块

在不利用__init__.py的情况下,我们来看一个四则运算的例子。我们的工程目录结构如下图所示:

四则运算例子的工程目录结构

如上图,其中,main.py是程序入口,我们用了不同的方式来import四则运算的各个子模块。arithmetic模块实现四则运算;为了展示需要,我们将加减乘除四种运算分别放在不同的代码中。

每个文件的代码如下:

#
# @file main.py
#

import arithmetic.add
import arithmetic.sub as sub

from arithmetic.mul import mul
from arithmetic import dev

def letscook(x, y, oper):
    r = 0
    if oper == "+":
        r = arithmetic.add.add(x, y)
    elif oper == "-":
        r = sub.sub(x, y)
    elif oper == "*":
        r = mul(x, y)
    else:
        r = dev.dev(x, y)

    print("{} {} {} = {}".format(x, oper, y, r))

x, y = 3, 8

letscook(x, y, "+")
letscook(x, y, "-")
letscook(x, y, "*")
letscook(x, y, "/")

#
# @file add.py
#

def add(a, b):
    return a + b

#
# @file sub.py
#

def sub(a, b):
    return a - b

#
# @file mul.py
# 

def mul(a, b):
    return a * b

#
# @file dev.py
#

def dev(a, b):
    return a / b

从代码可以看出,为了使用arithmetic中的某个子模块(main.py中我们展示了四种不同的方式),我们必须使用非常繁琐的import语句;在使用的时候,也有可能需要使用非常繁琐的表达式。如果我们在不同的地方使用arithmetic的子模块,都需要写这么繁琐的import或者使用表达式,你可能会觉得心累。这就是为什么我们需要利用__init__.py来简化我们的使用。

2)利用__init__.py

还是第1小节中的工程目录结构,实现同样的功能,我们在__init__.py中编写了一些代码;同样,我们对main.py进行了一些适当的修改。

修改后__init__.py和main.py的代码如下:

#
# @file main.py
#

import arithmetic as a4

def letscook(x, y, oper):
    r = 0
    if oper == "+":
        r = a4.add(x, y)
    elif oper == "-":
        r = a4.sub(x, y)
    elif oper == "*":
        r = a4.mul(x, y)
    else:
        r = a4.dev(x, y)

    print("{} {} {} = {}".format(x, oper, y, r))

x, y = 3, 8

letscook(x, y, "+")
letscook(x, y, "-")
letscook(x, y, "*")
letscook(x, y, "/")

#
# @file __init__.py
#

import arithmetic.add
import arithmetic.sub
import arithmetic.mul
import arithmetic.dev

add = arithmetic.add.add
sub = arithmetic.sub.sub
mul = arithmetic.mul.mul
dev = arithmetic.dev.dev

在__init__.py中, 我们import了arithmetic下的所有子模块,并在__init__.py中给各个子模块的核心功能取了新的名字,作为arithmetic模块的变量。所以我们在main.py中import了arithmetic模块之后,就可以直接进行使用了。如果你使用from arithmetic import * 语句,那么我们就可以使用add、sub、mul、dev,连a4都省了。

3)__init__.py的设计原则

__init__.py的原始使命是声明一个模块,所以它可以是一个空文件。在__init__.py中声明的所有类型和变量,就是其代表的模块的类型和变量,第2小节就是利用这个原理,为四则运算的4个子模块声明了新的变量。我们在利用__init__.py时,应该遵循如下几个原则:

A、不要污染现有的命名空间。模块一个目的,是为了避免命名冲突,如果你在种用__init__.py时违背这个原则,是反其道而为之,就没有必要使用模块了。

B、利用__init__.py对外提供类型、变量和接口,对用户隐藏各个子模块的实现。一个模块的实现可能非常复杂,你需要用很多个文件,甚至很多子模块来实现,但用户可能只需要知道一个类型和接口。就像我们的arithmetic例子中,用户只需要知道四则运算有add、sub、mul、dev四个接口,却并不需要知道它们是怎么实现的,也不想去了解arithmetic中是如何组织各个子模块的。由于各个子模块的实现有可能非常复杂,而对外提供的类型和接口有可能非常的简单,我们就可以通过这个方式来对用户隐藏实现,同时提供非常方便的使用。

C、只在__init__.py中导入有必要的内容,不要做没必要的运算。像我们的例子,import arithmetic语句会执行__ini__.py中的所有代码。如果我们在__init__.py中做太多事情,每次import都会有额外的运算,会造成没有必要的开销。一句话,__init__.py只是为了达到B中所表述的目的,其它事情就不要做啦。

二、from....import用法

看完这章之后对这个 from…import * 语句与 import 区别很是疑惑从别处看完解释理解如下。

首先你要了解 import 与 from…import 的区别。

  • import 模块:导入一个模块;注:相当于导入的是一个文件夹,是个相对路径。
  • from…import:导入了一个模块中的一个函数;注:相当于导入的是一个文件夹中的文件,是个绝对路径。

所以使用上的区别是当引用文件时是:

import   //模块.函数

from…import  // 直接使用函数名使用就可以了

所以

from…import *:是把一个模块中所有函数都导入进来; 注:相当于:相当于导入的是一个文件夹中所有文件,所有函数都是绝对路径。

结论:

from…import *语句与import区别在于:

import 导入模块,每次使用模块中的函数都要是定是哪个模块。

from…import * 导入模块,每次使用模块中的函数,直接使用函数就可以了;注因为已经知道该函数是那个模块中的了。

笔者建议:一般来说,推荐使用 import 语句,避免使用 from … import,因为这样可以使你的程序更加易读,也可以避免名称冲突。

参考文章:

1、from…import * 语句与 import 区别

2、__init__.py的神奇用法 - 知乎

猜你喜欢

转载自blog.csdn.net/qimo601/article/details/123897073