AttributeError: AS Instance has no attribute 'toString' - python

Writing code in Python for an Astar program to find the shortest path between cities. Getting the above error, and I'm at a complete loss. Pulling between a few .py files, here are the relevant sections:
from asdriver.py - added full asdriver
import adata # Map data
import astar # A* class
import sys
# Default start, goal cities
defaultcities = ('Yakima, WA', 'Tampa, FL')
def printnode(n):
print n.toString()
adata.input()
startcity = raw_input("Start city [{0}]: ".format(defaultcities[0])).strip()
if startcity == '': startcity = defaultcities[0]
if startcity not in adata.cities:
print "City not recognized"
sys.exit(0)
goalcity = raw_input("Goal city [{0}]: ".format(defaultcities[1])).strip()
if goalcity == '': goalcity = defaultcities[1]
if goalcity not in adata.cities:
print "City not recognized"
sys.exit(0)
dbg = raw_input("Debug Options: [none]").strip()
findpath = astar.AS(startcity, goalcity, printnode)
ans = findpath.astar_run(printnode, dbg)
if not ans:
print "No answer"
else:
print "Final Path:"
print ans.toString()
From astar.py
import adata
class AS:
def __init__(self, startcity, goalcity, tracefunc):
self.startcity = startcity
self.goalcity = goalcity
self.tracefunc = tracefunc
self.openlist = [Node([startcity])]
self.closedlist = []
def heuristic(self, printnode, start, end):
raise NotImplementedError
def astar_run(self, startcity, endcity, dbg = ""):
while self.openlist:
citystep = min(self.openlist, key = lambda o:o.g + o.h)
if citystep == self.goalcity:
path = []
while citystep.parent:
path.append(citystep)
citystep = citystep.parent
path.append(citystep)
return path[::-1]
self.openlist.remove(citystep)
self.closedlist.append(citystep)
for printnode in self.openlist: #was self.tracefunc
if printnode in self.closedset:
continue
elif printnode in self.openset:
newG = citystep.g + citystep.cost(printnode)
if printnode.g > newG:
printnode.g = newG
printnode.parent = citystep
else:
printnode.g = citystep.g + citystep.cost(printnode)
printnode.h = self.heuristic(printnode, start, end)
printnode.parent = citystep
self.openset.add(printnode)
return self
class Node:
def __init__(self, path=[], f=0, g=0, h=0):
self.path = path[:]
self.f = f
self.g = g
self.h = h
self.parent = None
def toString(self):
s = 'f=%d g=%d h=%d ' % (self.f, self.g, self.h)
for city in self.path:
s = s + ' ' + city
return s
def cost(self):
raise NotImplementedError
'
Complete beginner, so any help would be appreciated.
Thanks in advance!!!

Your def astar_run() method returns self (see last line of your method), or it returns a list by slicing the path[::-1], neither has a toString() method so you are getting this exception. If you want to print the representation of your class then it is normal to declare this method __repr__() and then you can just print ans. If you want to be able to convert to a string then the method is usually called __str__().
What do you expect to be return from astar_run()? It is usually poor practice to return two different types from the same function.

Related

How to handle the TypeError: 'int' object is not callable?

