Differences between revisions 1 and 7 (spanning 6 versions)
Revision 1 as of 2004-11-01 07:39:36
Size: 4798
Editor: 60
Comment:
Revision 7 as of 2004-11-01 08:25:40
Size: 6693
Editor: 60
Comment:
Deletions are marked like this. Additions are marked like this.
Line 15: Line 15:
获得类层次中所有成员属性
Line 16: Line 17:
Credit: Jürgen Hermann, Alex Martelli
Line 20: Line 22:
需要映射一个类的所有属性,包括继承的属性,到一个以类属性名称作为键的字典中。
Line 25: Line 27:
一个可以在Python的各种新(2.2)旧版本中使用的解决方法如下:
{{{
#!python
Line 40: Line 45:
}}}
Line 44: Line 50:

食谱中all_memebers函数创建了一个以类属性名称为键,属性值为对应字典值的字典。字典中包括了类的各种成员:函数成员和数据成员。下面是一个例子:

{{{
#!python
Line 58: Line 69:

}}}
Line 60: Line 74:
输出如下(注意字典的输出顺序是任意的,并且可能随Python解释器的不同而不同):

{{{
#!python
Line 63: Line 81:

}}}
Line 65: Line 85:
在使用d=all_memebers(c)构建字典d之后, 可以多次使用introspectoin来查询类c。判断类c 是否含有属性x使用: d.has_key(x), 效果同 hasattr(c,x)是一样的,获的类c的x属性使用 d.get(x),同getattr(c,x,None)效果也相同。使用字典d.has_key(x),以及d.get(x),
效率上得到提升, 不需要每次动态查询类的继承层次. 对于新的类c, 除属性的输出顺序外, 使用d.keys和dir(c)效果一样,但是对于旧的类(类的dir仅列出本身或覆盖的属性,并不列出继承的属性),has_memebers函数可能更有用些。
Line 66: Line 89:

all_members函数开始获得类层次中包含的相关类(类本身和直接和间接基类),按照属性查找的顺序,添加到变量mro(表示 method-resolution order 方法调用的解析顺序)中。对于一个新的提供了元组属性_ _ mro_ _的Python类,处理很快,只要将元组转换为list就可以了.如果访问_ _micro_ _失败,那么我们处理的是一个古典类,必须递归处理类层次,构造mro变量.代码中在except部分进行了递归处理.注意我们将函数getmtro作为递归参数传入,这样可以处理python的旧版本中语法不支持嵌套作用域。(##??)

文章来自《Python cookbook》.

翻译仅仅是为了个人学习,其它商业版权纠纷与此无关!

-- 60.7.17.36 [DateTime(2004-11-01T07:39:36Z)] TableOfContents

描述

Getting All Members of a Class Hierarchy Credit: Jürgen Hermann, Alex Martelli

获得类层次中所有成员属性

Credit: Jürgen Hermann, Alex Martelli

问题 Problem

You need to map all members of a class, including inherited members, into a dictionary of class attribute names.

需要映射一个类的所有属性,包括继承的属性,到一个以类属性名称作为键的字典中。

解决 Solution

Here is a solution that works portably and transparently on both new-style (Python 2.2) and classic classes with any Python version:

一个可以在Python的各种新(2.2)旧版本中使用的解决方法如下:

   1 def all_members(aClass):
   2     try:
   3         # Try getting all relevant classes in method-resolution order
   4         mro = list(aClass._ _mro_ _)
   5     except AttributeError:
   6         # If a class has no _ _mro_ _, then it's a classic class
   7         def getmro(aClass, recurse):
   8             mro = [aClass]
   9             for base in aClass._ _bases_ _: mro.extend(recurse(base, recurse))
  10             return mro
  11         mro = getmro(aClass, getmro)
  12     mro.reverse(  )
  13     members = {}
  14     for someClass in mro: members.update(vars(someClass))
  15     return members

讨论 Discussion

The all_members function in this recipe creates a dictionary that includes each member (such as methods and data attributes) of a class with the name as the key and the class attribute value as the corresponding value. Here's a usage example:

食谱中all_memebers函数创建了一个以类属性名称为键,属性值为对应字典值的字典。字典中包括了类的各种成员:函数成员和数据成员。下面是一个例子:

   1 class Eggs:
   2     eggs = 'eggs'
   3     spam = None
   4 
   5 class Spam:
   6     spam = 'spam'
   7 
   8 class Breakfast(Spam, Eggs):
   9     eggs = 'scrambled'
  10 
  11 print all_members(Eggs)
  12 print all_members(Spam)
  13 print all_members(Breakfast)

And here's the output of this example (note that the order in which each dictionary's items are printed is arbitrary and may vary between Python interpreters):

