如何让Python导入更有结构性?

13 投票
6 回答
14581 浏览
提问于 2025-04-17 01:59

这段代码能运行,但看起来有点乱,所以我在想这可能是个代码审查的问题。我对Python的规范了解得不够,没弄明白怎么更“Pythonic”地组织和结构化文件的开头。其实我只是把导入的部分直接粘贴上去,可能有重复的、不需要的,或者顺序搞错了。你能给我一些建议,告诉我怎么整理我的导入部分吗?还是说我可以这样留着,专注于我自己的函数?

文件1:

from __future__ import with_statement
import logging
import os
from google.appengine.api.users import is_current_user_admin, UserNotFoundError
import time
import cgi
import geo.geotypes
import main
import captcha
from google.appengine import api
from google.appengine.runtime import DeadlineExceededError
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.blobstore import BlobInfo
from google.appengine.ext.db import djangoforms
from django import forms
from django.core.exceptions import ValidationError
from django.utils import translation
from datetime import datetime, timedelta
os.environ['DJANGO_SETTINGS_MODULE'] = 'conf.settings'
from django.conf import settings
from django.template import RequestContext
from util import I18NHandler
import util
from google.appengine.api import urlfetch, taskqueue
from django.template.defaultfilters import register
from django.utils import simplejson as json
from functools import wraps
from google.appengine.api import urlfetch, taskqueue, users, images
from google.appengine.ext import db, webapp, search, blobstore
from google.appengine.ext.webapp import util, template
from google.appengine.runtime import DeadlineExceededError
from random import randrange
import Cookie
import base64
import cgi
import conf
import datetime
import hashlib
import hmac
import logging
import time
import traceback
import urllib
import twitter_oauth_handler
from twitter_oauth_handler import OAuthClient
from geo.geomodel import GeoModel
from django.utils.translation import gettext_lazy as _
webapp.template.register_template_library('common.templatefilters')

文件2(这里有几个我不理解的指令):

from __future__ import with_statement
                # -*- coding: utf-8 -*-
import facebookconf
import os, wsgiref.handlers
os.environ[u'DJANGO_SETTINGS_MODULE'] = u'conf'
import util
import time
import logging
import urllib
import wsgiref.handlers
import appengine_admin
import cgi
import captcha
import re
import hashlib
import string
import hmac
import twitter_oauth_handler
from twitter_oauth_handler import OAuthClient
os.environ['DJANGO_SETTINGS_MODULE'] = 'conf.settings'
from geo.geomodel import GeoModel
from google.appengine.dist import use_library
from google.appengine.ext import blobstore, webapp, db, search
# template import must be run before other Django modules imports
from google.appengine.ext.webapp import blobstore_handlers, util, template
from google.appengine.ext.blobstore import BlobInfo
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.api import files, images, mail, memcache, users
from django.conf import settings
# Force Django reload
settings._target = None
from util import I18NHandler, FacebookBaseHandler
from google.appengine.ext.db import djangoforms
from django.utils import translation
from django.utils import simplejson as json
from django.contrib.formtools.preview import FormPreview
from random import choice
from urllib import quote
from google.appengine.api.users import is_current_user_admin, UserNotFoundError
from google.appengine.api import urlfetch
import random
import datetime
from datetime import timedelta
from django.utils.translation import gettext_lazy as _
from django.template import defaultfilters

我怎么知道一个导入不再使用了,因为函数被移动或删除了?为什么我不能在一个地方为多个文件指定相同的导入,而必须在每个文件里都写一遍?我可以想象把导入处理放到一个单独的文件,比如imports.yaml,这样就能为那个目录下的所有Python文件指定导入。

6 个回答

8

在上面的回答基础上,我们还喜欢在遵循PEP8的同时,把内容按字母顺序整理,注意的是,import要放在from之前,像这样:

# 1. standard libraries alphabetical with 'imports' before 'from' like this:
import csv
import logging
from collections import defaultdict
from datetime import date
#(blank line)

# 2. third party packages alphabetical with imports first
# next is the third party packages (also alphabetical as described above)
import numpy as  np 
import pandas as pd
from statsmodels import api as sm
#(blank line again)

# 3. your own stuff (also alphabetical) 
from my_other_folder import my_other_file

23

PEP 8 - Python代码风格指南建议你按照以下顺序来整理你的导入:

1. Standard library imports
2. - blank line -
3. google sdk imports
4. - blank line -
5. django imports
6. - blank line -
7. your own code imports

只导入你在代码中使用的东西。把那些没用的导入去掉。你可以使用这些工具来检测未使用的导入:Eclipse上的Pydev / pyflakes / pylint

你的导入数量挺多的。那你的实际代码有多大呢?把它拆分成几个模块可能是个好主意。

为什么不能在一个文件里只导入一次呢?其实你可以这样做:

WARNING: THIS EXAMPLE ILLUSTRATES BAD CODING PRACTICES

import_all.py:

    import a
    import b
    import c

other.py:

     from import_all import *

但请不要这样做。 这违反了Python开发的所有好习惯,也违背了Python之禅中的原则:

明确比隐含要好。

...

命名空间是个非常棒的主意——我们应该多用它!

我还建议你阅读一下Python关于模块的文档,以及一些关于Python命名空间的内容。

11

当你用pylint工具找出了重复和未使用的导入,并按照PEP8的规范整理好后,你可以通过改变导入包的方式来进一步清理代码。

比如,原本你可能是这样导入的:

from google.appengine.api import urlfetch, taskqueue, users, images

但你可以改成这样:

from google.appengine import api

这样的话,你就需要在使用这些包的地方,比如“api.urlfetch”、“api.taskqueue”等,直接写出它们。

这并不是“正确”的做法,只是另一种选择。你可以根据自己的喜好来决定使用哪种方式。

另外,你还可以使用别名来导入:

from google.appengine import api as gaeapi

这样你就可以写成“gaeapi.urlfetch”。这在你需要从多个包中导入名为“api”的模块时特别有用。

还有,关于你问的“为什么不能在一个地方为多个文件指定相同的导入,而必须在每个文件中都写一遍”,如果你在多个文件中都导入了相同的包,这可能说明这些文件之间关系很紧密,应该合并成一个文件。在Python中,和C++或Java不同,每个类不一定要放在单独的文件里,Python的做法是尽量让每个模块(文件)尽可能自给自足,这通常意味着它们会包含多个类和函数。

撰写回答