I want to implements a-star algorithm and the function (from Route_Algorithm.py) extends the nodes to get the next layor of f_value in the tree . The node can be regard as the station. And the self.settings.station_matrix is the numpy.matrix.
def voluation_station(self, successor, dest_location,bus_stations):
'''initilize all the f(g+h) to the specific nodes'''
length = len(self.settings.station_matrix[successor])
for end_element in range(length):
for station in bus_stations:
if int(station.name) == end_element:
station.get_g(self.settings.station_matrix[successor][end_element])
length_station = len(self.settings.station_matrix[end_element])
for element_station in range(length_station):
if element_station == dest_location:
station.get_h(self.settings.station_matrix[end_element][dest_location])
for element in bus_stations:
element.result_f()
return bus_stations
However, when I run the part of code. It reports the error like this:
Traceback (most recent call last):
File "/home/surface/Final-Year-Project/FYP/Main.py", line 4, in <module>
class main():
File "/home/surface/Final-Year-Project/FYP/Main.py", line 13, in main
new_route.busy_route_matrix()
File "/home/surface/Final-Year-Project/FYP/oop_objects/Route.py", line 87, in busy_route_matrix
self.route_algorithm.A_STAR_Algorithm(start_location,dest_location,self.bus_stations)
File "/home/surface/Final-Year-Project/FYP/Util/Route_Algorithm.py", line 40, in A_STAR_Algorithm
self.voluation_station(successor, dest_location,bus_stations)
File "/home/surface/Final-Year-Project/FYP/Util/Route_Algorithm.py", line 73, in voluation_station
station.get_g(self.settings.station_matrix[successor][end_element])
TypeError: 'int' object is not callable
I search the solution in the Internet, I think the problem may be in the end_element, maybe some inherient problem but I'm not sure. Can some one help me! Please!
Additional codes for other classes:
These classes are Util classes, which helps for handle oop_objects!
The class is for the Route_Algorithm:
from Util.Mergesort_algorithm import mergesort_algorithm
class route_algorithm():
'''generate the route to optimise the profiles'''
def __init__(self,settings):
# a* algorithm
self.open_list = []
self.close_list = []
self.route = []
self.settings = settings
self.flag_find = False
self.lines = []
# merge_sort algorithm
self.mergesort_algorithm = mergesort_algorithm()
def A_STAR_Algorithm(self, start_location, dest_location,bus_stations):
'''search the best route for each passenger to the destination'''
#self.clean_f(bus_stations)
# initial the value of f in start_location
for item in bus_stations:
if int(item.name) == start_location:
item.get_g = 0
for key, value in item.adjacent_station.items():
if int(key.name) == dest_location:
item.get_h = value
self.open_list.append(start_location)
#start_location is the name of station
while self.flag_find == False:
successor = self.open_list[0]
self.open_list.remove(successor)
self.route.append(successor)
self.voluation_station(successor, dest_location,bus_stations)
self.a_brain_judge_1(dest_location,bus_stations)
print(self.flag_find)
if self.flag_find == True:
#end the location
self.route.append(dest_location)
#add the line to the self.line
self.print_lines()
self.flag_find = False
self.open_list = []
else:
#continue to search the minimize
list = self.sort(bus_stations)
for item in list:
print(item.name)
print(item.f)
#疑问如果前两个的预估值一样该如何处理
self.open_list.append(int(list[0].name))
def voluation_station(self, successor, dest_location,bus_stations):
'''initilize all the f(g+h) to the specific nodes'''
length = len(self.settings.station_matrix[successor])
for end_element in range(length):
for station in bus_stations:
if int(station.name) == end_element:
station.get_g(self.settings.station_matrix[successor][end_element])
length_station = len(self.settings.station_matrix[end_element])
for element_station in range(length_station):
if element_station == dest_location:
station.get_h(self.settings.station_matrix[end_element][dest_location])
for element in bus_stations:
element.result_f()
return bus_stations
def a_brain_judge_1(self, dest_location,bus_stations):
'''whether the direct_line is the optimize'''
tmp_dest = bus_stations[0]
self.tmp_nodes = []
self.flag_find = True
for element in bus_stations:
if int(element.name) == dest_location:
tmp_dest = element
for element in bus_stations:
if element == tmp_dest:
pass
else:
if element.f < tmp_dest.f:
self.tmp_nodes.append(element)
self.flag_find = False
if self.flag_find == True:
self.route.append(tmp_dest.name)
return None
else:
return self.tmp_nodes
def sort(self,bus_stations):
'''sort all the f in the next stations'''
return self.mergesort_algorithm.Merge_Sort(bus_stations)
def print_lines(self):
#print(len(self.route))
for item in self.route:
print(item)
print("NEXT PASSENGER!---------")
def clean_f(self,stations):
for item in stations:
item.clean_data()
The class is Random_Algorithm, which helps for generate the random passengers.
import random
from Data.Settings import settings
from oop_objects.Bus_Station import bus_station
from oop_objects.Passenger import passenger
class random_algorithm():
'''generate the random bus-stations and passengers'''
def __init__(self):
self.setting = settings()
def random_passenger(self,number):
'''generate random passengers for bus-station,
and assumes there are 6 stations now. Furthermore, the data will be crawled by the creeper'''
passengers = []
for i in range(number):
new_passenger = passenger()
random.seed(self.setting.seed)
new_passenger.Change_Name(random.randint(1,self.setting.bus_station_number))
# generate the start-location
self.setting.seed +=1
end_location = random.randint(1,self.setting.bus_station_number)
# generate the end-location
while new_passenger.name == end_location:
self.setting.seed += 1
end_location = random.randint(1,self.setting.bus_station_number)
#judge whether the start-location same as the end-location
new_passenger.change_end_location(end_location)
passengers.append(new_passenger)
return passengers
def random_station(self,number):
'''generate the name of random stations '''
bus_stations = []
for i in range(number):
new_bus_station = bus_station()
new_bus_station.Name(str(i))
bus_stations.append(new_bus_station)
return bus_stations
def random_edge(self,bus_stations):
'''generate the edge information for the stations'''
for location1 in bus_stations:
#print("The information add in "+location1.name)
for location2 in bus_stations:
if location1 != location2:
#print("the "+location2.name+" was added in the "+location1.name)
if location2 not in location1.adjacent_station and location1 not in location2.adjacent_station:
random.seed(self.setting.seed)
edge = random.randint(1,self.setting.edge_distance)
location1.add_adjacent_station(location2,edge)
#print("the edge is "+str(edge))
self.setting.seed += 1
return bus_stations
The class is the mergesort_algorithm, which compare the f for different stations
class mergesort_algorithm():
def Merge_Sort(self,stations):
length = len(stations)
middle = int(length/2)
if length<=1:
return stations
else:
list1 = self.Merge_Sort(stations[:middle])
list2 = self.Merge_Sort(stations[middle:])
return self.Merge(list1,list2)
def Merge(self,list1,list2):
list3 = []
length1 = len(list1)
length2 = len(list2)
point1 = 0
point2 = 0
while point1<=length1-1 and point2<=length2-1:
if list1[point1].f<list2[point2].f:
list3.append(list1[point1])
point1 += 1
else:
list3.append(list2[point2])
point2 += 1
if point1>=length1:
for i in range(length2):
if i>=point2:
list3.append(list2[point2])
if point2>=length2:
for i in range(length1):
if i>=point1:
list3.append(list1[point1])
return list3
#def print_sort_result(self):
The following class are oop.classes
The class is for the Route:
from Util.Random_Algorithm import random_algorithm
from Data.Settings import settings
from Util.Route_Algorithm import route_algorithm
import numpy as np
class route():
def __init__(self):
self.bus_stations = []
self.passengers = []
self.settings = settings()
#random algorithm
self.random_algorithm = random_algorithm()
#route_algorithm
self.route_algorithm = route_algorithm(self.settings)
def start_route(self):
'''The raw route Information(TEXT) for bus_stations '''
stations = self.random_algorithm.random_station(self.settings.bus_station_number)
finsih_edge_stations = self.random_algorithm.random_edge(stations)
'''
for item in finsih_edge_stations:
print("\nthe information for " + item.name + " is: \t")
for key, value in item.adjacent_station.items():
print("the station is " + key.name)
print(" the distace is " + str(value))
'''
self.bus_stations = finsih_edge_stations
'''The raw route Information(Text) for passengers'''
self.passengers = self.random_algorithm.random_passenger(self.settings.passengers_number)
def bus_stations_matrix(self):
'''trasfer the raw text to the matrix'''
#create zero_matrix
length = len(self.bus_stations)
tmp_matrix = np.zeros(length*length)
station_matrix = tmp_matrix.reshape(length,length)
for item in self.bus_stations:
for key,value in item.adjacent_station.items():
station_matrix[int(item.name)][int(key.name)] = value
station_matrix[int(key.name)][int(item.name)] = value
print(station_matrix)
self.settings.station_matrix = station_matrix
def passengers_matrix(self):
'''trasfer the raw text to the matrix'''
length = len(self.bus_stations)
tmp_matrix = np.zeros(length*length)
passenger_matrix = tmp_matrix.reshape(length,length)
for item in self.passengers:
#print("the start location of passenger is "+str(item.name))
#print("the end location of passenger is "+str(item.end_location))
#print(" ")
passenger_matrix[item.name-1][item.end_location-1]+=1;
print(passenger_matrix)
self.settings.passenger_matrix = passenger_matrix
def busy_route_matrix(self):
'''generate the bus_busy_route matrix'''
#read the requirements of passengers
length = self.settings.bus_station_number
for start_location in range(length):
for dest_location in range(length):
if self.settings.passenger_matrix[start_location][dest_location] == 0:
pass
else:
magnitude = self.settings.passenger_matrix[start_location][dest_location]
#运行a*算法去寻找最短路径/run the a* algorithm to search the path
self.route_algorithm.A_STAR_Algorithm(start_location,dest_location,self.bus_stations)
print("------------------------------------")
def practice(self):
'''practice some programming'''
for element in self.bus_stations:
print((element.f))
The class is for the Passenger
class passenger():
def __init__(self):
self.name = 0
self.end_location = "null"
def Change_Name(self,name):
'''change the name of passenger'''
self.name = name
def change_end_location(self,location):
'''generate the end_location'''
self.end_location = location
The class for the bus_station
class bus_station():
'''the class represents the bus station'''
def __init__(self):
'''the attribute of name means the name of bus-station
the attribute of passenger means the passenger now in the bus-station'''
self.name = "null"
self.passenger = []
self.adjacent_station = {}
#A* algorithm
self.g = 0
self.h = 0
self.f = 0
def Name(self,name):
'''change the name of the station'''
self.name = name
def add_passengers(self,*passenger):
'''add the passenger in the bus-station'''
self.passenger.append(passenger)
def add_adjacent_station(self,station,edge):
'''add the adjacent station in the this station'''
self.adjacent_station[station] = edge
def get_g(self,value):
'''get the value of g (线路值)'''
self.g =self.g+ value
def get_h(self,value):
'''get the value of f (预估值)'''
self.h = value
def result_f(self):
'''print the value of f (实际值)'''
self.f = self.g+self.h
def add_self_cost(self):
self.add_adjacent_station()
The following class is storing the data.
The class is for the setting:
class settings():
def __init__(self):
self.seed = 5
self.bus_station_number = 10
self.passengers_number = 10
self.edge_distance = 50
self.station_matrix = None
self.passenger_matrix = None
And the main class to run the whole project:
from oop_objects.Route import route
class main():
new_route = route()
new_route.start_route()
print("The distance between different bus station :")
new_route.bus_stations_matrix()
print("The location information for passengers :")
new_route.passengers_matrix()
new_route.busy_route_matrix()
#new_route.practice()practice
#new_route.sort()bus_stations
You should avoid the station of successor because you have assigned the value by using the get_g
The result should be:
def voluation_station(self, successor, dest_location,bus_stations):
'''initilize all the f(g+h) to the specific nodes'''
length = len(self.settings.station_matrix[successor])
for end_element in range(length):
if end_element == successor:
pass
else:
for station in bus_stations:
if int(station.name) == end_element:
station.get_g(self.settings.station_matrix[successor][end_element])
length_station = len(self.settings.station_matrix[end_element])
for element_station in range(length_station):
if element_station == dest_location:
station.get_h(self.settings.station_matrix[end_element][dest_location])
for element in bus_stations:
element.result_f()
return bus_stations

