I want to:
So for an object of class
class Person(object):
name = ""
age = 0
major = ""
def __init__(self, name="", surname="", father="", age =0):
self.name = name
self.surname = surname
self.father = father
self.age = age
self.identity = name +" "+ surname
def __str__(self):
return self.identity
__repr__ = __str__
and object
person = Person("Earl", "Martin", "Jason", 40)
I would like for string "What is the name" to return person.name (I already know which object the string is about)
The most basic solution would be to do cases for each property being there but the actual code has quite a few and I am sure I don't manually have to write them out, I am just new to programming so I am not sure what syntax is used for this
Any help appreciated
You are looking for the function hasattr() and getattr().
To check whether the attribute exists:
hasattr(Person(), 'string')
And to call the attribute:
getattr(Person(), 'string')
As others have noted, getattr is generally useful.
hasattr is of lesser utility; internally, it's basically a getattr call in a try/except AttributeError: block (if AttributeError occurs, it returns False, no exception means True), so if you're considering code like:
if hasattr(myobj, attrname):
attr = getattr(myobj, attrname)
...
just use:
try:
attr = getattr(myobj, attrname)
except AttributeError:
pass
else:
...
to avoid doubling the number of LEGB lookups, function calls and attribute lookups.
Alternatively, for repeatedly pulling named attribute(s), operator.attrgetter basically lets you make an optimized version of getattr that pre-binds the attribute name to lookup (making it ideal for use with stuff like the map and filter functions, as it makes them more efficient than their equivalent listcomps/genexprs).
On top of those, depending on what your goal is, the dir and (slightly less reliably, due to issues with classes that use __slots__ to define a known set of variables to reduce memory usage and prevent auto-vivification) vars functions may be useful.
For example, in your example case of pulling any attributes corresponding to a word from a string, you could do a bulk identification of legal attribute names using vars()/dir() and your choice of filter or set operations (or a mix) depending on the importance of order, uniqueness, etc.:
from future_builtins import filter # Only on Py2, not Py3
import operator
import re
def query_obj(obj, querystr):
# Extract list of legal attribute names from string
words = re.findall(r'\w+', querystr)
# Reduce to names present on object's __dict__; no need to construct temporaries
attrnames = filter(vars(obj).__contains__, words)
# Alternate if __slots__ might be an issue (temp list & frozenset):
attrnames = filter(frozenset(dir(obj)).__contains__, words)
# Or combine the two to be sure (on Py3, use .keys() instead of .viewkeys())
# (temp list and set):
attrnames = filter((vars(obj).viewkeys() | dir(obj)).__contains__, words)
# Convenient way to get all names discovered at once; returns single object
# for single attr, tuple of objects for multiple attrs:
return operator.attrgetter(*attrnames)(obj)
# If you want a tuple unconditionally, use this instead:
return tuple(getattr(obj, name) for name in attrnames)
# Or to only return the first attribute encountered, raising StopIteration
# if no attributes are found:
return next(getattr(obj, name) for name in attrnames)
Then usage is:
>>> person = Person("Earl", "Martin", "Jason", 40)
>>> query_obj(person, "What is the name?")
'Earl' # Would be ('Earl',) in unconditional tuple case
>>> query_obj(person, "What is the name and surname?")
('Earl', 'Martin') # Would be 'Earl' in single return case
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With