How to set a property of a property by name in python? - python

I have a piece of code where I have an object B that has another object A as a property, and I would like the user to be able to set the properties of either object by name. How can I let the user set attributes of either A or B?
The following code illustrates what I am trying to do:
>>> class A:
... def __init__(self):
... self.asd = 123
>>> class B:
... def __init__(self, a):
... self.a = a
>>> a=A()
>>> b=B(a)
>>> b.a.asd
123
>>> setattr(b, 'a.asd', 1000)
>>> b.a.asd
123 # I would like this to be 1000
I would like to only prompt the user for the property name and value.
I am prompting the user with this code:
prop = input("Property name to set: ")
try:
print(f"Current value of property {prop}: {getattr(B, prop)}")
value = input("Property value to set: ")
setattr(B, prop, value)
except AttributeError:
print(f"Object {B} has no property named {prop}. See {dir(B)}")
Edit: question solved, but I cannot accept my own answer for 2 days

setattr(getattr(b, 'a'), 'asd', 1000)

There is no way to traverse objects using the property name in setattr(). So to simulate this behaviour, you can split the property name on . and use getattr() to select the object you want to set the property on. This way, you only need to prompt the user for the property name and value.
prop = input("Property name to set: ")
obj_to_set = B
try:
for i in prop.split(".")[:-1]:
obj_to_set = getattr(obj_to_set, i)
prop_name = prop.split(".")[-1]
print(f"Current value of property {prop_name}: {getattr(obj_to_set, prop_name)}")
value = input("Property value to set: ")
setattr(obj_to_set, prop_name, value)
except AttributeError:
print(f"Object {obj_to_set} has no property named {prop}. See {dir(obj_to_set)}")

Related

Python3 script using SQLAlchemy returns object address vice string [duplicate]

I have a function below which I want to output lines of values relating to 'O', instead it prints the location of these values, how do I amend this? allReactions is an empty array initially. I've tried a number of ways to get around this but keep getting errors. Also I think my methods are less efficient than can be.
allReactions = []
reactionFile = "/Databases/reactionsDatabase.txt"
with open(reactionFile) as sourceFile:
for line in sourceFile:
if line[0] == "!" or len(line.strip()) == 0: continue
allReactions.append(Reaction(line, sourceType="Unified Data"))
def find_allReactions(allReactions, reactant_set):
reactant_set = set(reactant_set)
relevant_reactions = []
previous_reactant_count = None
while len(reactant_set) != previous_reactant_count:
previous_reactant_count = len(reactant_set)
for reaction in allReactions:
if set(reaction.reactants).issubset(reactant_set):
relevant_reactions.append(reaction)
reactant_set = reactant_set.union(set(reaction.products))
return relevant_reactions
print find_allReactions(allReactions, ["O"])
You are trying to print a list of Reaction objects. By default, python prints a class object's ID because it really doesn't have much to say about it. If you have control over the class definition, you can change that by adding __str__ and __repr__ method to the class.
>>> class C(object):
... pass
...
>>> print C()
<__main__.C object at 0x7fbe3af3f9d0>
>>> class C(object):
... def __str__(self):
... return "A C Object"
...
>>> print C()
A C Object
>>>
If you don't have control of the class... well, the author didn't implement a pretty view of the class. You could create subclasses with the methods or write a function to pull out the stuff you want.

How to retrieve a class object inside the dictionary in python?

I have added a employee class object inside a dictionary successfully .But i am not able to get back the value from the same dictionary? Below are the code and output.
source code:
# decalre a dict
employee_collection = {}
# Class object to store employee's details
class employee:
# Constructor
def __init__(self,name,age):
self.name = name
self.age = age
# Display the object values
def print_property(self):
print(f"name is {self.name} and age is {str(self.age)}")
# loop to add multiple employee details
for x in range(1, 6):
obj= employee("xxx", 28+x)
employee_collection.update({x : obj})
# extract the employee detail from and print the vaue to user
for x in employee_collection:
# print(x.name)
print(x)
print(employee_collection)
output :
1
2
3
4
5
{1: <__main__.employee object at 0x0327F610>, 2: <__main__.employee object at 0x03550C70>, 3: <__main__.employee object at 0x03550580>, 4: <__main__.employee object at 0x035503B8>, 5: <__main__.employee object at 0x03550FB8>}
My question is:
How to print the name and age using loop in main method?
Two methods. The dict is storing the instance of each employee (which should be Employee btw).
You can either print the properties of the instance, or change what happens when you try to print an object.
The former:
for key, e in employee_collection.items():
print(f'{x} {e.name} {e.age}')
The latter:
class Employee:
...
def __str__(self):
return f'{self.name} {self.age}'
for e in employee_collection.values():
print(e)
To iterate through a dictionary you can use its keys(), values() or items(). Since you want both the key (x) and the value (employee) you want to use items() which returns all dictionary key-value pairs as so-called tuple in a list:
for x, employee in employee_collection.items():
print(f'Number: {x}, Name: {employee.name}, age: {employee.age}') # this is printing a format-string

