python中类的属性一般来说是通过类名来访问,Python:如何确定属性(按名称)是类还是实例属性?...

Goal (in Python 2.7):

Inspecting an arbitrary object, find all of the instance variables. But exclude class variables.

Ultimate goal:

Print useful details of an object, from a third-party class library that doesn't provide a useful "str" implementation. (Maya's Python API, version 1, which is a simple SWIG wrapper.

not using version 2, because I'm learning from some version 1 examples.)

Example class:

# ---------- class Vector ----------

class Vector(object):

def __init__(self, x=0.0, y=0.0, z=0.0):

self.x, self.y, self.z = x, y, z

# Provide useful info for 'repr(self)', 'str(self)', and 'print self'.

def __repr__(self):

return 'Vector({0}, {1}, {2})'.format(self.x, self.y, self.z)

# math operators

def __add__(self, other):

return Vector(self.x + other.x, self.y + other.y, self.z + other.z)

# a simple method

def ApproximateLength(self):

return self.x + self.y + self.z

# list/sequence/iterator support.

def tolist(self):

return [self.x, self.y, self.z]

def __len__(self):

return 3

# No need for "next(self)", because we create a list, use its iterator.

def __iter__(self):

return iter(self.tolist())

# class variable

Vector.Zero = Vector()

Solution so far:

import inspect

import types

def printElements(ob):

for x in ob: print x

# Excludes 'internal' names (start with '__').

def Public(name):

return not name.startswith('__')

def Attributes(ob):

# Exclude methods.

attributes = inspect.getmembers(ob, lambda member: not inspect.ismethod(member))

# Exclude 'internal' names.

publicAttributes = filter(lambda desc: Public(desc[0]), attributes)

return publicAttributes

Example usage:

vec = Vector(1.0, 2.0, 3.0)

printElements(Attributes(vec))

Output:

('Zero', Vector(0.0, 0.0, 0.0))

('x', 1.0)

('y', 2.0)

('z', 3.0)

This class does print itself well:

print vec

=>

Vector(1.0, 2.0, 3.0)

The goal is to extract similar information, for classes that I don't have source to (or don't want to modify the source of). Those classes have many class variables, which bury the information I seek.

Question:

How detect that 'Zero' is a "class variable", inherited from Vector, to eliminate it from the output?

Clumsy approach I will use if no better way:

printElements(Attributes(type(vec)))

lists the attributes on the object's type. Could test each attribute of "vec" against the attributes of "type(vec)", excluding any that match. I don't care about the subtle possibility that the same named attribute exists on both class and instance. So this would satisfy my requirements.

However, that seems clumsy. Is there a more direct way to determine whether the attribute is inherited from the class?

EDIT: Incorporating Joran's answer:

def IsClassVar(self, attrName):

return hasattr(self.__class__, attrName)

def Attributes(ob):

....

publicAttributes = filter(lambda desc: Public(desc[0]), attributes)

# Exclude 'class' variables.

# NOTE: This does not attempt to detect whether the instance variable is different than the class variable.

publicAttributes = filter(lambda desc: not isClassVar(ob, desc[0]), publicAttributes)

return publicAttributes

This gives the desired result:

printElements(Attributes(vec))

=>

('x', 1.0)

('y', 2.0)

('z', 3.0)

Alternative, To detect instance variable overriding class variable:

def IsClassVar(self, attrName):

return hasattr(self.__class__, attrName)

# REQUIRE attrName already known to be supported by self.

# But just in case, return False if exception, so will be skipped.

def IsNotSameAsClassVar(self, attrName):

try:

if not IsClassVar(self, attrName):

return True

# If it has different value than class' attribute, it is on the instance.

return getattr(self, attrName) is not getattr(self.__class__, attrName)

except:

return False

def Attributes(ob):

....

publicAttributes = filter(lambda desc: Public(desc[0]), attributes)

# Exclude 'class' variables.

# More complete solution.

publicAttributes = filter(lambda desc: IsNotSameAsClassVar(ob, desc[0]), publicAttributes)

return publicAttributes

Now if we override 'Zero' on vec, it gets included:

# Probably a bad idea, but showing the principle.

vec.Zero = "Surprise!"

Then:

print vec.Zero

print Vector.Zero

=>

Surprise!

Vector(0.0, 0.0, 0.0)

And:

printElements(Attributes(vec))

=>

('Zero', 'Surprise!')

('x', 1.0)

('y', 2.0)

('z', 3.0)

解决方案

something like this may work

def isClassVar(self,varname):

return hasattr(self.__class__,varname)

...

vec.isClassVar("Zero")

note that this does not necessarily mean it is an instance variable ... just that is is not a class variable

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值