How to define instantiation of object class as global variable in Python?

I am a starter & want to integrate dfs code with Fibonacci series generating code. The Fibonacci code too runs as dfs, with calls made from left to right.
The integration is incomplete still.
I have two issues :
(i) Unable to update 'path' correctly in fib(), as the output is not correctly depicting that.
(ii) Stated in fib() function below, as comment.
P.S.
Have one more issue that is concerned with program's working:
(iii) On modifying line #16 to: stack = root = stack[1:]; get the same output as before.
import sys
count = 0
root_counter = 0
#path=1
inf = -1
node_counter = 0
root =0
def get_depth_first_nodes(root):
nodes = []
stack = [root]
while stack:
cur_node = stack[0]
stack = stack[1:]
nodes.append(cur_node)
for child in cur_node.get_rev_children():
stack.insert(0, child)
return nodes
def node_counter_inc():
global node_counter
node_counter = node_counter + 1
class Node(object):
def __init__(self, id_,path):
self.id = node_counter_inc()
self.children = []
self.val = inf #On instantiation, val = -1, filled bottom up;
#except for leaf nodes
self.path = path
def __repr__(self):
return "Node: [%s]" % self.id
def add_child(self, node):
self.children.append(node)
def get_children(self):
return self.children
def get_rev_children(self):
children = self.children[:]
children.reverse()
return children
def fib(n, level, val, path):
global count, root_counter, root
print('count :', count, 'n:', n, 'dfs-path:', path)
count += 1
if n == 0 or n == 1:
path = path+1
root.add_child(Node(n, path))
return n
if root_counter == 0:
root = Node(n, path)
root_counter = 1
else:
#cur_node.add_child(Node(n, path)) -- discarded for next(new) line
root.add_child(Node(n, path))
tmp = fib(n-1, level + 1,inf, path) + fib(n-2, level + 1,inf,path+1)
#Issue 2: Need update node's val field with tmp.
#So, need suitable functions in Node() class for that.
print('tmp:', tmp, 'level', level)
return tmp
def test_depth_first_nodes():
fib(n,0,-1,1)
node_list = get_depth_first_nodes(root)
for node in node_list:
print(str(node))
if __name__ == "__main__":
n = int(input("Enter value of 'n': "))
test_depth_first_nodes()
Want to add that took idea for code from here.
Answer to the first question:
Path in this particular question is an int. It is a numbering of path from the root to a leaf in a greedy dfs manner.
This can be achieved by letting path be a global variable rather than an input to fib function. We increment the path count whenever we reach a leaf.
I have also modified the fib function to returns a node rather than a number.
import sys
count = 0
root_counter = 0
path=1
inf = -1
node_counter = 0
root = None
def node_counter_inc():
global node_counter
node_counter = node_counter + 1
print("node_counter:", node_counter)
return node_counter
class Node(object):
def __init__(self, id__,path):
print("calling node_counter_inc() for node:", n )
try:
self.id = int(node_counter_inc())
except TypeError:
self.id = 0 # or whatever you want to do
#self.id = int(node_counter_inc())
self.val = inf #On instantiation, val = -1, filled bottom up;
#except for leaf nodes
self.path = path
self.left = None
self.right = None
def __repr__(self):
return "Node" + str(self.id) + ":"+ str(self.val)
def fib(n, level, val):
# make fib returns a node rather than a value
global count, root_counter, root, path
print('count :', count, 'n:', n, 'dfs-path:', path)
count += 1
if n == 0 or n == 1:
path = path+1
new_Node = Node(n, path)
new_Node.val = n
return new_Node
#root.add_child(new_Node)
# return new_node
#if root_counter == 0:
# root = Node(n, path)
# root_counter = 1
#else:
#cur_node.add_child(Node(n, path)) -- discarded for next(new) line
# root.add_child(Node(n, path))
#tmp = fib(n-1, level + 1,inf) + fib(n-2, level + 1,inf)
#Issue 2: Need update node's val field with tmp.
#So, need suitable functions in Node() class for that.
#print('tmp:', tmp, 'level', level)
#return tmp
ans = Node(n, path)
ans.left = fib(n-1, level + 1, inf)
ans.right = fib(n-2, level + 1, inf)
ans.val = ans.left.val + ans.right.val
print("the node is", ans.id, "with left child", ans.left.id, "and right child", ans.right.id)
print("the corresponding values are", ans.val, ans.left.val, ans.right.val)
return ans
def test_depth_first_nodes():
ans = fib(n,0,-1)
print("The answer is", ans.val)
#node_list = get_depth_first_nodes(root)
#for node in node_list:
# print(str(node))
if __name__ == "__main__":
n = int(input("Enter value of 'n': "))
test_depth_first_nodes()