输出如下(注意字典的输出顺序是任意的,并且可能随Python解释器的不同而不同):

   1 {'spam': None, '_ _doc_ _': None, 'eggs': 'eggs', '_ _module_ _': '_ _main_ _'}
   2 {'spam': 'spam', '_ _doc_ _': None, '_ _module_ _': '_ _main_ _'}
   3 {'_ _doc_ _': None, 'eggs': 'scrambled', 'spam': 'spam', '_ _module_ _': '_ _main_ _'}

After constructing the dictionary d with d=all_members(c), you can use d for repeated introspection about class c. d.has_key(x) is the same as hasattr(c,x), and d.get(x) is the same as getattr(c,x,None), but it doesn't repeat the dynamic search procedure each time. Apart from the order of its items, d.keys is like dir(c) if c is a new-style class (for which dir also returns the names of inherited attributes) but is richer and potentially more useful than dir(c) if c is a classic class (for which dir does not list inherited attributes, only attributes defined or overridden directly in class c itself).

在使用d=all_memebers(c)构建字典d之后, 可以多次使用introspectoin来查询类c。判断类c 是否含有属性x使用: d.has_key(x), 效果同 hasattr(c,x)是一样的,获的类c的x属性使用 d.get(x),同getattr(c,x,None)效果也相同。使用字典d.has_key(x),以及d.get(x), 效率上得到提升, 不需要每次动态查询类的继承层次. 对于新的类c, 除属性的输出顺序外, 使用d.keys和dir(c)效果一样,但是对于旧的类(类的dir仅列出本身或覆盖的属性,并不列出继承的属性),has_memebers函数可能更有用些。

The all_members function starts by getting a list of all relevant classes (the class itself and all of its bases, direct and indirect), in the order in which attributes are looked up, in the mro variable (MRO stands for method-resolution order). This happens immediately for a new-style class, since it exposes this information with its _ _mro_ _ attribute梬e just need to build a list from it, since it is a tuple. If accessing _ _mro_ _ fails, we're dealing with a classic class and must build mro up in a recursive way. We do that in the nested function getmro in the except clause. Note that we give getmro itself as an argument to facilitate recursion in older Python versions that did not support lexically nested scopes.

all_members函数开始获得类层次中包含的相关类(类本身和直接和间接基类),按照属性查找的顺序,添加到变量mro(表示 method-resolution order 方法调用的解析顺序)中。对于一个新的提供了元组属性_ _ mro_ _的Python类,处理很快,只要将元组转换为list就可以了.如果访问_ _micro_ _失败,那么我们处理的是一个古典类,必须递归处理类层次,构造mro变量.代码中在except部分进行了递归处理.注意我们将函数getmtro作为递归参数传入,这样可以处理python的旧版本中语法不支持嵌套作用域。(##??)

Once we have mro, we need to reverse it, because we build up our dictionary with the update method. When we call adict.update(anotherdict), the entries in the two dictionaries adict and anotherdict are merged as the new contents of adict. In case of conflict (i.e., a key k is present in both dictionaries), the value used is anotherdict[k], which overrides the previous value of adict[k]. Therefore, we must build our dictionary starting with the classes that are looked up last when Python is looking for an attribute. We move towards the classes that are looked up earlier to reproduce how overriding works with inheritance. The dictionaries we merge in this way are those given sequentially by the built-in function vars on each class. vars takes any object as its argument and returns a dictionary of the object's attributes. Note that even for new-style classes in Python 2.2, vars does not consider inherited attributes, just the attributes defined or overridden directly in the object itself, as dir does only for classic classes.

参考 See Also

Understanding method resolution order is a new challenge even for old Python hands. The best description is in Guido's essay describing the unification of types and classes (http://www.python.org/2.2/descrintro.html#mro), which was refined somewhat in PEP 253 (http://www.python.org/peps/pep-0253.html).

PyCkBk-5-3 (last edited 2009-12-25 07:15:05 by localhost)