Getting a object stored in a dict by a string key - python

I successfully print a list of keys to the screen and then ask the user to type in a key name to get a specific object. This is the way i thought it worked:
print dict['bob']
and this would output the object stored with the 'bob' key however it does not. I'm assuming this problem arises because im storing objects and not strings or ints. If the name entered is a key it just prints the name again not the object and if it isn't a key it throws an error. The end result of this is to get a specified object so the user can view that objects attributes.
When the above statement is ran it just prints the key to the screen:
bob
printing my dictionary looks like this
{'Sal': <Employ_Class2.Employee object at 0x01EE38F0>, 'bob': <Emplo
y_Class2.Employee object at 0x01EE3930>, 'jack': <Employ_Class2.Employee o
bject at 0x01EE3990>, 'alexa': <Employ_Class2.Employee object at 0x01EE3870>,
'dave': <Employ_Class2.Employee object at 0x01EE3910>, 'sew
': <Employ_Class2.Employee object at 0x01EE3950>, 'tam': <Employ_Class2.Em
ployee object at 0x01EE39D0>}

It looks like you're simply being misled by the fact that print obj prints the result of calling the object's __str__ or __unicode__ methods. So, the object in the dictionary under the key "bob", when converted to string, is simply "bob".
As others have said, if you simply want to print the attributes of the object under that key, use dir:
obj = dict['bob']
print dir(obj)

If you want to view the names of the attributes of the object, use dir().
If the dictionary contains the instances of the class you've created and you want to extract relevant information from those objects, you need to create in your class a function which does that and invoke it later.
Suppose you have an object of type Product, given that Product is the class you've created. You store multiple products in your dictionary. What do you want to get back? The name of the product? The name, the price and the description? Or maybe the class name? Python won't be able to figure out your intention, so it's up to you to either create a specific method which does what you want it to do, or use __str__().

I think what you wanted is dir([object]) .
Without arguments, return the list of names in the current local scope. With an argument, attempt to return a list of valid attributes for that object.
So according to the documentation you can have the attributes fro that object with dir().
Hope this is what you have wanted..

