I've been working on a text based game in Tkinter, and I need a way so as to allow more flexibility with input. Basically, what I'm looking for is how to code:
if Input.get() == "look at" Item:
Item.look()
But with the flexibility of 'item' being a class, with subclasses, all of which can be 'looked at'. This is my current (non-working) code for this segment:
def Check():
if Output == "look at" Item:
Item.look()
else:
pass
class Item():
def __init__(self, name, description, value, quantity):
self.name = name
self.description = description
self.value = value
def look(self):
Look.Title = "{}".format(self.name)
Look.Description = "{}".format(self.Description)
Look.Value = "{} is worth {}.".format(self.name, self.value)
Details.insert(Look.Title)
Details.insert(Look.Description)
Details.insert(Look.Value)
Details.insert(Look.Quantity)
class Headphones(Item):
def __init__(self):
super.__init__(name = "Headphones", description = "A set of high quality white headphones.", value = 150)
Any help is much appreciated,
Blaze
You will need to do some sort of mapping between the input and the functions you want to call. You will need to parse the string in order to pull out the object from the input string and use the result of the parsing to look up the proper object or class.
For example, you could use a regular expression to parse the string "look at X", and then use "X" as an index into a dictionary in order to know what class to instantiate.
Here's a simple example:
import re
class Headphones(object):
def look(self):
print("you are looking at headphones")
class Goggles(object):
def look(self):
print("you are looking at goggles")
class Unknown(object):
def look(self):
print("I don't know what you're looking at")
def check(input):
map = {
"goggles": Goggles,
"headphones": Headphones,
}
match = re.match(r'look at (.*)', input)
if match:
thing = match.group(1)
cls = map.get(thing, Unknown)
object = cls()
object.look()
for phrase in ("look at headphones",
"look at goggles",
"look at something else"):
check(phrase)
Note: this is one of many ways to solve the problem. The point is, you need to:
write a parser that can pull out the important parts from the input, and
use the result of the parsing stage to decide how to process the data
The parser can be anything from simply splitting the input on spaces and grabbing the last word, to using a regular expression, to using a full blown parser using something like pyparsing.
Related
I was just practicing class and object
The code is
I already know the second function def name is overlapped since name is already set as self.name. but I am not sure how it makes error.
Can anyone tell how to fix this problem?
The error is pretty descriptive; strings aren't callable, functions are. I believe Python will look for variables within the class before it checks if there are functions with a given name. Thus, the string name is found but because it has () added to it, python then tries to call it like a function and fails.
Simply rename the function or the variable. You could use self._name as the variable name if you want to indicate that it's private and shouldn't be changed - at least not from outside the class. You'll also have to write print "The University name is %s" % (self._name) (and self.rank).
You already have a variable called name in your class University, so the program is trying to call "University of America"(), which triggers an error. Thus, change the function name to something like print_name:
class University():
def __init__(self, name, rank):
self.name = name
self.rank = rank
def print_name(self):
print "The University name is %s" % (self.name)
print "This University is ranked at %s" % (self.rank)
>>> users = University("University of America", "#1")
>>> users.name #The string of the name
'University of America'
>>> users.print_name()
The University name is University of America
This University is ranked at #1
>>>
I'm trying to make a simple RPG game. I have a list of people that will be in the game, and want to create a character for each of them.
people = ['Mike','Tom']
class Character(object):
def __init__(self,name):
self.name = name
self.health = '100'
for x in people:
[x] = Character(x) # This is where I don't know what to do / if it's possible
That way I can call a character easily like
for x in people:
print ("%s: %s health" % (people[x].name, people[x].health))
Is such a thing possible, or am I going about this wrong? I read over How do I create a variable number of variables? but it seemed like dictionaries were the ultimate fix for their problem, and I have no idea how that would work in this situation.
It looks like you're just wanting to keep a list of Character objects. You don't need to reference people once you have that.
characters = [Character(person) for person in people]
Then, to print the character stats:
for c in characters:
print ("%s: %s health" % (c.name, c.health))
I'm working with the program Autodesk Maya.
I've made a naming convention script that will name each item in a certain convention accordingly. However I have it list every time in the scene, then check if the chosen name matches any current name in the scene, and then I have it rename it and recheck once more through the scene if there is a duplicate.
However, when i run the code, it can take as long as 30 seconds to a minute or more to run through it all. At first I had no idea what was making my code run slow, as it worked fine in a relatively low scene amount. But then when i put print statements in the check scene code, i saw that it was taking a long time to check through all the items in the scene, and check for duplicates.
The ls() command provides a unicode list of all the items in the scene. These items can be relatively large, up to a thousand or more if the scene has even a moderate amount of items, a normal scene would be several times larger than the testing scene i have at the moment (which has about 794 items in this list).
Is this supposed to take this long? Is the method i'm using to compare things inefficient? I'm not sure what to do here, the code is taking an excessive amount of time, i'm also wondering if it could be anything else in the code, but this seems like it might be it.
Here is some code below.
class Name(object):
"""A naming convention class that runs passed arguments through user
dictionary, and returns formatted string of users input naming convention.
"""
def __init__(self, user_conv):
self.user_conv = user_conv
# an example of a user convention is '${prefix}_${name}_${side}_${objtype}'
#staticmethod
def abbrev_lib(word):
# a dictionary of abbreviated words is here, takes in a string
# and returns an abbreviated string, if not found return given string
#staticmethod
def check_scene(name):
"""Checks entire scene for same name. If duplicate exists,
Keyword Arguments:
name -- (string) name of object to be checked
"""
scene = ls()
match = [x for x in scene if isinstance(x, collections.Iterable)
and (name in x)]
if not match:
return name
else:
return ''
def convert(self, prefix, name, side, objtype):
"""Converts given information about object into user specified convention.
Keyword Arguments:
prefix -- what is prefixed before the name
name -- name of the object or node
side -- what side the object is on, example 'left' or 'right'
obj_type -- the type of the object, example 'joint' or 'multiplyDivide'
"""
prefix = self.abbrev_lib(prefix)
name = self.abbrev_lib(name)
side = ''.join([self.abbrev_lib(x) for x in side])
objtype = self.abbrev_lib(objtype)
i = 02
checked = ''
subs = {'prefix': prefix, 'name': name, 'side':
side, 'objtype': objtype}
while self.checked == '':
newname = Template (self.user_conv.lower())
newname = newname.safe_substitute(**subs)
newname = newname.strip('_')
newname = newname.replace('__', '_')
checked = self.check_scene(newname)
if checked == '' and i < 100:
subs['objtype'] = '%s%s' %(objtype, i)
i+=1
else:
break
return checked
are you running this many times? You are potentially trolling a list of several hundred or a few thousand items for each iteration inside while self.checked =='', which would be a likely culprit. FWIW prints are also very slow in Maya, especially if you're printing a long list - so doing that many times will definitely be slow no matter what.
I'd try a couple of things to speed this up:
limit your searches to one type at a time - why troll through hundreds of random nodes if you only care about MultiplyDivide right now?
Use a set or a dictionary to search, rather than a list - sets and dictionaries use hashsets and are faster for lookups
If you're worried about maintining a naming convetion, definitely design it to be resistant to Maya's default behavior which is to append numeric suffixes to keep names unique. Any naming convention which doesn't support this will be a pain in the butt for all time, because you can't prevent Maya from doing this in the ordinary course of business. On the other hand if you use that for differntiating instances you don't need to do any uniquification at all - just use rename() on the object and capture the result. The weakness there is that Maya won't rename for global uniqueness, only local - so if you want to make unique node name for things that are not siblings you have to do it yourself.
Here's some cheapie code for finding unique node names:
def get_unique_scene_names (*nodeTypes):
if not nodeTypes:
nodeTypes = ('transform',)
results = {}
for longname in cmds.ls(type = nodeTypes, l=True):
shortname = longname.rpartition("|")[-1]
if not shortname in results:
results[shortname] = set()
results[shortname].add(longname)
return results
def add_unique_name(item, node_dict):
shortname = item.rpartition("|")[-1]
if shortname in node_dict:
node_dict[shortname].add(item)
else:
node_dict[shortname] = set([item])
def remove_unique_name(item, node_dict):
shortname = item.rpartition("|")[-1]
existing = node_dict.get(shortname, [])
if item in existing:
existing.remove(item)
def apply_convention(node, new_name, node_dict):
if not new_name in node_dict:
renamed_item = cmds.ls(cmds.rename(node, new_name), l=True)[0]
remove_unique_name(node, node_dict)
add_unique_name ( renamed_item, node_dict)
return renamed_item
else:
for n in range(99999):
possible_name = new_name + str(n + 1)
if not possible_name in node_dict:
renamed_item = cmds.ls(cmds.rename(node, possible_name), l=True)[0]
add_unique_name(renamed_item, node_dict)
return renamed_item
raise RuntimeError, "Too many duplicate names"
To use it on a particular node type, you just supply the right would-be name when calling apply_convention(). This would rename all the joints in the scene (naively!) to 'jnt_X' while keeping the suffixes unique. You'd do something smarter than that, like your original code did - this just makes sure that leaves are unique:
joint_names= get_unique_scene_names('joint')
existing = cmds.ls( type='joint', l = True)
existing .sort()
existing .reverse()
# do this to make sure it works from leaves backwards!
for item in existing :
apply_convention(item, 'jnt_', joint_names)
# check the uniqueness constraint by looking for how many items share a short name in the dict:
for d in joint_names:
print d, len (joint_names[d])
But, like i said, plan for those damn numeric suffixes, maya makes them all the time without asking for permission so you can't fight em :(
Instead of running ls for each and every name, you should run it once and store that result into a set (an unordered list - slightly faster). Then check against that when you run check_scene
def check_scene(self, name):
"""Checks entire scene for same name. If duplicate exists,
Keyword Arguments:
name -- (string) name of object to be checked
"""
if not hasattr(self, 'scene'):
self.scene = set(ls())
if name not in self.scene:
return name
else:
return ''
I'm new at Python, but I tried something and it was ambiguous for me.
Why Python allows doing def of function inside a loop ? and how I can benefit from that ?
for i in range(2):
def f():
print 'f'
f()
Well because python is a high level programming language, you can actually return functions. The following a simple yet demonstrative function.
def multiplier(multiple):
def f(number):
return multiple * number
return f
you can use that function as follows:
double = multiplier(2)
print double(3)
which would print 6.
Same concept would apply for loops if you want to make multiple functions for example and store them in a list or any other purpose befitting your needs.
list_of_functions = [] #list of functions
for i in range(2):
def f(n):
def printer():
print "f"*n
return printer
list_of_functions.append(f(i+1))
Now you can call list_of_functions[0]() which would print 'f' and list_of_functions[1]() which would print 'ff'.
You can define functions anywhere! Because Python is dynamic in this way, you can create functions (and classes, and pretty much anything else) at runtime. It's difficult to come up with a simple example of why you'd want to do this without it seeming contrived, but use cases certainly do exist.
Let's say you're writing a simple processing framework. You'll allow users to type commands, which will cause certain functions to run. You can define those functions first, and then store them all in a dictionary, so that you can quickly look up the appropriate function to run when you get the user's input.
def define_functions(letters):
commands = {} # dictionary of commands
for letter in letters:
# Define functions dynamically
if letter == 'f':
def _function():
print('foo')
elif letter == 'b':
def _function():
print('bar')
elif letter == 'z':
def _function():
print('baz')
else:
def _function():
print('Unknown command')
# Add the new function to the dictionary with the key "n squared"
commands[letter] = _function
return commands
commands = define_functions('abcdefghijklmnopqrstuvwxyz')
# Now we have a dictionary of functions.
while True: # loop forever
# Ask for input and run the specified function!
func_name = raw_input('Enter the one-letter name of the function to run: ')
if func_name not in commands:
print("sorry, that function isn't defined.")
break
# Look up the function
func = commands.get(func_name)
# Call the function
func()
I've been using ScalaTest's FeatureSpec for a couple of days now and I'm trying to understand if it's possible to define the following spec using the built-in matchers (and if not, how I can write a suitable custom matcher).
Suppose I have the class Book:
case class Book(val title: String, val author: String)
and in my test I have a List of books:
val books = List(Book("Moby Dick", "Melville"))
Now, I would like to specify that the books list should contain a book with the title "Moby Dick". I would like to write something like:
books should contain (value with title "Moby Dick")
I can't seem to figure out from the docs and code if it's possible to express this requirement in ScalaTest. Has anyone ran into a similar situation?
In the meantime here's a custom matcher you can use:
def containElement[T](right: Matcher[T]) = new Matcher[Seq[T]] {
def apply(left: Seq[T]) = {
val matchResults = left map right
MatchResult(
matchResults.find(_.matches) != None,
matchResults.map(_.failureMessage).mkString(" and "),
matchResults.map(_.negatedFailureMessage).mkString(" and ")
)
}
}
Then you can use the full power of the ScalaTest Have matcher to inspect the fields of your object:
val books = List(Book("Moby Dick", "Melville"),
Book("Billy Budd", "Melville"),
Book("War and Peace", "Tolstoy"))
books should containElement(have('title("Moby Dick")))
books should containElement(have('title("Billy Budd"), 'author("Melville")))
books should containElement(have('title("War and Peace"), 'author("Melville")))
The last one is a failure producing this output:
The title property had value "Moby Dick", instead of its expected value "War and Peace", on object Book(Moby Dick,Melville) and The title property had value "Billy Budd", instead of its expected value "War and Peace", on object Book(Billy Budd,Melville) and The author property had value "Tolstoy", instead of its expected value "Melville", on object Book(War and Peace,Tolstoy)
You can also combine matchers with and or or, use not, etc.
Not currently, though you will be able to do something like this very soon in the future. What you can do now is something like:
books.exists(_.title == "Moby Dick") should be (true)