Where attribute does not exist, create an attribute and give it a default value

I am learning Python out of a book and have written myself a long quiz/type game which prints a summary at the end. However, the summary looks for attributes that will not always exist depending on what choices have been made by the user.
I have abstracted this into a basic example to show what I am trying to do. Essentially, I just want to run an attribute error check, for every variable that does not have an attribute, create an attribute with a default value of N/A.
In the below example, I would want it to print:
Forename: Joe
Surname: Bloggs
Smith Test: N/A
Test 4: N/A
I created a class called CodeCleaner which I was going to use to set the N/A values, but got very stuck!
class QuestionSet(object):
next_set = 'first_set'
class ClaimEngine(QuestionSet):
def current_set(self):
last_set = "blank"
while_count = int(0)
quizset = Sets.subsets
ParentSet = QuestionSet()
while ParentSet.next_set != last_set and int(while_count)<50:
quizset[ParentSet.next_set].questioning()
while_count = while_count+1
class FirstSet(QuestionSet):
def questioning(self):
self.value1 = raw_input("Forename:\n")
QuestionSet.next_set = "second_set"
class SecondSet(QuestionSet):
def questioning(self):
self.value2 = raw_input("Surname:\n")
if self.value2 == "Smith":
self.value3 = "He's a Smith!"
self.value4 = "Test val 4"
QuestionSet.next_set = "summary"
else:
QuestionSet.next_set = "summary"
class CodeCleaner(QuestionSet):
def questioning(self):
mapping = Sets()
sets = mapping.subsets
variable_list = {
[sets['first_set']].value1,
[sets['second_set']].value2,
[sets['second_set']].value3,
[sets['second_set']].value4
}
#while key_no < 4:
# try:
# print variable_list
# except AttributeError:
class Summary(QuestionSet):
def questioning(self):
mapping = Sets()
sets = mapping.subsets
print "Forename:",sets['first_set'].value1
print "Surname:",sets['second_set'].value2
print "Smith Test:",sets['second_set'].value3
print "Test 4:",sets['second_set'].value4
exit(0)
class Sets(object):
subsets = {
'first_set': FirstSet(),
'second_set': SecondSet(),
'summary': Summary()
}
run = ClaimEngine()
run.current_set()
I feel quite lazy asking this question, however, I've been wrestling with this for a few days now! Any help would be appreciated.
I'm not sure I go exactly your approach, but you can implement a __getattr__ method in an object that would be called when the attribute is not found:
class A(object):
def __getattr__(self, name):
print("Creating attribute %s."%name)
setattr(self, name, 'N/A')
Then:
>>> a = A()
>>> a.a
Creating attribute a.
>>> a.a
'N/A'

How to extract string values into object fields

I have this dictionary:
{"id":3,"name":"MySQL","description":"MySQL Database Server - Fedora 21 - medium","image":"","flavor":""}
And I have this object:
class Record():
id = None
name = None
description = None
image = None
flavor = None
How can I assign values from the dictionary to their corresponding class fields?
Take a dict object as the parameter of init function:
class Record(object):
def __init__(self,record_dict):
try:
self.id = record_dict['id']
self.name = record_dict['name']
self.description = record_dict['description']
self.image = record_dict['image']
self.flavor = record_dict['flavor']
except KeyError:
print 'KeyError'
def get_name(self):
return self.name
adict = {"id":3,"name":"MySQL","description":"MySQL Database Server - Fedora 21 - medium","image":"","flavor":""}
one_obj = Record(adict)
print one_obj
print one_obj.get_name()
output:
<__main__.Record object at 0x022E4C90>
MySQL
works for me...
You probably want something like this:
class Record:
def __init__(self, myDict):
self.id = myDict[“id”]
self.name = myDict[“name”]
self.description = myDict[“description”]
self.image = myDict[“image”]
self.flavor = myDict[“flavor”]
And call it:
rec = Record(myDict)
See here to understand the difference between class and instance variables.
Long story short, class variables have a single value for every instance of the class while instance variables values are unique to each instance.
A class variable is defined like this:
class myClass:
Classvar = ‘something’
An instance variable is defined like this:
class myClass:
def __init__():
Self.instanceVar = ‘something else’
This has already been answered here:
Convert Python dict to object?
My favorite method is this one: x.__dict__.update(d)
You can assign them as follows, assuming your dictionary name is input
id = input['id']
name = input['name']
description = input['description']
image = input['image']
flavor = input['flavor']
Try this method in which you grab the attributes of the object:
r = Record()
attributes = [i for i in dir(r) if not i.startswith('_')]
Basically, there are a bunch of background attributes that contain a bunch of underscores. The dir method gets all the attributes and we create a list of the ones that we want. At this point:
# attributes = ['count', 'description', 'flavor', 'id', 'image', 'index', 'name']
So now we use __setattr__ to set the attributes we just grabbed according to the my_dict
for i in attributes:
r.__setattr__(i, my_dict[i])
See the code run online here.
When you create the Record, pass in the dictionary. Then map the key to the value.
Another simple method, see the code here
r = Record()
for k, v in my_dict.items():
exec('r.' + k + '="' + str(v) + '"')

