有没有工具可以检查我从“疯狂”导入的模块中使用了哪些名称?

2024-04-29 22:01:26 发布

您现在位置:Python中文网/ 问答频道 /正文

为了我的研究,我一直在使用python进行计算。为了清理我糟糕的代码,我一直在阅读davidgoodger的Code Like a Pythonista: Idiomatic Python。在

在本文中,Goodger建议不要使用“通配符”导入表单

from module import *

我的代码使用了很多这样的代码。我想清理我的代码,但我不知道如何清理。我很好奇是否有一种方法可以检查我在代码中使用了module中的名称。这样我就可以显式地导入这些名称,或者用module.name替换这些名称。有没有专门设计的工具来完成这样的任务?在


Tags: 方法代码fromimport名称表单code建议
3条回答

概述

一种方法是:

  • 手动(甚至自动)标识使用*方法导入的每个模块
  • 将它们导入单独的文件中
  • 然后,如果它们出现在sys.modules[<module>].__dict__中,则进行搜索和替换,其中{a1}中的对象来自Python模块。在

亲自查看sys.modules的实际操作:

from numpy import *
import sys

sys.modules['numpy'].__dict__.keys()  # will display everything you just imported from `numpy`
>>> ['disp', 'union1d', 'all', 'issubsctype', 'savez', 'atleast_2d', 'restoredot', 'ptp', 'PackageLoader', 'ix_', 'mirr', 'blackman', 'FLOATING_POINT_SUPPORT', 'division', 'busdaycalendar', 'pkgload', 'void', 'ubyte', 'moveaxis', 'ERR_RAISE', 'void0', 'tri', 'diag_indices', 'array_equal', 'fmod', 'True_', 'indices', 'loads', 'round', 'set_numeric_ops', 'pmt', 'nanstd', '_mat', 'cosh', 'object0', 'argpartition', 'FPE_OVERFLOW', 'index_exp', 'append', 'compat', 'nanargmax', 'hstack', 'typename', 'diag', 'rollaxis', 'ERR_WARN', 'polyfit', 'version', 'memmap', 'nan_to_num', 'complex64', 'fmax', 'spacing', 'sinh', '__git_revision__', 'unicode_', 'sinc', 'trunc', 'vstack', 'ERR_PRINT', 'asscalar', 'copysign', 'less_equal', 'BUFSIZE', 'object_', 'divide', 'csingle', 'dtype', 'unsignedinteger', 'fastCopyAndTranspose', 'bitwise_and', 'uintc', 'select', 'deg2rad', 'nditer', 'eye', 'kron', 'newbuffer', 'negative', 'busday_offset', 'mintypecode', 'MAXDIMS', 'sort', 'einsum', 'uint0', 'zeros_like', 'int_asbuffer', 'uint8', 'chararray', 'linspace', 'resize', 'uint64', 'ma', 'true_divide', 'Inf', 'finfo', 'triu_indices', 'complex256', 'add_newdoc', 'seterrcall', 'logical_or', 'minimum', 'WRAP', 'tan', 'absolute', 'MAY_SHARE_EXACT', 'numarray', 'array_repr', 'get_array_wrap', 'polymul', 'tile', 'array_str', 'setdiff1d', 'sin', 'longlong', 'product', 'int16', 'str_', 'mat', 'fv', 'max', 'asanyarray', 'uint', 'npv', 'logaddexp', 'flatnonzero', 'amin', 'correlate', 'fromstring', 'left_shift', 'searchsorted', 'int64', 'may_share_memory', 'dsplit', 'intersect1d', 'can_cast', 'ppmt', 'show_config', 'cumsum', 'roots', 'outer', 'CLIP', 'fix', 'busday_count', 'timedelta64', 'degrees', 'choose', 'FPE_INVALID', 'recfromcsv', 'fill_diagonal', 'empty_like', 'logaddexp2', 'greater', 'histogram2d', 'polyint', 'arctan2', 'datetime64', 'complexfloating', 'ndindex', 'ctypeslib', 'PZERO', 'isfortran', 'asfarray', 'nanmedian', 'radians', 'fliplr', 'alen', 'recarray', 'modf', 'mean', 'square', 'ogrid', 'MAY_SHARE_BOUNDS', 'nanargmin', 'r_', 'diag_indices_from', 'hanning', 's_', 'allclose', 'extract', 'float16', 'ulonglong', 'matrix', 'asarray', 'poly1d', 'promote_types', 'rec', 'datetime_as_string', 'uint32', 'math', 'log2', '__builtins__', 'cumproduct', 'diagonal', 'atleast_1d', 'meshgrid', 'column_stack', 'put', 'byte', 'remainder', 'row_stack', 'expm1', 'nper', 'ndfromtxt', 'matmul', 'place', 'DataSource', 'newaxis', 'arccos', 'signedinteger', 'ndim', 'rint', 'number', 'rank', 'little_endian', 'ldexp', 'lookfor', 'array', 'vsplit', 'common_type', 'size', 'logical_xor', 'geterrcall', 'sometrue', 'exp2', 'bool8', 'msort', 'alltrue', 'zeros', 'False_', '__NUMPY_SETUP__', 'nansum', 'bool_', 'inexact', 'nanpercentile', 'broadcast', 'copyto', 'short', 'arctanh', 'typecodes', 'rot90', 'savetxt', 'sign', 'int_', 'std', 'not_equal', 'fromfunction', 'tril_indices_from', '__config__', 'double', 'require', 'rate', 'typeNA', 'str', 'getbuffer', 'abs', 'clip', 'savez_compressed', 'frompyfunc', 'triu_indices_from', 'conjugate', 'alterdot', 'asfortranarray', 'binary_repr', 'angle', 'lib', 'min', 'unwrap', 'apply_over_axes', 'ERR_LOG', 'right_shift', 'take', 'broadcast_to', 'byte_bounds', 'trace', 'warnings', 'any', 'shares_memory', 'compress', 'histogramdd', 'issubclass_', 'multiply', 'mask_indices', 'amax', 'logical_not', 'average', 'partition', 'nbytes', 'exp', 'sum', 'dot', 'int0', 'nanprod', 'longfloat', 'random', 'setxor1d', 'copy', 'FPE_UNDERFLOW', 'frexp', 'errstate', 'nanmin', 'swapaxes', 'SHIFT_OVERFLOW', 'infty', 'fft', 'ModuleDeprecationWarning', 'digitize', '__file__', 'NZERO', 'ceil', 'ones', 'add_newdoc_ufunc', '_NoValue', 'deprecate', 'median', 'geterr', 'convolve', 'isreal', 'where', 'isfinite', 'SHIFT_UNDERFLOW', 'MachAr', 'argmax', 'testing', 'deprecate_with_doc', 'full', 'polyder', 'rad2deg', 'isnan', '__all__', 'irr', 'sctypeDict', 'NINF', 'min_scalar_type', 'count_nonzero', 'sort_complex', 'nested_iters', 'concatenate', 'vdot', 'bincount', 'transpose', 'array2string', 'corrcoef', 'fromregex', 'vectorize', 'set_printoptions', 'isrealobj', 'trim_zeros', 'unravel_index', 'cos', 'float64', 'log1p', 'ushort', 'equal', 'cumprod', 'float_', 'vander', 'geterrobj', 'load', 'fromiter', 'poly', 'bitwise_or', 'polynomial', 'diff', 'iterable', 'array_split', 'get_include', 'pv', 'tensordot', 'piecewise', 'invert', 'UFUNC_PYVALS_NAME', 'SHIFT_INVALID', 'c_', 'flexible', 'pi', '__doc__', 'empty', 'VisibleDeprecationWarning', 'find_common_type', 'isposinf', 'arcsin', 'sctypeNA', 'imag', 'sctype2char', 'singlecomplex', 'SHIFT_DIVIDEBYZERO', 'matrixlib', 'apply_along_axis', 'reciprocal', 'tanh', 'dstack', 'cov', 'cast', 'logspace', 'packbits', 'issctype', 'mgrid', 'longdouble', 'signbit', 'conj', 'asmatrix', 'inf', 'flatiter', 'bitwise_xor', 'fabs', 'generic', 'reshape', 'NaN', 'cross', 'sqrt', '__package__', 'longcomplex', 'complex', 'pad', 'split', 'floor_divide', '__version__', 'format_parser', 'nextafter', 'polyval', 'flipud', 'i0', 'iscomplexobj', 'sys', 'mafromtxt', 'bartlett', 'polydiv', 'stack', 'identity', 'safe_eval', 'greater_equal', 'Tester', 'trapz', 'PINF', 'object', 'recfromtxt', 'oldnumeric', 'add_newdocs', 'RankWarning', 'ascontiguousarray', 'less', 'putmask', 'UFUNC_BUFSIZE_DEFAULT', 'unicode', 'half', 'NAN', 'absolute_import', 'typeDict', '__path__', 'shape', 'setbufsize', 'cfloat', 'RAISE', 'isscalar', 'character', 'bench', 'source', 'add', 'uint16', 'cbrt', 'bool', 'ufunc', 'save', 'ravel', 'float32', 'real', 'int32', 'tril_indices', 'around', 'lexsort', 'complex_', 'ComplexWarning', 'unicode0', 'ipmt', '_import_tools', 'atleast_3d', 'isneginf', 'integer', 'unique', 'mod', 'insert', 'bitwise_not', 'getbufsize', 'array_equiv', 'arange', 'asarray_chkfinite', 'in1d', 'interp', 'hypot', 'logical_and', 'get_printoptions', 'diagflat', 'float128', 'nonzero', 'kaiser', 'ERR_IGNORE', 'polysub', 'fromfile', 'prod', 'nanmax', 'core', 'who', 'seterrobj', 'power', 'bytes_', 'percentile', 'FPE_DIVIDEBYZERO', '__name__', 'subtract', 'print_function', 'nanmean', 'frombuffer', 'iscomplex', 'add_docstring', 'argsort', 'fmin', 'ones_like', 'is_busday', 'arcsinh', 'intc', 'float', 'ndenumerate', 'intp', 'unpackbits', 'Infinity', 'log', 'cdouble', 'complex128', 'long', 'round_', 'broadcast_arrays', 'inner', 'var', 'sctypes', 'log10', 'uintp', 'linalg', 'histogram', 'issubdtype', 'maximum_sctype', 'squeeze', 'int8', 'info', 'seterr', 'argmin', 'genfromtxt', 'maximum', 'record', 'obj2sctype', 'clongdouble', 'euler_gamma', 'arccosh', 'delete', 'tril', 'int', 'ediff1d', 'char', 'single', 'loadtxt', 'hsplit', 'ScalarType', 'triu', 'floating', 'expand_dims', 'floor', 'polyadd', 'nan', 'TooHardError', 'emath', 'arctan', 'bmat', 'isclose', 'ERR_DEFAULT', 'test', 'roll', 'string0', 'compare_chararrays', 'iinfo', 'real_if_close', 'repeat', 'nanvar', 'hamming', 'ALLOW_THREADS', 'ravel_multi_index', 'string_', 'isinf', 'ndarray', 'e', 'ERR_CALL', 'datetime_data', 'clongfloat', 'full_like', 'result_type', 'gradient', 'base_repr', 'argwhere', 'set_string_function']