How to convert an object to iterable (list)?

I want to convert an object to an iterable.
I have the output of the format
>>>result[0]
<Particle [0.015270307267929021, -0.0009933688866323714, -0.004208897534490854, -0.011275132115610775, 0.0029132053067140572, 0.005608170262839968, 0.0005401367846572976, -0.013393458586919493, 0.0003998091070805884, 0.0002900137732599478]>
The full code of the problem is
from fstpso import FuzzyPSO
def example_fitness( particle ):
return sum(map(lambda x: x**2, particle))
if __name__ == '__main__':
dims = 10
FP = FuzzyPSO()
FP.set_search_space( [[-10, 10]]*dims )
FP.set_fitness(example_fitness)
result = FP.solve_with_fstpso()
print "Best solution:", result[0]
print "Whose fitness is:", result[1]
I want to use result[0] as the list.
Source
According to your comment which states it's fstpso.pso.Particle, if you just call the following, you'll be able to use it as iterator without changing the original source code.
variable = result[0].X
for i in variable:
print(i)
The original source code indicates the __repr__() function is just printing the self.X value, which is a list.
def __repr__(self):
return "<Particle %s>" % str(self.X)
The fstpso.pso.Particle object is as follows:
class Particle(object):
def __init__(self):
self.X = []
self.V = []
self.B = []
self.MarkedForRestart = False
self.CalculatedFitness = sys.float_info.max
self.FitnessDevStandard = sys.float_info.max
self.CalculatedBestFitness = sys.float_info.max
self.SinceLastLocalUpdate = 0
self.DerivativeFitness = 0
self.MagnitudeMovement = 0
self.DistanceFromBest = sys.float_info.max
self.CognitiveFactor = 2.
self.SocialFactor = 2.
self.Inertia = 0.5
# support for PPSO
self.MaxSpeedMultiplier = .25
self.MinSpeedMultiplier = 0
def __repr__(self):
return "<Particle %s>" % str(self.X)
def __str__(self):
return "\t".join(map(str, self.X))
From https://github.com/aresio/fst-pso/blob/master/fstpso/pso.py
What you want can be got with:
result[0].X

