是否有 Python 方法可以访问类的所有非私有和非内置属性?
Posted
技术标签:
【中文标题】是否有 Python 方法可以访问类的所有非私有和非内置属性?【英文标题】:Is there a Python method to access all non-private and non-builtin attributes of a class? 【发布时间】:2013-06-09 03:07:50 【问题描述】:我想调用一个方法来给我一个包含所有“非私有”(我在这里使用术语“私有”的术语,因为它在 Python 中并不真正存在)和非内置属性(即那些不以单下划线或双下划线开头的)。类似 vars(MyClass) 的东西只会返回该类的“公共”属性。
我知道
from M import *
不导入名称以下划线开头的对象。 (http://www.python.org/dev/peps/pep-0008/#id25) import 是如何实现的?通过内置函数还是仅通过检查下划线?这样做的pythonic方法是什么?
例子:
class MyClass(object):
def __init__(self):
do_stuff()
def _private(self):
print 'private'
def __gets_name_mangled(self:
print 'becomes _MyClass__gets_name_mangled()'
def public(self):
print 'public'
如果我这样做了
vars(MyClass).keys()
我明白了
['_MyClass__gets_name_mangled', '__module__', '_private', '__doc__', '__dict__', '__weakref__', 'public', '__init__']
我怎样才能只得到
['public']
还是我只需要自己检查下划线?似乎有一种pythonic方式可以做到这一点。
有关下划线和双下划线的更多信息,请参阅: What is the meaning of a single- and a double-underscore before an object name?
【问题讨论】:
vars(MyClass).keys()
是dir(MyClass)
我不知道有什么功能可以做到这一点。总有:[f for f in dir(MyClass) if not f.startswith('_')]
@Elazar 如果我的理解是正确的, dir(MyClass) 将返回 MyClass 子类化的类的属性(如果 MyClass 碰巧发生子类化)除了在 MyClass 中定义的那些属性,而 vars(MyClass ) 只返回在 MyClass 中定义的那些属性。细微的差别。但原始问题仍然存在。
其实Pythonic的方式是定义一个函数:def public_vars(klass): return [f for f in vars(MyClass) if f[0] != '_']
双下划线不代表私有。它的意思是“使用名称修饰”,这只是该类保留与任何子类中的相同属性不同的属性的一种机制
【参考方案1】:
实际上,存在这样的函数是不合 Python 的——因为“官方”在 Python 中没有私有或受保护的字段/属性。
虽然在import *
期间从某个模块* 中丢弃带有前导下划线的模块属性(通常是一些实现细节)是有意义的,但它在任何其他对象的上下文中都没有用。
因此,如果您只需要列出对象的“公共”方法/属性,只需遍历 dir
的结果并删除带有前导下划线的名称。
* "在 import *
期间来自某个模块'"
通常这不是最佳做法。考虑下一个例子:
模块A
定义了a1
和a2
模块B
定义了b1
和b2
模块C
中的代码按预期工作:
from A import a1, a2
from B import *
假设我们在模块B
中添加函数a1
。现在突然模块C
坏了,虽然我们还没有碰过它。
【讨论】:
出于好奇:import * 是否只是像@Blender 建议的那样检查前导下划线? @andy - 导入 * 被认为是不好的做法,因为您永远无法确定您究竟导入了什么,这反过来又会造成名称冲突和可能意外使用使用 * 导入的方法。最好单独显式导入每个方法,或者简单地从公共命名空间中引用它们。 我认为这是在不使用exec
的情况下添加隐式绑定的唯一方法。
我明白了。你是说 调用 import *
是不好的做法(这是有道理的)。我以为您是在说import *
的实现(忽略带有前导下划线的属性)是不好的做法(因为它遵循公共/私有范式)。感谢您的澄清。
@andy 知道了。编辑答案以消除歧义。【参考方案2】:
我正在使用这个功能:
def print_all_public_fields(obj):
print(obj)
for a in dir(obj):
if not a.startswith('_') and not a.isupper():
print('\t%s = %s' % (a, getattr(obj, a)))
我知道这不是你想要的,但也许它会给你一些想法。
【讨论】:
【参考方案3】:使用过滤 vars() 的 dict 理解
k:v for k,v in vars(myObject).items() if not k.startswith('_')
移入一个函数,该函数返回一个非“软私有”或可调用属性列表。如果您愿意,可以通过更改为上述 dict 理解来返回值
def list_public_attributes(input_var):
return [k for k, v in vars(input_var).items() if
not (k.startswith('_') or callable(v))]
【讨论】:
'public'(所需的输出)不是可调用的吗?为什么这是一个过滤条件? 请注意,vars
将过滤“魔术”(又名 d'under)方法,这与 dir
不同。对于“private”/s'under,需要此处显示的过滤器。以上是关于是否有 Python 方法可以访问类的所有非私有和非内置属性?的主要内容,如果未能解决你的问题,请参考以下文章