最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - In python, "export" a custom-tailored object from a module - Stack Overflow

programmeradmin1浏览0评论

In JavaScript, specifically in node.js setting, one can spell module.exports = 13; in module.js, then x = import ("module.js"); elsewhere and have 13 assigned to x directly.

This saves some code when a module exports a single function, and I notice a lot of widely used packages (such as through2) make use of it.

Is there a way to do the same in Python? With some black magic, maybe?

I do have heard of a thing called loader that's, I guess, supposed to do some manipulations with a module before making it available. In particular, I think SaltStack makes use of something like that in salt.loader, but the code is too hard for me to follow. I imagine we could write a function similar to this:

def loader(module):
    m = __import__(module)
    return m["__exports__"]

— Then define __exports__ somewhere in a module we want to import and enjoy functionality very similar to JavaScript's module.exports mechanics. But unfortunately TypeError: 'module' object has no attribute '__getitem__' prevents us from doing that.

In JavaScript, specifically in node.js setting, one can spell module.exports = 13; in module.js, then x = import ("module.js"); elsewhere and have 13 assigned to x directly.

This saves some code when a module exports a single function, and I notice a lot of widely used packages (such as through2) make use of it.

Is there a way to do the same in Python? With some black magic, maybe?

I do have heard of a thing called loader that's, I guess, supposed to do some manipulations with a module before making it available. In particular, I think SaltStack makes use of something like that in salt.loader, but the code is too hard for me to follow. I imagine we could write a function similar to this:

def loader(module):
    m = __import__(module)
    return m["__exports__"]

— Then define __exports__ somewhere in a module we want to import and enjoy functionality very similar to JavaScript's module.exports mechanics. But unfortunately TypeError: 'module' object has no attribute '__getitem__' prevents us from doing that.

Share Improve this question edited May 14, 2017 at 14:00 gz. 6,7011 gold badge24 silver badges34 bronze badges asked May 14, 2017 at 13:15 Ignat InsarovIgnat Insarov 4,84221 silver badges38 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 2

Python has importing built in to the language at a more basic level than Javascript does, almost all use cases are covered by a simple import statement.

For your example, all it really boils down to is:

from module import exports as x

So, there's not need to look for code savings by changing module.

The other part of the question is how, as a module author, would you restrict people to seeing only a single symbol.

Generally this is not required except to help users know what are public functions vs implementation details. Python has a few mon idioms for this:

  • Any names that start with a leading underscore, such as _helper, are considered private. They can be accessed as normal, but the implication is you should not.
  • If a module level variable __all__ = [...] exists, only the strings it contains are considered public. The names must seperatedly be declared in the module.

As well as being documentation, both of these do affect one aspect of the module import:

from module import *

Using a star import is generally discouraged, but only public names will be brought in to the local namespace.

After some thinking I understood that, while we can't say m["__exports__"] due to module object's class not having __getitem__ method, we can still access some of the module's elements with "dot" notation: m.__exports__ works.

Another way: screen all module level names off with an underscore and assign the object to be exported to a variable named after the module, then from module import *.

loader.py:

def loader(module):
    m = __import__(module)
    return m.__exports__

exports.py:

def _f():
    return 13

_a = 31

exports = {"p6": _f, "p8": _a}

__exports__ = exports

Python 2.7:

>>> import loader
>>> e = loader.load ("exports")
>>> e
{'p8': 31, 'p6': <function _f at 0x7fb79d494cf8>}
>>> from exports import *
>>> exports
{'p8': 31, 'p6': <function _f at 0x7fb79d494cf8>}

Python 3:

>>> import loader
>>> e = loader.load ("exports")
>>> e
{'p6': <function _f at 0x7f88ae229ae8>, 'p8': 31}
>>> from exports import *
>>> exports
{'p6': <function _f at 0x7f88ae229ae8>, 'p8': 31}

In the first way proposed, I unfortunately cannot use __all__ in loader.load to filter only listed names from a module being loaded since __getitem__ is not defined for module object.

In the second way proposed I don't get so much control (in that a malicious module can export arbitrary names and manipulate my namespace) and flexibility (in that I cannot assign the module's exported object to arbitrary name anywhere in my code).

So, there is still a bit left to be desired here.

发布评论

评论列表(0)

  1. 暂无评论