Error: object() takes no parameters , cant resolve it

this is python file im trying to make A*algorithm , but cant get it to work, I need some help , its an awesome code , its been run in latest python version for windows
from queue import PriorityQueue
class State(object):
def _init_(self,value,parent,start = 0,goal = 0):
self.children = []
self.value = value
self.parent = parent
self.dist = 0
if parent:
self.path = parent.path[:]
self.path.append(value)
self.start = parent.start
self.goal = parent.goal
else:
self.path = [value]
self.start = start
self.goal = goal
def GetDist(self):
pass
def CreateChildren(self):
pass
class State_String(State):
def _init_(self,value,parent,start = 0,goal = 0):
super(State_String,self).__init__(value,parent,start,goal)
self.dist = self.GetDist()
def GetDist(self):
if self.value == self.goal:
return 0
dist = 0
for i in range(len(self.goal)):
letter = self.goal[i]
dist += abs(i - self.value.index(letter))
return dist
def CreateChildren(self):
if not self.children:
for i in xrange(len(self.goal)-1):
val = self.value
val = val[:i] + val[i+1] + val[i] + val[i+2:]
child = State_String(val,self)
self.children.append(child)
class AStar_Solver:
def _init_(self,start,goal):
self.path = []
self.visitedQueue = []
self.priorityQueue = PriorityQueue()
self.start = start
self.goal = goal
def Solve(self):
startState = State_String(self.start,0,self.start,self.goal)
count = 0
self.priorityQueue.put((0,count,startState))
while(not self.path and self.priorityQueue.qsize()):
closestChild = self.priorityQueue.get()[2]
closestChild.CreateChildren()
self.visitedQueue.append(closestChild.value)
for child in closestChild.children:
if child.value not in self.visitedQueue:
count +=1
if not child.dist:
self.path = child.path
break
self.priorityQueue.put((child.dist,count,child))
if not self.path:
print "Goal of " + self.goal + " is not possible!"
return self.path
if _name_ == '__main__':
start1 = "hma"
goal1 = "ham"
a = AStar_Solver(start1,goal1)
a.Solve()
for i in xrange(len(a.path)):
print " %d)" %i + a.path[i]
getting these errors:
Traceback (most recent call last):
File "C:/Users/Herby/Desktop/untitled/Astar.py", line 82, in <module>
a.Solve()
File "C:/Users/Herby/Desktop/untitled/Astar.py", line 59, in Solve
startState = State_String(self.start,0,self.start,self.goal)
TypeError: object() takes no parameters
I need to know how it can be fixed
All of your init in your classes are written with single underscore instead of double underscore:
Change all init written as: _init_ to __init__
Also, this line is incorrect as well:
if _name_ == '__main__':
It needs to be double underscore for name as well
if __name__ == '__main__':
If you're interested, here is more information on why this is needed:
https://www.python.org/dev/peps/pep-0008/
In particular look at the description for: "double_leading_and_trailing_underscore"

