我试图"模拟" python中的命名空间。我使用内部和外部类hirarchies来创建我的命名空间。例如,您希望在一个位置保存文件路径(如资源)。我试过这样的事情:
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
我的问题
是否可以根据外部类的类变量设置内部类的类变量?如果没有,是否有另一种方法来访问如上所示的元素而不使用多个文件?
答案 0 :(得分:1)
是否可以根据外部类的类变量设置内部类的类变量?
不是没有重新定位到自定义元类来处理内部类,这肯定不会有助于可读性和可维护性(并且 - 任何有经验的python程序员都可以看作是一个完整的WTF)。
编辑: 实际上,对于您的示例代码段,元类解决方案并不复杂,请参阅此答案的结尾
原因是在Python中几乎所有事情都发生在运行时。 class
是一个可执行语句,只有在整个类语句的主体结束后才创建并绑定到它的名称的类对象。
如果没有,是否有其他方法可以访问如上所示的元素而不使用多个文件?
非常简单(愚蠢的例子):
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"
答案 1 :(得分:0)
我认为你没有在OOP中明确类和实例的概念。如果你想存储这类信息Resources
不应该是一个类,它应该是一个Dir
类的实例。
class Dir:
def __init__(self, path="/", parent=None):
self.parent = parent
self.path = path
self.contents = {}
def __getitem__(self, key):
return self.contents[key]
def create_subdir(name):
self.contents[name] = Dir(os.path.join(self.path + name), self)
def add_file(file):
self.contents[file] = file # You should probably also have a File type
# ...
resources = Dir(os.path.join(src, "Resources"))
resources.create_subdir("fonts")
fonts = resources["fonts"]
fonts.add_file("font1.ttf")
...
我已经使用os.path.join
函数委托Python为每个SO选择正确的分隔符,而不是像你一样硬编码Windows分隔符。 __getitem__
方法允许获取项目,就好像变量是字典一样。
如果您不喜欢路径库的pathlib,您可以利用div operator usage标准模块并添加属性访问表示法(使用'。'来访问子目录)。
from pathlib import Path as Path_, WindowsPath as WPath_, PosixPath as PPath_
import os
class Path(Path_):
def __new__(cls, *args, **kwargs):
return super().__new__(WindowsPath if os.name == 'nt' else PosixPath,
*args, **kwargs)
def __getattr__(self, item):
if item == '_str':
raise AttributeError
for i in self.iterdir():
if i.name == item:
return i
raise AttributeError
class WindowsPath(WPath_, Path):
pass
class PosixPath(PPath_, Path):
pass
current = Path()
subdir = current.subdir_name # current / 'subdir_name'