![](/img/trans.png)
[英]Python `argparse`: Is there a clean way to add a flag that sets multiple flags (e.g. `--all`" is equivalent to `--x --y`)
[英]OpenMaya API (python): print more useful info from MObjects? E.g. MFloatVector(x, y, z)
使用常規的python對象,很容易看到它們的詳細信息。 例如
vec = (1, 2, 3)
print vec
=>
(1, 2, 3)
當使用等效的OpenMaya(OM)對象時,所有print或str()顯示的都是對象的類型:
vec = OpenMaya.MFloatVector(1,2,3)
print vec
=>
<maya.OpenMaya.MFloatVector; proxy of <Swig Object of type 'MFloatVector *' at 0x000000002A346060> >
有沒有一般的方法可以要求MObject提供更多詳細信息? 我想要一個類似的結果:
MFloatVector(1, 2, 3)
----- 編輯 -----
從C ++文檔中,我可以通過ostream <<運算符在C ++中獲得所需的信息。 例如,MFloatVector的<<表示:
使用的格式為[x,y,z]
因此,提出我的問題的另一種方法是:在python中,如何在內存中創建一個ostream,將對象發送給它,然后以字符串形式獲取結果?
----- 編輯2 -----
我的進口聲明是:
import maya.OpenMaya as OpenMaya
這意味着我正在使用Maya Python API的版本1。 (因為某些版本2的東西是存根,例如MGlobal。我正在查看示例使用這些版本1的功能,所以我仍然使用版本1。)
我已經發布了自己的答案,即使用版本2來獲得所需的行為。 TBD是否需要版本2的所有內容,以及將版本1的示例轉換為版本2所需的內容。目前,我堅持使用版本1。如果有人可以獲取版本1來提供更多有用的打印詳細信息,那就是我會接受的答案。
Maya Python API的版本2對python更友好。
要訪問版本2,請從以下位置更改導入語句
import maya.OpenMaya as OpenMaya
至
import maya.api.OpenMaya as OpenMaya
這將需要對腳本進行更改,因為許多方法都經過了調整,使其對python更友好。
完成此操作后,“ print vec”,“ str(vec)”和“ len(vec)”都將變為有用的操作:
vec = OpenMaya.MFloatVector(1, 2, 3)
print vec
print str(vec)
print len(vec)
=>
(1, 2, 3)
(1, 2, 3)
3
好吧, 可以將repr函數與您自己的包裝在一起; 類似於以下內容:
import maya.OpenMaya as om
def repr_MfloatVector(self):
n = self.__class__.__name__
return "%s(%r, %r, %r)"%(n, self[0], self[1], self[2])
om.MFloatVector.__repr__ = repr_MfloatVector
vec = om.MFloatVector(1,2,3)
print vec
這將影響所有將來(但不是過去)的MFloatVectors。 但是,為什么要陷入這樣的麻煩是另一回事。 至於MObjects的一般工作,在此級別上需要進行太多工作。 但是,您可以嘗試詢問每個對象的obj.length()以確定其是否可迭代,等等。這樣,您可以得到很好的傳播,但仍然進行了太多的工作而沒有太多收獲。
這是定義“ Repr(self)”的代碼。 對於大多數對象返回“ repr(self)”的全局函數。 但是對於返回以“ <”開頭的表示形式的對象,結果是一個成員值列表,這些成員值(1)不是內部的(不要以'__'開頭),而(2)不是方法。
例如,OpenMaya MFloatVector實例“ OpenMaya.MFloatVector(1,2,3)”給出結果:
#MFloatVector( x: 1.0, y: 2.0, z: 3.0)
編碼:
# ==================== AttributeAccess.py ====================
import maya.cmds as cmds
import maya.mel as mel
import sys
import maya.OpenMaya as OM # Version 1
import math
import inspect
import types
# ---------- Common Stuff ----------
# "something" can be any Python object.
def Exists(something):
return something is not None
def printElements(ob):
print '----- Elements: -----'
i = 0
for x in ob:
print ' [' + str(i) + ']: ' + repr(x)
i += 1
print '---------------------'
def printDictElements(ob):
print ''
print '-----------------------'
for x in ob: print repr(x) + ': ' + repr(ob[x])
print '-----------------------'
# ---------- inspect Attributes ----------
# NOTE: ob is an instance, NOT a type object.
def TypeName(ob):
return ob.__class__ .__name__
# Excludes 'internal' names (start with '__').
def Public(name):
return not name.startswith('__')
# member is element of inspect.getmembers:
# a two-element tuple.
def MemberWithType(member):
return ( member[0], TypeName(member[1]), member[1] )
#print MemberWithType( (1.1, 2) )
def Members(ob):
return inspect.getmembers(ob)
# True for Maya Python's 'this' member.
# member [1] is attribute value.
def SwigThis(member):
return (member[0] == 'this') and (TypeName(member[1]) == 'SwigPyObject')
# HACK: "not SwigThis": omit Maya Python's 'this' member.
def PublicMembers(ob):
members = filter(lambda member: Public(member[0]) and not SwigThis(member), Members(ob))
return map(MemberWithType, members)
# Excludes 'internal' names (start with '__').
def Dir(ob):
return filter(Public, dir(ob))
def _Type_And_Features(ob, names):
return '{0}.({1})'.format(TypeName(ob), ', '.join(names))
def MemberName(member):
return member[0]
# member with typename inserted as [1]. So descriptor is [2].
# member type-name is [1].
def CallableMember(member):
#return (member[2].__class__ is types.MethodType)
return inspect.isroutine(member[2])
def MemberNames(members):
return map(MemberName, members)
def Features(ob):
return _Type_And_Features(ob, MemberNames(PublicMembers(ob)) )
#return _Type_And_Features(ob, Dir(ob))
def Callable(ob):
return _Type_And_Features(ob, MemberNames(filter(lambda a: CallableMember(a), PublicMembers(ob))))
#return _Type_And_Features(ob, filter(lambda a: callable(a), Dir(ob)))
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
# ---------- _MayaValues ----------
# NOTE: 'ob' is an instance, not the class (type) itself.
def _ClassVars(ob):
attributes = filter(lambda a: not CallableMember(a), PublicMembers(ob))
# Keep class variables.
# "not IsProperty": HACK: Skip Maya/Swig 'property' class variables.
classVars = filter(lambda desc: IsClassVar(ob, desc[0]) and not IsProperty(getattr(ob.__class__, desc[0])), attributes)
return MemberNames(classVars)
# NOTE: 'ob' is an instance, not the class (type) itself.
def ClassVars(ob):
return _Header_And_Values(TypeName(ob) + ' Class_Variables',
map(lambda attr: attr + ': ' + Repr(getattr(ob, attr)), _ClassVars(ob)),
0
)
# If it is invocable without parameters, return (attrName, typename, result of invocation).
# if Not reportExceptions, return None for Exception.
def CallAttribute_AsTriple(self, attrName, reportExceptions=False):
try:
expressionString = 'self.{0}()'.format(attrName)
result = eval(expressionString)
typename = TypeName(result)
except Exception as e:
if reportExceptions:
result = e
typename = '*** Exception'
else:
return None
return (attrName, typename, result)
# member is tuple (attrName, typeName, value)
# If it is invocable without parameters, return (attrName, typename, result of invocation).
# if Not reportExceptions, return None for Exception.
def CallMember_AsTriple(self, member, reportExceptions=False):
return CallAttribute_AsTriple(self, member[0], reportExceptions)
# If it is invocable without parameters, return string: pretty-printed result of invocation.
# if Not reportExceptions, return None for Exception.
def CallAttribute(self, attrName, reportExceptions=False):
try:
#printElements(locals())
expressionString = 'self.{0}()'.format(attrName)
#print Eval(expressionString, locals())
result = eval(expressionString)
resultString = Repr(result)
typename = TypeName(result)
except Exception as e:
if reportExceptions:
#result = '*** Exception ' + str(e)
result = e
resultString = str(e)
typename = '*** Exception'
else:
return None
return ' .{0} {{{1}}}= {2}'.format(attrName, typename, resultString)
# member is tuple (attrName, typeName, value)
# If it is invocable without parameters, return string: pretty-printed result of invocation.
# if Not reportExceptions, return None for Exception.
def CallMemberRepr(self, member, reportExceptions=False):
return CallAttribute(self, member[0], reportExceptions)
def FirstLine(string):
lines = string.split('\n')
if len(lines) > 1:
return lines[0] + '...'
return string
def ArgLessRoutines_AsTriples(ob):
members = PublicMembers(ob)
members_WithNones = map(lambda member: CallMember_AsTriple(ob, member), members)
# member is tuple (attrName, typeName, value)
members = filter(Exists, members_WithNones)
return members
def ArgLessRoutines(ob):
members = PublicMembers(ob)
members_WithNones = map(lambda member: CallMember_AsTriple(ob, member), members)
# member is tuple (attrName, typeName, value)
members = filter(Exists, members_WithNones)
resultStrings = map(lambda string: FirstLine(string), resultStrings)
return _Header_And_Values(TypeName(ob) + ' ArgLessRoutines', resultStrings)
def _MayaCallables_Common(mayaType):
try:
typeName = mayaType.__name__
if typeName == 'MDagPath':
return ['fullPathName']
if typeName == 'MTypeId':
return ['id']
if typeName == 'MFnMesh':
return ['numPolygons', 'numVertices', 'numEdges', 'numFaceVertices']
if typeName == 'MDagPath':
return ['fullPathName']
except Exception as e:
print e
return []
def _MayaCallables_Version1(mayaType):
return _MayaCallables_Common(mayaType)
def _MayaCallables_Version2(mayaType):
return _MayaCallables_Common(mayaType)
# Names of callable attributes to include in Repr of 'ob'.
# For instances of types in 'maya.OpenMaya'.
def MayaCallables(ob):
try:
typ = ob.__class__
if typ == type:
return []
if typ.__module__ == 'maya.OpenMaya':
return _MayaCallables_Version1(typ)
if typ.__module__ == 'OpenMaya':
return _MayaCallables_Version2(typ)
except Exception as e:
print e
return []
# Return (name, typename, value) per maya callable.
def _MayaValues(ob):
callables = MayaCallables(ob)
members_WithNones = map(lambda attrName: CallAttribute_AsTriple(ob, attrName), callables)
members = filter(Exists, members_WithNones)
return members
# TODO: If all results fit on single line, remove "{typename}" so is more readable.
#def MayaValues(ob):
# resultStrings = _MayaValues(ob)
# return _Header_And_Values(TypeName(ob) + ' MayaValues', resultStrings)
# ---------- Attributes ----------
def _AttributeNames(ob):
attributes = filter(lambda a: not CallableMember(a), PublicMembers(ob))
# Omit class variables.
attributes = filter(lambda desc: IsNotSameAsClassVar(ob, desc[0]), attributes)
return MemberNames(attributes)
def AttributeNames(ob):
return _Type_And_Features(ob, _AttributeNames(ob))
#return _Type_And_Features(ob, filter(lambda a: not callable(a), Dir(ob)))
def _Header_And_Values(headerString, valueStrings, maxWidth=100):
if sum(map(len, valueStrings)) > maxWidth:
# pretty print, with one value per line.
return '{0}(\n {1}\n)'.format(headerString, '\n '.join(valueStrings))
return '{0}({1})'.format(headerString, ', '.join(valueStrings))
def _Type_And_Values(ob, valueStrings, maxWidth=100):
return _Header_And_Values(TypeName(ob), valueStrings, maxWidth)
def AttributeValues(ob):
return _Type_And_Values(ob, map(lambda attr: str(getattr(ob, attr)), _AttributeNames(ob)))
def Attributes(ob, depth=0):
# Limit recursion.
# If deep, don't include MayaValues.
if depth >= 2:
return _Type_And_Values(ob, map(lambda attr: attr + ': ' + str(getattr(ob, attr)), _AttributeNames(ob)))
attributes = map(lambda attr: attr + ': ' + Repr(getattr(ob, attr), depth + 1), _AttributeNames(ob))
if depth == 0:
mayaValues = _MayaValues(ob)
if len(mayaValues) > 0:
for mayaValue in mayaValues:
attribute = mayaValue[0] + ': ' + Repr(mayaValue[2])
attributes.append(attribute)
return _Type_And_Values(ob, attributes)
def IsProperty(ob):
return (TypeName(ob) == 'property')
# ---------- Repr ----------
def Repr(ob, depth=0):
r = repr(ob)
# Helps avoid undesired recursion.
if ob.__class__ == type:
return r
if (r.__class__ == types.StringType) and (len(r) > 0) and (r.find('<') <> 0):
# Has a good repr.
return r
# Doesn't have a good repr; inspect it instead.
return '#' + Attributes(ob, depth)
def Eval(expressionString, _locals=locals(), _globals=globals()):
return str(expressionString) + "= " + str(Repr(eval(expressionString, _globals, _locals)))
# ---------- Testing ----------
# ---------- 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)
# ==
def __eq__(self, other):
return (self.__class__ == other.__class__) and \
(self.x == other.x) and \
(self.y == other.y) and \
(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()
# ---------- inspecting Vector ----------
def Testing_Vector_Attributes():
#vec = (1, 2, 3)
#vec = [1, 2, 3]
#vec = Vector(1.0, 2.0, 3.0)
vec = OM.MFloatVector(1, 2, 3)
print vec
#for x in vec: print x
print dir(vec)
print TypeName(vec)
print Dir(vec)
print Features(vec)
print Callable(vec)
print '-----------------------'
printElements(PublicMembers(vec))
print '-----------------------'
print AttributeNames(vec)
#print vec.x
#print eval('vec.x')
#print getattr(vec, 'x')
print AttributeValues(vec)
print Attributes(vec)
vec = OM.MFloatVector(1, 2, 3)
#print repr(vec)
#print Repr('Hi')
print Repr( (1,2,3) )
print Repr(vec)
print ClassVars( Vector(1.0, 2.0, 3.0) )
print ClassVars( OM.MFloatVector(1, 2, 3) )
print Eval('OM.MMatrix()')
print Eval('OM.MMatrix().matrix')
if __name__ == "__main__":
Testing_Vector_Attributes()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.