您可以使用if <function_name> in sys.modules[<module>].__dict__手动检查是否出现您不确定的函数名,也可以编写一个整洁的自动脚本,遍历sys.modules[<module>]中的每个条目。在

我倾向于后者来处理任何过于复杂的问题,而前者用于诊断目的。在

自动工具的粗略实现

一个非常、非常、非常快速和肮脏的示例,说明如何编写这样一个自动化脚本:

^{pr2}$

这不是很健壮,你不应该按原样使用它!您可能会发现自己正在重写模块中定义的名称。在

最好允许某种形式的用户交互来确认您希望为找到的每个函数名应用更改。但它能让人理解要点。在

使用以下简单的示例文件对此进行了测试:

from numpy import *
array([1])

变成

^{4}$

编辑:此后,我创建了一个更加健壮和有用的命令行实用程序here

这里有一个更简单的解决方案。它使用ast模块将代码从文件中剥离出来,然后将其与inspect模块找到的可用函数列表进行比较。只需在运行之前替换yourfilename和yourmodulename。在

import ast, inspect, yourmodulename as mymodule
filename='yourfilename.py'
tab = ' '*4

funcs = {m[0] for m in inspect.getmembers(mymodule) 
        if str(m[1])[1:].split(' ')[0] in ('function', 'class') and 
        inspect.getmodule(m[1]) == mymodule}
