python - 名称间距 : How to set class variable of inner class based on class variable of outer class?

标签 python namespaces

我正在尝试在 python 中“模拟”命名空间。我使用内部和外部类层次结构来创建我的命名空间。例如,您希望将文件(如资源)的路径保存在一个位置。我试过这样的事情:

src = #path to source folder

class Resources:
    root = src + "Resources\\"

    class Fonts:
        root = Resources.root + "fonts\\"
        font1 = root + "font1.ttf"
        font2 = root + "font2.ttf"     

    class Images:
        root = Resources.root + "images\\"
        logo = root + "logo"
        image1= root + "image1"

    class StyleSheets:
        root = Resources.root + "stylesheets\\"
        default = root + "default.qss"

class JsonData:
    root = src + "Data\\"

    class TableEntries:
        root = JsonData.root
        entries1 = root + "Entries1.json"
        entries2 = root + "Entries2.json"

访问元素如下所示:
logoPath = Resources.Images.image1

不幸的是,由于以下错误,这不起作用:
root = Resources.root + "fonts\\"
NameError: name 'Resources' is not defined

我的问题

是否可以根据外部类的类变量设置内部类的类变量?如果没有,是否有另一种方法可以在不使用多个文件的情况下访问如上所示的元素?

最佳答案

Is it possible to set class variables of inner class based on class variables of outer class?



并非没有使用自定义元类来处理内部类,这肯定无助于可读性和可维护性(并且将 - 正确地 - 被任何有经验的 Python 程序员视为一个完整的 WTF)。

编辑:实际上对于您的示例片段,元类解决方案并不那么复杂,请参见此答案的结尾

原因是在 Python 中几乎所有事情都发生在运行时。 class是一个可执行语句,并且类对象仅在整个类语句的主体结束后创建并绑定(bind)到它的名称。

If not, is there another way to access the elements as shown above without using multiple files?



很简单(简单的例子):
import os

# use a single leading underscore to mark those classes
# as "private" (=> not part of the module's API)
class _Fonts(object):
    def __init__(self, resource):
        self.font1 = os.path.join(resource.root, "font1.ttf")
        self.font2 = os.path.join(resource.root, "font2.ttf")

class _Resources(object):
    def __init__(self, src):
        self.root = os.path.join(rsc, "Ressources")
        self.Fonts = _Fonts(self)

# then instanciate it like any other class
src = "/path/to/source/folder"
Resources = _Resources(src)

print(Resources.Fonts.font1)

编辑:经过更多思考,针对您的用例的基于元类的解决方案不会那么复杂(但这不会是任何通用的东西):
import os

class ResourcesMeta(type):
    def __init__(cls, name, bases, attrs):
        for name in attrs:
            obj = getattr(cls, name)
            if isinstance(obj, type) and issubclass(obj, SubResource):
                instance = obj(cls)
                setattr(cls, name, instance)


class SubResourceMeta(type):
    def __new__(meta, name, bases, attrs):
        if not bases:
            # handle the case of the SubResource base class
            return type.__new__(meta, name, bases, attrs)

        root = attrs.pop("root")
        cls = type.__new__(meta, name, bases, {})
        cls._root = root
        cls._attrs = attrs
        return cls

class SubResource(metaclass=SubResourceMeta):
    def __init__(self, parent):
        self.root = os.path.join(parent.root, self._root)
        for name, value in self._attrs.items():
            setattr(self, name, os.path.join(self.root, value))


class Resources(metaclass=ResourcesMeta):
    root = "/path/to/somewhere"

    class Fonts(SubResource):
        root = "fonts"
        font1 = "font1.ttf"
        font2 = "font2.ttf"

    class Images(SubResource):
        root = "images"
        logo = "logo"
        image1= "image1"

关于python - 名称间距 : How to set class variable of inner class based on class variable of outer class?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49320766/

相关文章:

python - 如何通过 pip 包名称使用 setuptools 指定两个替代要求?

python - Pyenv 在 'pyenv global 3.7.2' 时不会更改 python 版本

.net - 为什么 VS 2005 不断给出 "' x' is ambigacy in the namespace 'y' 错误?

Python编码/解码问题

python - 如何捕获 PyCharm 调试器的 "Stop Button"?

python - __init__ 总是需要的吗?

c++ - 在不使用类名和范围解析运算符的情况下调用方法

flash - 在 Flash Builder 中将 Namespace 降低到 2.6

asp.net-mvc-3 - "Kernel' 命名空间中不存在 'Sitecore'

namespaces - 如何使 RequireJS 正确解析 TYPO3 BE 的命名空间?