【问题标题】:Python 3.5 type hinting dynamically generated instance attributesPython 3.5 类型提示动态生成的实例属性
【发布时间】:2016-03-17 18:49:20
【问题描述】:

我想为动态生成的对象属性添加 Python 3.5 类型提示,以便 IDE 正确地自动完成它们。这里的“动态”是指该属性在类创建期间或__init__ 或任何其他方法中不存在。

例如有没有办法通过 cmets 或其他技巧添加这些?如果没有,我可以回退以添加虚拟类属性。

示例::

 class Request:
      """Example HTTP request object.

      We have `get_user()`  but we do not declare it anyhere.
      """

 ...


 # Pyramid's way of plugging in methods and properties to request, enabled addon capabilities for the framework
 # adds Request.user - done in different part of application lifecycle, not during class creation
 config.add_request_method(auth.get_user, 'user', reify=True)

我们的目标是完成这项工作,以便 PyCharm 和其他 IDE 完成此属性。

【问题讨论】:

  • 我怀疑除了在为您添加方法的库中之外的任何地方都需要付出很多努力。如果它添加了带有正确类型注释的方法,它应该可以工作。也许您应该在 Pyramid 上提交功能请求错误?

标签: python pycharm python-3.5


【解决方案1】:

在 Python 3.6+ 中,您可以使用类级别的类型提示 - 这些不会在类中生成属性。即

class Request(_Request):
    user: Optional[User]

这不会在类中创建属性,只会创建注释。

>>> Request.user
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'Request' has no attribute 'user'

>>> Request.__annotations__
{'user': typing.Union[foo.User, NoneType]}

在 Python 3.5 中,可以创建一个返回非数据描述符的函数(即描述符没有 __set__);这将可以被实例属性覆盖,但它会带来一些最小 运行时开销——描述符将从__dict__ 获取并检查它是否定义了__set__ 插槽——即使对于所有读取也是如此。然后它可能看起来像

class Request(_Request):
    user = typed(User)

typed 定义为

def typed(type: Type[T]) -> T:
    ... return a dummy non-data-descriptor...

这应该足以让 PyC​​harm 正确推断类型。

【讨论】:

    【解决方案2】:
    • 我继承了真正的类

    • 我在课堂上添加了仿__type_hinting__ 方法

    • 我使用这个类而不是真正的类作为参数类型提示

      class Request(_Request):
          """
          HTTP request class.
          This is a Pyramid Request object augmented with type hinting information for Websauna-specific functionality.
          To know more about request read also
          * py:class:`pyramid.request.Request` documentation
          * py:class:`webob.request.Request` documentation
      
          Counterintuitively, this request is also available in non-HTTP applications like command line applications and timed tasks. 
          These applications do not get request URL from a front end HTTP webserver, but a faux request is constructed pointing to the website URL taken from ``websauna.site_url`` setting. 
          This is to allow similar design patterns and methodology to be applied in HTTP and non-HTTP applications.
      
          By setting variables in ``__type_hinting__()`` based on arguments types allows IDEs to infer type information when you hint your views as::
      
               from websauna.system.http import Request
      
               def hello_world(request: Request):
                   request.  # <-- When typing, here autocompletion kicks in.
      
          """
      
          def __type_hinting__(self, user: Optional[User], dbsession: Session, session: ISession, admin: Admin, registry: Registry):
              """
              A dummy helper function to tell IDEs about reify'ed variables.
              :param user: The logged in user. None if the visitor is anonymous.
              :param dbsession: Current active SQLAlchemy session
              :param session: Session data for anonymous and logged in users.
              :param admin: The default admin interface of the site. Note that the site can have several admin interfaces for different purposes.
              :param registry: Pyramid registry's. E.g. 
                  :py:attr:`pyramid.registry.Registry.settings` for reading settings and :py:meth:`pyramid.registry.Registry.notify` for sending events.
              """
              self.user = user
              self.dbsession = dbsession
              self.session = session
              self.admin = admin
              self.registry = registry 
      

    【讨论】:

    • 嗨 Mikko,我找不到任何有关 __type_hinting__ 的文档。我在哪里可以了解更多信息?我猜任何方法都应该有效,只要它为 IDE 提供成员类型的“一些提示”。
    • 你能找到的唯一地方就是上面。
    • 然而这是旧的并且无关紧要,因为现代 Python 解释器具有变量注释 python.org/dev/peps/pep-0526
    • 感谢您的解释。
    猜你喜欢
    • 2020-11-30
    • 2020-01-25
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 2018-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多