有没有一种Python方法可以访问类的所有非私有和非内置属性?

问题描述 投票:0回答:4

我想调用一个方法来给我所有“非私有”(我在这里使用术语“私有”有点松散,因为它在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']

或者我只需要自己检查下划线? 似乎有一种Python式的方法可以做到这一点。

有关下划线和双下划线的更多信息,请参阅: 对象名称前的单下划线和双下划线是什么意思?

python private public built-in
4个回答
19
投票

使用过滤 vars() 的字典理解

{ k:v for k,v in vars(myObject).items() if not k.startswith('_') }

移入一个返回非“软私有”或可调用属性列表的函数。如果您愿意,您可以通过更改为上面的字典理解来返回值

def list_public_attributes(input_var):
    return [k for k, v in vars(input_var).items() if
            not (k.startswith('_') or callable(v))]

4
投票

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

虽然在某些模块*的

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

因此,如果您只需要列出对象的“公共”方法/属性,只需迭代

dir
的结果并删除以下划线开头的名称即可。


*“在某个模块的

import *
期间”

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

模块

A
已定义
a1
a2

模块

B
已定义
b1
b2

模块中的代码

C
按预期工作:

from A import a1, a2
from B import *

想象我们在模块

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


1
投票

我正在使用这个功能:

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)))

我知道这并不完全是你想要的,但也许它会给你一些想法。


0
投票

一个简单的

list comprehension
应该可以做到这一点,尽管这将返回一个list而不是dict(类似于
vars()
):

def public_attr(classvar):
    return [a for a in dir(classvar) if not a.startswith("_")]

现在,如果我们有一门与您提议的课程类似的课程:

class MyClass(object):
    def __init__(self):
        print("init")

    def _private(self):
        print("private")

    def __gets_name_mangled(self):
        print("gets name mangled")

    def public(self):
        print("public")

这将导致:

>>> public_attr(MyClass())
init
['public']
>>> public_attr(MyClass)
['public']

谨防在 class 而不是 class 实例 上调用它(上面的第二个测试)。特别是对于当前版本的 Python,某些属性可能仅在运行时创建,例如

dataclasses.field(default_factory)
(自
Python 3.7
起)..

© www.soinside.com 2019 - 2024. All rights reserved.