Is there a better way to get a named series of constants (enumeration) in Python? [duplicate]

This question already has answers here:
How can I represent an 'Enum' in Python?
(43 answers)
Closed 9 years ago.
Just looking at ways of getting named constants in python.
class constant_list:
(A_CONSTANT, B_CONSTANT, C_CONSTANT) = range(3)
Then of course you can refer to it like so:
constant_list.A_CONSTANT
I suppose you could use a dictionary, using strings:
constant_dic = {
"A_CONSTANT" : 1,
"B_CONSTANT" : 2,
"C_CONSTANT" : 3,}
and refer to it like this:
constant_dic["A_CONSTANT"]
My question, then, is simple. Is there any better ways of doing this? Not saying that these are inadequate or anything, just curious - any other common idioms that I've missed?
Thanks in advance.
For 2.3 or after:
class Enumerate(object):
def __init__(self, names):
for number, name in enumerate(names.split()):
setattr(self, name, number)
To use:
codes = Enumerate('FOO BAR BAZ')
codes.BAZ will be 2 and so on.
If you only have 2.2, precede this with:
from __future__ import generators
def enumerate(iterable):
number = 0
for name in iterable:
yield number, name
number += 1
(This was taken from here)
I find the enumeration class recipe (Active State, Python Cookbook) to be very effective.
Plus it has a lookup function which is nice.
Pev
An alternative construction for constant_dic:
constants = ["A_CONSTANT", "B_CONSTANT", "C_CONSTANT"]
constant_dic = dict([(c,i) for i, c in enumerate(constants)])
The following acts like a classisc "written in stone" C enum -- once defined, you can't change it, you can only read its values. Neither can you instantiate it. All you have to do is "import enum.py" and derive from class Enum.
# this is enum.py
class EnumException( Exception ):
pass
class Enum( object ):
class __metaclass__( type ):
def __setattr__( cls, name, value ):
raise EnumException("Can't set Enum class attribute!")
def __delattr__( cls, name ):
raise EnumException("Can't delete Enum class attribute!")
def __init__( self ):
raise EnumException("Enum cannot be instantiated!")
This is the test code:
# this is testenum.py
from enum import *
class ExampleEnum( Enum ):
A=1
B=22
C=333
if __name__ == '__main__' :
print "ExampleEnum.A |%s|" % ExampleEnum.A
print "ExampleEnum.B |%s|" % ExampleEnum.B
print "ExampleEnum.C |%s|" % ExampleEnum.C
z = ExampleEnum.A
if z == ExampleEnum.A:
print "z is A"
try:
ExampleEnum.A = 4
print "ExampleEnum.A |%s| FAIL!" % ExampleEnum.A
except EnumException:
print "Can't change Enum.A (pass...)"
try:
del ExampleEnum.A
except EnumException:
print "Can't delete Enum.A (pass...)"
try:
bad = ExampleEnum()
except EnumException:
print "Can't instantiate Enum (pass...)"
This is the best one I have seen: "First Class Enums in Python"
http://code.activestate.com/recipes/413486/
It gives you a class, and the class contains all the enums. The enums can be compared to each other, but don't have any particular value; you can't use them as an integer value. (I resisted this at first because I am used to C enums, which are integer values. But if you can't use it as an integer, you can't use it as an integer by mistake so overall I think it is a win.) Each enum is a unique object. You can print enums, you can iterate over them, you can test that an enum value is "in" the enum. It's pretty complete and slick.
In Python, strings are immutable and so they are better for constants than numbers. The best approach, in my opinion, is to make an object that keeps constants as strings:
class Enumeration(object):
def __init__(self, possibilities):
self.possibilities = set(possibilities.split())
def all(self):
return sorted(self.possibilities)
def __getattr__(self, name):
if name in self.possibilities:
return name
raise AttributeError("Invalid constant: %s" % name)
You could then use it like this:
>>> enum = Enumeration("FOO BAR")
>>> print enum.all()
['BAR', 'FOO']
>>> print enum.FOO
FOO
>>> print enum.FOOBAR
Traceback (most recent call last):
File "enum.py", line 17, in <module>
print enum.FOOBAR
File "enum.py", line 11, in __getattr__
raise AttributeError("Invalid constant: %s" % name)
AttributeError: Invalid constant: FOOBAR

Categories

Resources