我在模块中有一个python类,我有一些方法需要在同一个模块中有一些其他类的列表。以下是我现在正在做的事情:
module.py
class Main:
@staticmethod
def meth1():
for c in classes:
#do something
@staticmethod
def meth2():
for c in classes:
#do something
class Class1:
pass
class Class2:
pass
class Class3:
pass
classes = [Class1, Class3]
我想改进的一些事情:
classes
列表放在更普遍的地方。理想情况下,在所有类之外,但在模块文件的顶部,或作为Main
的类属性,但在meth1
或meth2
之外。这样做的目的是为了更容易找到,如果有人需要添加另一个类定义。dir()
或locals()
,但它们也列出了导入的类,方法和模块。另外,我需要一些方法来识别我想要的类。我只能使用类中的属性来做到这一点,但如果有更优雅的方式,那就太好了。我正在尝试做什么?
答案 0 :(得分:4)
就个人而言,我会使用decorator来标记重要的类。您可以将将它们保存在文件顶部的列表放置在可以显示的位置。
这是一个简单的例子:
# Classes are added here if they are important, because...
important_classes = []
def important(cls):
important_classes.append(cls)
return cls
@important
class ClassA(object):
pass
class ClassB(object):
pass
@important
class ClassC(object):
pass
# Now you can use the important_classes list however you like.
print(important_classes)
# => [<class '__main__.ClassA'>, <class '__main__.ClassC'>]
答案 1 :(得分:2)
您可以使用inspect。
首先,获取局部变量列表:
local_vars = locals().values()
然后我们需要检查每一个:
import inspect
local_vars = [i for i in local_vars if inspect.isclass(i)]
要仅获取本地定义的类,请检查cls.__module__ == __name__
是否如下:
def get_classes():
global_vars = list(globals().values())
classes = [i for i in global_vars if inspect.isclass(i)]
return [i for i in classes if i.__module__ == __name__]
总体思路是:inspect允许您检查实时对象,迭代所有局部变量允许您检查当前命名空间中的所有内容。最后一部分,即本地定义的类,可以通过检查模块名称是否与当前名称空间相同,或cls.__module__ == __name__
来完成。
最后,为了兼容Python3,我添加了list(globals().values()
,因为字典大小会在列表理解期间发生变化。对于Python2,由于dict.values()
返回一个列表,因此可以省略。
编辑:
对于进一步过滤,您还可以使用特定的类属性或其他属性,如注释中所述。如果您担心稍后将模块重组为包,那就太棒了。
def get_classes(name='target'):
global_vars = list(globals().values())
classes = [i for i in global_vars if inspect.isclass(i)]
return [i for i in classes if hasattr(i, name)]
答案 2 :(得分:2)
可能有更好的方法来实现这一点,但我会将所有这些子类放在持有者身上,然后使用__subclasses__()
将它们全部拉出来:
class Main:
def meth1(self):
for c in Holder._subclasses__():
#do something
def meth2(self):
for c in Holder._subclasses__():
#do something
class Holder(object):
pass
class Class1(Holder):
pass
class Class2(Holder):
pass
class Class3(Holder):
pass
如果您愿意,甚至可以将它们设为Main
的子类,然后使用类方法将它们拉出来:
class Main(object):
@classmethod
def meth1(cls):
for c in cls._subclasses__():
#do something
class Class1(Main): pass
您需要使用Python 2继承object
才能实现此目的。
答案 3 :(得分:2)
您的列表似乎是针对模块中可用类的子集,因此在某些时候您必须指定要定位的类。
import sys
target_classes = ["Class1", "Class3"]
class Main:
def __init__(self, classes):
self.target_classes = classes
def meth1(self):
for s in self.target_classes:
C = getattr(sys.modules[__name__], s)
C().speak()
def meth2(self):
for c in classes:
print c
#do something
class Class1:
def speak(self):
print "woof"
class Class2:
def speak(self):
print "squeak"
class Class3:
def speak(self):
print "meow"
Main(target_classes).meth1()
--output:--
woof
meow
答案 4 :(得分:1)
我不确定这是否是最佳做法,但这可以满足您的需求:
class Main:
def __init__(self, locals):
self.classes = []
for (c, val) in locals.iteritems():
try:
if c[:5] == 'Class':
self.classes.append(val)
except:
pass
def meth1(self):
for c in self.classes:
pass
def meth2(self):
for c in self.classes:
pass
class Class1:
pass
class Class2:
pass
class Class3:
pass
main = Main(locals())
print main.classes