【问题描述】:

我想调用一个方法来给我一个包含所有“非私有”(我在这里使用术语“私有”的术语,因为它在 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] != '_']< /代码>
  • 双下划线不代表私有。它的意思是“使用名称修饰”,这只是该类保留与任何子类中的相同属性不同的属性的一种机制

标签: python private public built-in


【解答1】:

实际上,存在这样的函数是不合 Python 的——因为“官方”在 Python 中没有私有或受保护的字段/属性。

虽然在 import * from some module* 期间丢弃带有前导下划线的模块属性(通常是一些实现细节)是有意义的,但它在任何其他对象的上下文中都没有用。< /p>

因此,如果您只需要列出对象的“公共”方法/属性,只需遍历 dir 的结果并删除带有前导下划线的名称。


* "在 import * from some module'期间"

通常这不是最佳做法。考虑下一个例子:

模块 A 定义了 a1a2

模块 B 定义了 b1b2

模块 C 中的这段代码按预期工作:

from A import a1, a2
from B import *

假设我们在模块 B 中添加函数 a1。现在突然模块 C 坏了,虽然我们还没有碰过它。

【问题讨论】:

  • 出于好奇:import * 是否只是像@Blender 建议的那样检查前导下划线?
  • @andy - 导入 * 被认为是不好的做法,因为您永远无法确定您究竟导入了什么,这反过来又会造成名称冲突和可能意外使用使用 * 导入的方法。最好单独显式导入每个方法,或者简单地从公共命名空间中引用它们。
  • 我认为这是在不使用 exec 的情况下添加隐式绑定的唯一方法。
  • 我明白了。你说 calling import * 是不好的做法(这是有道理的)。我以为您是在说 import *implementation (忽略带有前导下划线的属性)是不好的做法(因为它遵循公共/私有范式)。感谢您的澄清。
  • @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,需要此处显示的过滤器。