Not sure if you are referring to object attributes you are defining in your class definition or the names you would find with dir(). In either case, if your object class has a __str__ or __repr__ methods defined, those will be called when using print. If you want a user to be able to view the names in the object space, just use dir(). If you want them to access attributes and properties you set in the class definition, access them directly (or through whatever methods you created to do so:
class Test:
attr = 'item' # this is a class attribute
def __init__(self):
self.name = 'Me' # this will be an instance variable/property
def __str__(self):
return self.name
d = {} # example does not need a dict but using one to relate to posted question
d['item'] = Test()
print(d['item'])
results in self.name being printed to screen:
dir(d['item']) will instead print out all of the names in the object namespace, including methods and attributes.
To print your created attributes (attr and self.name above), then you can simply do:
print(d['item'].attr)
print(d['item'].name)
So, in that case, your users should just access the dict objects directly: dict['bob'].attribute
Hope that makes some sense.

Related

What is the difference between assign and declare a variable in python? [duplicate]

I want to clarify how variables are declared in Python.
I have seen variable declaration as
class writer:
path = ""
sometimes, there is no explicit declaration but just initialization using __init__:
def __init__(self, name):
self.name = name
I understand the purpose of __init__, but is it advisable to declare variable in any other functions?
How can I create a variable to hold a custom type?
class writer:
path = "" # string value
customObj = ??
Okay, first things first.
There is no such thing as "variable declaration" or "variable initialization" in Python.
There is simply what we call "assignment", but should probably just call "naming".
Assignment means "this name on the left-hand side now refers to the result of evaluating the right-hand side, regardless of what it referred to before (if anything)".
foo = 'bar' # the name 'foo' is now a name for the string 'bar'
foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar',
# and starts being a name for the integer 6, resulting from the multiplication
As such, Python's names (a better term than "variables", arguably) don't have associated types; the values do. You can re-apply the same name to anything regardless of its type, but the thing still has behaviour that's dependent upon its type. The name is simply a way to refer to the value (object). This answers your second question: You don't create variables to hold a custom type. You don't create variables to hold any particular type. You don't "create" variables at all. You give names to objects.
Second point: Python follows a very simple rule when it comes to classes, that is actually much more consistent than what languages like Java, C++ and C# do: everything declared inside the class block is part of the class. So, functions (def) written here are methods, i.e. part of the class object (not stored on a per-instance basis), just like in Java, C++ and C#; but other names here are also part of the class. Again, the names are just names, and they don't have associated types, and functions are objects too in Python. Thus:
class Example:
data = 42
def method(self): pass
Classes are objects too, in Python.
So now we have created an object named Example, which represents the class of all things that are Examples. This object has two user-supplied attributes (In C++, "members"; in C#, "fields or properties or methods"; in Java, "fields or methods"). One of them is named data, and it stores the integer value 42. The other is named method, and it stores a function object. (There are several more attributes that Python adds automatically.)
These attributes still aren't really part of the object, though. Fundamentally, an object is just a bundle of more names (the attribute names), until you get down to things that can't be divided up any more. Thus, values can be shared between different instances of a class, or even between objects of different classes, if you deliberately set that up.
Let's create an instance:
x = Example()
Now we have a separate object named x, which is an instance of Example. The data and method are not actually part of the object, but we can still look them up via x because of some magic that Python does behind the scenes. When we look up method, in particular, we will instead get a "bound method" (when we call it, x gets passed automatically as the self parameter, which cannot happen if we look up Example.method directly).
What happens when we try to use x.data?
When we examine it, it's looked up in the object first. If it's not found in the object, Python looks in the class.
However, when we assign to x.data, Python will create an attribute on the object. It will not replace the class' attribute.
This allows us to do object initialization. Python will automatically call the class' __init__ method on new instances when they are created, if present. In this method, we can simply assign to attributes to set initial values for that attribute on each object:
class Example:
name = "Ignored"
def __init__(self, name):
self.name = name
# rest as before
Now we must specify a name when we create an Example, and each instance has its own name. Python will ignore the class attribute Example.name whenever we look up the .name of an instance, because the instance's attribute will be found first.
One last caveat: modification (mutation) and assignment are different things!
In Python, strings are immutable. They cannot be modified. When you do:
a = 'hi '
b = a
a += 'mom'
You do not change the original 'hi ' string. That is impossible in Python. Instead, you create a new string 'hi mom', and cause a to stop being a name for 'hi ', and start being a name for 'hi mom' instead. We made b a name for 'hi ' as well, and after re-applying the a name, b is still a name for 'hi ', because 'hi ' still exists and has not been changed.
But lists can be changed:
a = [1, 2, 3]
b = a
a += [4]
Now b is [1, 2, 3, 4] as well, because we made b a name for the same thing that a named, and then we changed that thing. We did not create a new list for a to name, because Python simply treats += differently for lists.
This matters for objects because if you had a list as a class attribute, and used an instance to modify the list, then the change would be "seen" in all other instances. This is because (a) the data is actually part of the class object, and not any instance object; (b) because you were modifying the list and not doing a simple assignment, you did not create a new instance attribute hiding the class attribute.
This might be 6 years late, but in Python 3.5 and above, you can give a hint about a variable type like this:
variable_name: type_name
or this:
variable_name # type: shinyType
This hint has no effect in the core Python interpreter, but many tools will use it to aid the programmer in writing correct code.
So in your case(if you have a CustomObject class defined), you can do:
customObj: CustomObject
See this or that for more info.
There's no need to declare new variables in Python. If we're talking about variables in functions or modules, no declaration is needed. Just assign a value to a name where you need it: mymagic = "Magic". Variables in Python can hold values of any type, and you can't restrict that.
Your question specifically asks about classes, objects and instance variables though. The idiomatic way to create instance variables is in the __init__ method and nowhere else — while you could create new instance variables in other methods, or even in unrelated code, it's just a bad idea. It'll make your code hard to reason about or to maintain.
So for example:
class Thing(object):
def __init__(self, magic):
self.magic = magic
Easy. Now instances of this class have a magic attribute:
thingo = Thing("More magic")
# thingo.magic is now "More magic"
Creating variables in the namespace of the class itself leads to different behaviour altogether. It is functionally different, and you should only do it if you have a specific reason to. For example:
class Thing(object):
magic = "Magic"
def __init__(self):
pass
Now try:
thingo = Thing()
Thing.magic = 1
# thingo.magic is now 1
Or:
class Thing(object):
magic = ["More", "magic"]
def __init__(self):
pass
thing1 = Thing()
thing2 = Thing()
thing1.magic.append("here")
# thing1.magic AND thing2.magic is now ["More", "magic", "here"]
This is because the namespace of the class itself is different to the namespace of the objects created from it. I'll leave it to you to research that a bit more.
The take-home message is that idiomatic Python is to (a) initialise object attributes in your __init__ method, and (b) document the behaviour of your class as needed. You don't need to go to the trouble of full-blown Sphinx-level documentation for everything you ever write, but at least some comments about whatever details you or someone else might need to pick it up.
For scoping purpose, I use:
custom_object = None
Variables have scope, so yes it is appropriate to have variables that are specific to your function. You don't always have to be explicit about their definition; usually you can just use them. Only if you want to do something specific to the type of the variable, like append for a list, do you need to define them before you start using them. Typical example of this.
list = []
for i in stuff:
list.append(i)
By the way, this is not really a good way to setup the list. It would be better to say:
list = [i for i in stuff] # list comprehension
...but I digress.
Your other question.
The custom object should be a class itself.
class CustomObject(): # always capitalize the class name...this is not syntax, just style.
pass
customObj = CustomObject()
As of Python 3, you can explicitly declare variables by type.
For instance, to declare an integer one can do it as follows:
x: int = 3
or:
def f(x: int):
return x
see this question for more detailed info about it:
Explicitly declaring a variable type in Python

Can I declare a variable firmly typed as an integer in Python, like I do in Java? [duplicate]

I want to clarify how variables are declared in Python.
I have seen variable declaration as
class writer:
path = ""
sometimes, there is no explicit declaration but just initialization using __init__:
def __init__(self, name):
self.name = name
I understand the purpose of __init__, but is it advisable to declare variable in any other functions?
How can I create a variable to hold a custom type?
class writer:
path = "" # string value
customObj = ??
Okay, first things first.
There is no such thing as "variable declaration" or "variable initialization" in Python.
There is simply what we call "assignment", but should probably just call "naming".
Assignment means "this name on the left-hand side now refers to the result of evaluating the right-hand side, regardless of what it referred to before (if anything)".
foo = 'bar' # the name 'foo' is now a name for the string 'bar'
foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar',
# and starts being a name for the integer 6, resulting from the multiplication
As such, Python's names (a better term than "variables", arguably) don't have associated types; the values do. You can re-apply the same name to anything regardless of its type, but the thing still has behaviour that's dependent upon its type. The name is simply a way to refer to the value (object). This answers your second question: You don't create variables to hold a custom type. You don't create variables to hold any particular type. You don't "create" variables at all. You give names to objects.
Second point: Python follows a very simple rule when it comes to classes, that is actually much more consistent than what languages like Java, C++ and C# do: everything declared inside the class block is part of the class. So, functions (def) written here are methods, i.e. part of the class object (not stored on a per-instance basis), just like in Java, C++ and C#; but other names here are also part of the class. Again, the names are just names, and they don't have associated types, and functions are objects too in Python. Thus:
class Example:
data = 42
def method(self): pass
Classes are objects too, in Python.
So now we have created an object named Example, which represents the class of all things that are Examples. This object has two user-supplied attributes (In C++, "members"; in C#, "fields or properties or methods"; in Java, "fields or methods"). One of them is named data, and it stores the integer value 42. The other is named method, and it stores a function object. (There are several more attributes that Python adds automatically.)
These attributes still aren't really part of the object, though. Fundamentally, an object is just a bundle of more names (the attribute names), until you get down to things that can't be divided up any more. Thus, values can be shared between different instances of a class, or even between objects of different classes, if you deliberately set that up.
Let's create an instance:
x = Example()
Now we have a separate object named x, which is an instance of Example. The data and method are not actually part of the object, but we can still look them up via x because of some magic that Python does behind the scenes. When we look up method, in particular, we will instead get a "bound method" (when we call it, x gets passed automatically as the self parameter, which cannot happen if we look up Example.method directly).
What happens when we try to use x.data?
When we examine it, it's looked up in the object first. If it's not found in the object, Python looks in the class.
However, when we assign to x.data, Python will create an attribute on the object. It will not replace the class' attribute.
This allows us to do object initialization. Python will automatically call the class' __init__ method on new instances when they are created, if present. In this method, we can simply assign to attributes to set initial values for that attribute on each object:
class Example:
name = "Ignored"
def __init__(self, name):
self.name = name
# rest as before
Now we must specify a name when we create an Example, and each instance has its own name. Python will ignore the class attribute Example.name whenever we look up the .name of an instance, because the instance's attribute will be found first.
One last caveat: modification (mutation) and assignment are different things!
In Python, strings are immutable. They cannot be modified. When you do:
a = 'hi '
b = a
a += 'mom'
You do not change the original 'hi ' string. That is impossible in Python. Instead, you create a new string 'hi mom', and cause a to stop being a name for 'hi ', and start being a name for 'hi mom' instead. We made b a name for 'hi ' as well, and after re-applying the a name, b is still a name for 'hi ', because 'hi ' still exists and has not been changed.
But lists can be changed:
a = [1, 2, 3]
b = a
a += [4]
Now b is [1, 2, 3, 4] as well, because we made b a name for the same thing that a named, and then we changed that thing. We did not create a new list for a to name, because Python simply treats += differently for lists.
This matters for objects because if you had a list as a class attribute, and used an instance to modify the list, then the change would be "seen" in all other instances. This is because (a) the data is actually part of the class object, and not any instance object; (b) because you were modifying the list and not doing a simple assignment, you did not create a new instance attribute hiding the class attribute.
This might be 6 years late, but in Python 3.5 and above, you can give a hint about a variable type like this:
variable_name: type_name
or this:
variable_name # type: shinyType
This hint has no effect in the core Python interpreter, but many tools will use it to aid the programmer in writing correct code.
So in your case(if you have a CustomObject class defined), you can do:
customObj: CustomObject
See this or that for more info.
There's no need to declare new variables in Python. If we're talking about variables in functions or modules, no declaration is needed. Just assign a value to a name where you need it: mymagic = "Magic". Variables in Python can hold values of any type, and you can't restrict that.
Your question specifically asks about classes, objects and instance variables though. The idiomatic way to create instance variables is in the __init__ method and nowhere else — while you could create new instance variables in other methods, or even in unrelated code, it's just a bad idea. It'll make your code hard to reason about or to maintain.
So for example:
class Thing(object):
def __init__(self, magic):
self.magic = magic
Easy. Now instances of this class have a magic attribute:
thingo = Thing("More magic")
# thingo.magic is now "More magic"
Creating variables in the namespace of the class itself leads to different behaviour altogether. It is functionally different, and you should only do it if you have a specific reason to. For example:
class Thing(object):
magic = "Magic"
def __init__(self):
pass
Now try:
thingo = Thing()
Thing.magic = 1
# thingo.magic is now 1
Or:
class Thing(object):
magic = ["More", "magic"]
def __init__(self):
pass
thing1 = Thing()
thing2 = Thing()
thing1.magic.append("here")
# thing1.magic AND thing2.magic is now ["More", "magic", "here"]
This is because the namespace of the class itself is different to the namespace of the objects created from it. I'll leave it to you to research that a bit more.
The take-home message is that idiomatic Python is to (a) initialise object attributes in your __init__ method, and (b) document the behaviour of your class as needed. You don't need to go to the trouble of full-blown Sphinx-level documentation for everything you ever write, but at least some comments about whatever details you or someone else might need to pick it up.
For scoping purpose, I use:
custom_object = None
Variables have scope, so yes it is appropriate to have variables that are specific to your function. You don't always have to be explicit about their definition; usually you can just use them. Only if you want to do something specific to the type of the variable, like append for a list, do you need to define them before you start using them. Typical example of this.
list = []
for i in stuff:
list.append(i)
By the way, this is not really a good way to setup the list. It would be better to say:
list = [i for i in stuff] # list comprehension
...but I digress.
Your other question.
The custom object should be a class itself.
class CustomObject(): # always capitalize the class name...this is not syntax, just style.
pass
customObj = CustomObject()
As of Python 3, you can explicitly declare variables by type.
For instance, to declare an integer one can do it as follows:
x: int = 3
or:
def f(x: int):
return x
see this question for more detailed info about it:
Explicitly declaring a variable type in Python

AttributeError: 'dict' object has no attribute 'charss'

I am new to OOP with python. I have 3 classes with one being called from the other as a parameter instance:
class Characters:
def __init__(self, b="", c = ""):
self.b= b
self.c= c
class Words:
def __init__(self, charss=Characters()):
self.charss= charss
class Sentences:
def __init__(self, w=Words()):
self.w = w
I am then creating a new instance of class Words form another Class and filling it with data i have from a json file.
s = Sentences()
s.__dict__ = json.loads(output.content)
When debugging i can see that s is populated correctly. I am then trying to print out the values of s like this:
print(s.w[0].charss[0])
an error occurs:AttributeError: 'dict' object has no attribute 'charss'
is it because I am populating from the JSON as __dict__ where charss instantiated as list. If that is so what would be the best solution changing the __dict__ from json input or instantiating the object as __dict__?
The problem is the way the instance s is being accessed for printing. I am saving the json output as a dictionary but the instance of a class is by default a list. therefore instead of
print(s.w[0].charss[0])
that line should be
print(s.w[0]["charss"][0])
When you say s.__dict__ = some_dictionary, you're entirely replacing all the instance variables of s with the ones in some_dictionary. This includes w, which is now defined entirely by whatever's in your JSON. JSON objects are never going to have charss attributes, so it's guaranteed to fail in the way you mention.
What are you trying to accomplish with s.__dict__ = json.loads(output.content)? Do you just want to store the dictionary in s? If so, s.my_cool_dict_name = json.loads(output.content) might be what you want.

Create dynamically named classes instances in Python

I need to create a new instance of a specific class named from the content of a variable.
For example create an instance of the Foo class named whatever the content of the "s" variable is. This is what I tried
class Foo:
pass
s = 'bar'
eval(s) = Foo
The above code returns a "can't assign to function call" error.
I need it to create an instance called 'bar' in the Foo class in this case but I also need to be able to change the 's' variable to any string and for it to still work.
If there is another way for me to create class instances and then access them later with the "s" variable that would work too.
A lot of similar questions have been answered by creating pre defined dictionaries but in my case these dictionaries would have to be several hundred items long and hand written, and so are impractical and not very pythonian. I need to create and access the instance completely dynamically, hopefully by name but if there is another way I'm open to that too.
This should do it.
def make_class(name):
class_text = """
global {} # Makes the class object global.
class {}: # You put the class here.
pass
""".format(name, name) # Formats the text. There are a couple different ways to do this.
exec(class_text)
Example:
>>> make_class("Foo")
>>> make_class("Bar")
>>> Foo()
<__main__.Foo object at 0x7fedebcda748>
>>> Bar()
<__main__.Bar object at 0x7fedebcda8d0>

Confused by self["name"] = filename

I'm currently reading this amazing book called "Dive into Python". Up to now everything has made sense to me, but the following method has left me with some questions. Its in the chapter about initializing classes:
class FileInfo(UserDict):
"store file metadata"
def __init__(self, filename=None):
UserDict.__init__(self)
self["name"] = filename
It's only the last line I don't get. The way I see it at the moment, the calling object has a list, whose item "name" is assigned the value of the argument passed. But this doesn't make sense to me, since I thought that you can only access list indices by integers.
The book says the following about this line: "You're assigning the argument filename as the value of this object's name key." Is the name key another variable that every object defines (like doc)? And if yes, why can it be accessed like that?
[...] isn't just for lists. Any type can support it, and the index doesn't necessarily have to be an integer. self is the current object, which according to your code derives from UserDict, which supports the item manipulation methods.
You're extending a dictionary, by doing class FileInfo(UserDict), that's why you can reference to the key doing self['name'] = filename
The class inherits from UserDict which I presume is a dict-like class. For all subclasses of dicts (which keeps the dict interface intact), you can treat self as a dict, which is why you can do self[key] = value
No, the self object is a subclass of UserDict, which is a form of hash table (known as a dictionary or dict in Python). The last line is simply creating a key "name" to the filename.
Since your class derives from UserDict, it inherits a __getitem__() method that takes an arbitrary key, not just an integer:
self["name"] = filename # Associate the filename with the "name" key.

Categories

Resources