【问题标题】:How does eclipse's pydev do code completion?eclipse的pydev是怎么做代码补全的?
【发布时间】:2013-08-12 02:46:31
【问题描述】:

有谁知道 pydev 如何确定使用什么来完成代码?我正在尝试定义一组专门用于启用代码完成的类。我尝试使用__new__ 设置__dict____slots__,但似乎都没有在pydev 自动完成中列出。

我有一组要在自动完成中列出的枚举,但我想将它们设置在生成器中,而不是为每个类都硬编码。

所以而不是

class TypeA(object):
    ValOk = 1
    ValSomethingSpecificToThisClassWentWrong = 4
    def __call__(self):
        return 42

我想做类似的事情

def TYPE_GEN(name, val, enums={}):
    def call(self):
        return val
    dct = {}
    dct["__call__"] = call
    dct['__slots__'] = enums.keys()
    for k, v in enums.items():
        dct[k] = v
    return type(name, (), dct)

TypeA = TYPE_GEN("TypeA",42,{"ValOk":1,"ValSomethingSpecificToThisClassWentWrong":4})

我可以做些什么来帮助处理?

编辑: cmets 似乎是在质疑我在做什么。同样,我所追求的很大一部分是代码完成。我正在使用 python 绑定到协议来与各种微控制器通信。我可以更改的每个参数(有数百个)在概念上都有一个名称,但在协议上我需要使用它的 ID,这实际上是随机的。许多参数接受在概念上命名但又由整数表示的值。因此枚举。

我正在尝试为该库自动生成一个 python 模块,因此该组可以使用名称而不是容易出错的数字来指定他们想要更改的内容。 __call__ 属性将返回参数的 id,枚举是参数的允许值。

是的,我可以生成每个类的详细版本。每种类型的一行对我来说似乎更清楚,因为重点是自动完成,而不是查看这些类。

【问题讨论】:

  • 您不需要为此动态生成类。此外,动态生成类可能与自动完成不兼容。
  • 请问您为什么不想对名称进行硬编码?您希望通过从字符串的dict 生成枚举值来获得什么好处?
  • 我不知道 pydev 有多聪明,但您可以尝试通过元类定义您的枚举。
  • 如果将所有内容都放在 dict 文字中并将其传递给构造函数,与使用常规类语句相比,它的硬编码也不会少。你只会失去清晰度。
  • 附带说明,将可变容器作为默认参数 (enums={}) 是个坏主意。从函数内部对其进行的更改将在调用中持续存在。更好的是有一个默认值None 并在函数内部检查它。

标签: python eclipse pydev metaclass


【解决方案1】:

好的,正如所指出的,您的代码太动态了... PyDev 只会静态分析您自己的代码(即:存在于您项目中的代码)。

仍然有一些替代方案:

选项 1:

您可以强制 PyDev 动态分析库中(即:站点包中)的代码,在这种情况下,它可以通过 shell 动态获取该信息。

为此,您必须在站点包中创建一个模块,并在您的解释器配置中将其添加到“强制内置”中。有关详细信息,请参阅:http://pydev.org/manual_101_interpreter.html

选项 2:

另一种选择是将其放入预定义的补全中(但在这种情况下,它还需要在解释器配置中,而不是在您的代码中——而且无论如何您都必须在此处明确补全)。请参阅上面的链接了解如何执行此操作。

选项 3:

生成实际代码。我相信 Cog (http://nedbatchelder.com/code/cog/) 是最好的选择,因为您可以编写 python 代码来输出文件的内容,然后您可以更改代码/重新运行 cog 以更新所需的内容(如果您想要正确完成而无需把你的代码作为一个库放在 PyDev 中,我相信这将是最好的选择——你将能够更好地掌握你所拥有的东西,因为你的结构在那里是明确的)。

请注意,如果您使用其他语言(例如 Java/C++ 等),则 cog 也可以使用。因此,无论这个特定问题如何,我都建议您将其添加到您的工具集中。

【讨论】:

    【解决方案2】:

    在“离线”编辑器中(而不是在交互式 Python shell 中)实际上不可能实现 Python 的完全通用代码完成。

    原因是Python过于动态;基本上任何事情都可以随时改变。如果我输入TypeA.Val 并要求完成,系统必须知道TypeA 绑定到什么对象,它的类是什么,以及两者的属性是什么。所有这 3 个事实都可以改变(并且会改变;TypeA 开始未定义,并且仅在程序执行期间的某个特定点绑定到对象)。

    所以系统必须知道您希望从程序运行的哪个点开始完成?即使有一些明确的方式来指定它,也没有一般的方法可以知道程序中所有内容的状态,而无需实际运行到该点,您可能不希望您的编辑器这样做!

    所以 pydev 所做的就是猜测,这很明显。如果您在模块foo 中有一个类块定义类Bar,那么可以肯定的是,从foo 导入的名称Bar 将引用该类。因此,您知道在Bar. 下或在obj = Bar() 创建的对象上可以访问哪些名称。当然,程序可以在运行时重新绑定foo.Bar(或更改其属性集),或者可以在import foo 访问其他文件的环境中运行。但这种事情很少发生,补全在常见情况下很有用。

    这意味着,只要您“过多”地使用 Python 的动态语言灵活性,您就会基本上失去补全。通过调用函数来定义类就是其中一种情况。还没准备好猜测TypeA 有名称ValOkValSomethingSpecificToThisClassWentWrong;毕竟,调用TYPE_GEN 可能会产生许多其他对象,但它们都有不同的名称。

    因此,如果您的主要目标是完成,我认为您必须简化 pydev 并完整地编写这些类。当然,如果需要,您可以使用类似的代码(以文本方式)生成 python 文件。不过,看起来用字典定义这些实际上比作为一个类有更多的“语法开销”;您正在为每个项目写"a": b,,而不是a = b。除非您可以更系统地生成这些或解析现有的定义文件或其他东西,否则我想我会发现静态类定义比驱动TYPE_GEN 的字典更易于阅读和。

    【讨论】:

      【解决方案3】:

      您的代码越简单,完成的可能性就越大。将其作为一个单独的工具来生成包含上述类定义的 Python 代码文件是否合理?这基本上是两全其美的。您甚至可以将名称/值对放在 JSON 或 INI 文件或您拥有的文件中,从而消除名称/值对中方法调用的混乱。唯一的缺点是需要在代码更改时运行该工具来重新生成代码文件,但至少这是一个自动化、简单的过程。

      就个人而言,我只会让事情变得更冗长并手动编写类,但这只是我的意见。

      另一方面,我认为使类可调用与仅具有 id 类变量相比没有多大好处。两者都需要知道输入什么:TypeA()TypeA.id。如果您想阻止实例化,我认为在__init__ 中抛出异常会更清楚您的意图。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-03
        • 2014-11-21
        • 1970-01-01
        • 2011-03-13
        • 1970-01-01
        • 2011-04-26
        相关资源
        最近更新 更多