【问题标题】:Static classes being initialised on import. How does python 2 initialise static classes on import导入时初始化的静态类。 python 2如何在导入时初始化静态类
【发布时间】:2016-08-03 04:13:54
【问题描述】:

我正在尝试为包mime 引入python 3 支持,并且代码正在做一些我以前从未见过的事情。

有一个类Types() 在包中用作静态类。

class Types(with_metaclass(ItemMeta, object)): # I changed this for 2-3 compatibility

    type_variants = defaultdict(list)
    extension_index = defaultdict(list)

    # __metaclass__ = ItemMeta # unnessecary now

    def __init__(self, data_version=None):
        self.data_version = data_version

type_variants defaultdict 是在 python 2 中而不是在 3 中填充的内容。

当它位于另一个名为 mime_types.py 的文件中时,似乎被这个类填满了。

class MIMETypes(object):
    _types = Types(VERSION)

    def __repr__(self):
        return '<MIMETypes version:%s>' % VERSION

    @classmethod
    def load_from_file(cls, type_file):
        data = open(type_file).read()
        data = data.split('\n')
        mime_types = Types()
        for index, line in enumerate(data):
            item = line.strip()
            if not item:
                continue
            try:
                ret = TEXT_FORMAT_RE.match(item).groups()
            except Exception as e:
                __parsing_error(type_file, index, line, e)

            (unregistered, obsolete, platform, mediatype, subtype, extensions,
             encoding, urls, docs, comment) = ret
            if mediatype is None:
                if comment is None:
                    __parsing_error(type_file, index, line, RuntimeError)
                continue
            extensions = extensions and extensions.split(',') or []
            urls = urls and urls.split(',') or []
            mime_type = Type('%s/%s' % (mediatype, subtype))
            mime_type.extensions = extensions
            ...
            mime_type.url = urls
            mime_types.add(mime_type) # instance of Type() is being filled?
        return mime_types

每当mime_types.py 被导入并执行此操作时,函数startup() 就会运行。

def startup():
    global STARTUP
    if STARTUP:
        type_files = glob(join(DIR, 'types', '*'))
        type_files.sort()
        for type_file in type_files:
            MIMETypes.load_from_file(type_file) # class method is filling Types?
    STARTUP = False

这一切对我来说似乎很奇怪。 MIMETypes 类首先在第一行创建Types() 的实例。 _types = Types(VERSION)。然后它似乎对这个实例什么都不做,只使用在load_from_file() 类方法中创建的mime_types 实例。 mime_types = Types()

这种事情隐约让我想起了 javascript 类的构造。实例mime_types如何填充Types.type_variants,这样导入的时候就这样了。

from mime import Type, Types

可以使用类的type_variants defaultdict。为什么这在 python 3 中不起作用?

编辑:

添加额外代码以显示type_variants 的填充方式

(In "Types" Class)
@classmethod
def add_type_variant(cls, mime_type):
    cls.type_veriants[mime_type.simplified].append(mime_type)

@classmethod
def add(cls, *types):
    for mime_type in types:
        if isinstance(mime_type, Types):
            cls.add(*mime_type.defined_types())
        else:
            mts = cls.type_veriants.get(mime_type.simplified)
            if mts and mime_type in mts:
                Warning('Type %s already registered as a variant of %s.',
                        mime_type, mime_type.simplified)
            cls.add_type_variant(mime_type)
            cls.index_extensions(mime_type)

您可以看到MIMETypes 使用了add() 类方法。

【问题讨论】:

  • 您提供的代码不包含对任何名为 type_variants 的变量的引用,但原始声明除外。那么它怎么可能在这段代码中被修改或“填充”或以任何方式访问呢?无论 Python 版本如何,这个问题都适用。在 Python2 的情况下,它必须在其他地方被填充。您的列表是否遗漏了重要内容?
  • @PaulCornelius:是的,我确实忽略了与type_variants dict 交互的类方法。 MIMETypes 有调用add() 填充字典的方法。
  • “静态类”是什么意思?这在其他语言中可能意味着某些东西(其含义取决于语言),但在 Python 中,该形容词不能应用于该名词。
  • @user2357112 只是在没有实例化的情况下使用该类。该代码执行类似于Types['something'] 而不是types = Types() 然后types['something']

标签: python class import static


【解决方案1】:

不发布更多代码,很难说。我会说,我只需进行一些更改(打印语句 -> 函数,basestring -> str,在相同包导入之前添加一个点,以及一个非常丑陋的 hack以补偿他们对cmp的喜爱:

def cmp(x,y): 
    if isinstance(x, Type): return x.__cmp__(y)
    if isinstance(y, Type): return y.__cmp__(x) * -1
    return 0 if x == y else (1 if x > y else -1)

注意,我什至不确定这是否正确。

然后

import mime
print(mime.Types.type_veriants)    # sic

打印出一个 1590 条目defaultdict


关于您关于MIMETypes._types 未被使用的问题,我同意,不是。

关于您关于如何字典被填充的问题,它非常简单,并且您已经识别了大部分内容。

import mime

导入包的__init__.py,其中包含以下行:

from .mime_types import MIMETypes, VERSION

mime_types.py 包括以下几行:

def startup():
    global STARTUP
    if STARTUP:
        type_files = glob(join(DIR, 'types', '*'))
        type_files.sort()
        for type_file in type_files:
            MIMETypes.load_from_file(type_file)
    STARTUP = False

startup()

MIMETypes.load_from_file() 有以下几行:

mime_types = Types()
#...
for ... in ...:
    mime_types.add(mime_type)

Types.add(): 有一行:

cls.add_type_variant(mime_type)

并且该类方法包含:

cls.type_veriants[mime_type.simplified].append(mime_type)

【讨论】:

  • 是的,我做了同样的技巧来移植到 python 3。由于空的 defaultdict,单元测试失败了。我将不得不检查是否只导入它并忽略单元测试。
  • 感谢您的帮助。关于您的编辑,我可以看到字典是如何填充的,但是如何填充实例 also 填充静态类。而且我仍然不明白为什么它不适用于我的 python 3
  • 另外你做了什么移植项目?你是 pip 安装包然后编辑它还是从 Github 下载它并编辑它?
  • 在classmethods中,第一个参数是类。如果您执行type(&lt;an instance&gt;)&lt;class name&gt;,您会得到同样的结果。这与第一个参数是实例的常规/非类方法不同。所以在Types.add() 中,cls.add_type_variant() 与输入Types.add_class_variant() 相同,在该类方法中,cls.type_veriants[...].append()Types.type_veriants[...].append() 相同。
  • @thundergolfer 我从您发布的 PyPy 链接下载了源 tarball。
猜你喜欢
  • 2020-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-10
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
相关资源
最近更新 更多