with open(filename) as f:
    code = ast.parse(f.read())
    words = {node.id for node in ast.walk(code) if isinstance(node, ast.Name)}
    print('from', mymodule.__name__, 'import (')
    out = tab
    for word in (', '.join((sorted(words & funcs)))+')').split():
        if len(out + word) > 80:
            print(out.rstrip())
            out = tab + word + ' '
        else:
            out += word + ' '
    if out:
        print(out.rstrip())

我的脚本和我的脚本检查了几十行。在

Edit:添加了检查,以确保它只列出实际属于所需模块一部分的函数,而不是它的子模块。另外,修改后使其同时列出要导入的类和函数。在

使用pyflakes(无论如何都应该使用它)这样的工具来注意在将from module import *替换为import module之后,代码中的哪些名称将变得未定义。一旦确定了从module导入的名称的每个实例,就可以评估是否要

  1. 对于从module导入的import module和{}始终使用x。在
  2. 如果模块名很长,请使用import module as m和{}。在
  3. 使用module有选择地将一些名称从module导入到模块命名空间中

以上三个并不互斥;作为一个极端的例子,您可以在同一个模块中使用这三个:

import really.long.module.name
import really.long.module.name as rlmn
from really.long.module.name import obvious_name

really.long.module.name.foo()  # full module name
rlmn.bar()                     # module alias
obvious_name()                 # imported name

都在同一个代码里。(我不建议在同一个模块中同时使用这三个模块。在单个模块中使用完整的模块名别名,但直接导入常见的、明显的名称并使用完全限定名来处理更模糊的模块属性是没有坏处的。)

相关问题 更多 >