是否有 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 定义了a1a2

模块B 定义了b1b2

模块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 方法可以访问类的所有非私有和非内置属性?的主要内容,如果未能解决你的问题,请参考以下文章

您可以在 Java 中访问私有变量,而无需来自非内部类的类的 getter [重复]

子类将继承父类所有的方法和属性吗?为啥?

Python 获取类属性

Python中的私有属性和私有方法

python-类的封装(私有属性,私有方法)

python-类的封装(私有属性,私有方法)