OpenMaya API (python): print more useful info from MObjects? E.g. MFloatVector(x, y, z)

With regular python objects, it is easy to see their details.
E.g.
vec = (1, 2, 3)
print vec
=>
(1, 2, 3)
When working with equivalent OpenMaya (OM) objects, all print or str() shows is the type of object:
vec = OpenMaya.MFloatVector(1,2,3)
print vec
=>
<maya.OpenMaya.MFloatVector; proxy of <Swig Object of type 'MFloatVector *' at 0x000000002A346060> >
Is there a general way to ask an MObject to provide more details?
I'd like a result something like:
MFloatVector(1, 2, 3)
----- EDIT -----
From C++ documentation, I see that the information I want is available in C++ via the ostream << operator. E.g. for MFloatVector's << it says:
The format used is [x, y, z]
So another way to ask my question is: In python, how do I create an ostream in memory, send the object to it, then get the result as a string?
----- EDIT #2 -----
My import statement is:
import maya.OpenMaya as OpenMaya
This means I am using Version 1 of Maya Python API. (Because some of the Version 2 stuff is stubs, such as MGlobal. Examples I am looking at use these Version 1 features, so I stayed with Version 1.)
I've posted my own answer, which is to use Version 2, to get the desired behavior. TBD whether Version 2 has everything needed, and what is required to convert Version 1 examples to Version 2. For now, I'm sticking to Version 1. If anyone has a way to get Version 1 to provide more useful print details, that is what I would accept as an answer.
Version 2 of Maya Python API is more python-friendly.
To access Version 2, change the import statement from
import maya.OpenMaya as OpenMaya
to
import maya.api.OpenMaya as OpenMaya
This will require changes to the script, as many methods are tweaked to be more python friendly.
Once this is done, "print vec" and "str(vec)" and "len(vec)" all become useful operations:
vec = OpenMaya.MFloatVector(1, 2, 3)
print vec
print str(vec)
print len(vec)
=>
(1, 2, 3)
(1, 2, 3)
3
Well it is certainly possible to wrap the repr function with your own; something along the lines of:
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
This would affect all future (but not past) MFloatVectors. But why you would go trough such a trouble is another matter. As for working in general for MObjects too much work on this level. However you could try to ask obj.length() of each object to determine if its iterable etc etc. so you could get a quite good spread still too much work for not much gain.
Here is code that defines "Repr(self)". A global function that returns "repr(self)" for most objects. But for objects that return a representation starting with "<", the result is a list of member values that (1) aren't internal (don't start with '__'), and (2) aren't methods.
E.g. an OpenMaya MFloatVector instance "OpenMaya.MFloatVector( 1, 2, 3)" gives result:
#MFloatVector( x: 1.0, y: 2.0, z: 3.0)
The code:
# ==================== 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()

Categories

Resources