Use String as variable name inside __init__ method - python

I want to use strings as variable names inside a init method of a function, however it does not seem to work so far. I tried the following:
class SomeClass:
def __init__(self, car_brand="BMW", **kwargs):
car_brand = 'Mercedes'
# change car_brand variable with exec
exec("identifier " + "= 'Audi'")
# change car_brand variabel with local
str = "car_brand"
locals()[str] = 'Audi'
self.car_brand = car_brand
sc = SomeClass(car_brand="BMW")
sc.car_brand
My output is "Mercedes" so apparently it is possible to simply overwrite the input argument however it is not possible to overwrite the variable with "Audi" using the string "car_brand" as variable name.

There are multiple ways to accomplish this.
# modifying the globals
globals()[name] = value
from operator import setitem
setitem(globals(), name, value)
# custom dicionary, like globals
custom_dict[name] = value
Perhaps you want to modify only the current instance's attributes?
setattr(self, name, value)

Related

Creating a global variable passed as parameter

I'm trying to create a function, that would take a parameter, then make a global variable out of it(more precisely an instance of a class).
class SomeClass():
#some stuff defined inside
def create(crt, **kwargs):
globals()[crt] = SomeClass()
for key, value in kwargs.items():
if crt.__dict__.__contains__(key):
crt.__setattr__(key, value)
return crt
Output that I'm interested in would be:
create(foo, class_attribute=10)
That would then allow me to:
foo.other_attribute = "whatever"
I can't pass a parameter without '' if it's not defined earlier, neither can I pass a string, because it's not a variable in itself, hence it can't be an instance of a class.
Would that be even possible?
This is a bad idea, but here's how to do it.
You need to pass the name as a string. When you're setting the attributes, do it on a local variable that contains the new object.
def create(crt, **kwargs):
obj = SomeClass()
for key, value in kwargs.items():
if obj.__dict__.__contains__(key):
obj.__setattr__(key, value)
globals()[crt] = obj
return obj
create('foo', class_attribute=10)
foo.other_attribute = 'whatever'

Dynamically set dict elements with getattr

I already see the post Dynamically get dict elements via getattr?, but i can't solve my problem.
I want do something similar, but I'm a bit confused. I want set (not get) the data in the correspondent dictionary, but I get this error
AttributeError: type object 'Dictionary' has no attribute 'VERBS'.
My code is:
class Dictionary:
def __init__(self):
self.VERBS = dict()
self.REFERENCER = dict()
def setDictionary(self, fileDictionary, name):
methodCaller = Dictionary()
dictionary = "self."+name.upper()
dictionary = getattr(Dictionary, name.upper())
dictionary = fileDictionary.copy()
Can you see what I'm doing wrong? Because I don't understand completely that.
I think that this is what you are looking for:
class Dictionary:
def __init__(self):
self.VERBS = dict()
self.REFERENCER = dict()
def setDictionary(self, fileDictionary, name):
setattr(self, name.upper(), fileDictionary)
This uses setattr to assign fileDictionary to the member with the name name.upper() on self
The error that the code in the question has results from attempting to access the name on the class where it doesn't exist rather than on the instance where it exists.
It is also possible to write the method as:
def setDictionary(self, fileDictionary, name):
dictionary = getattr(self, name.upper())
dictionary.update(fileDictionary)
Which might be closer to what you were attempting.
Note that these two behave differently if the passed dictionary is mutated. The first binds the object to the name on the instance. The second updates the existing dictionary with the items from the passed dictionary.

understanding method use inside a class

I'm new to classes, this is a small piece of code I've written, but I'm still really shaky on this concept, and am wondering exactly how the method node_name comes into play here and if it's even needed?
from rdflib import BNode
class HigherNode(object):
def node_name(name):
return name
def __init__(self, **kwargs):
self.node_type = kwargs.get('node_type', 'cog_con')
self.position = kwargs.get('position', 0)
self.node_id = self.node_name
self.node = kwargs.get(self.node_name(), BNode())
for key, value in kwargs.items():
setattr(self, key, value)
def __str__(self):
return 'This is the node of {} in the graph'.format(self.node_id)
I behavior that I'm seeking is something equivalent to this:
elephant = BNode()
when used as:
some_node = HigherNode(node_id = 'elephant')
So, first off, methods have to be called by an instance of the class. So, your behavior would look something like this:
# create an instance
node = HigherNode()
# get the name
print node.node_name()
However, you never declared name inside the class. So, you'll have to do something like this:
def node_name(self):
return self.name
(All instances pass a reference to themselves to thier functions when called, so you'll always have to have at least one variable in the function call. You don't have to call it self.)
Really, it looks like what you want is actually a name setter/getter.
Try this:
Declare/set the variable in __init__.
def __init__(self, **kwargs):
self.node_name= kwargs.get('node_name', None)
Then you can use the variable like this:
# create an instance
node = HigherNode()
# get the name
print node.node_name
# set the name
node.node_name = "bluh"
Since your class extends object, use getter/setter properties.
#property
def node_name(self):
return self.node_name
#node_name.setter
def node_name(self, x):
self.node_name = str(x)
These are called exactly the same as above in option 1:
# create an instance
node = HigherNode()
# get the name
print node.node_name
# set the name
node.node_name = "bluh"
I prefer this method, since it allows you much more control over how things are set, or even whether or not you can set or get them! (Just make a getter property without a corresponding setter property, for instance.)
However, this second method is more work to set up and may not be suitable for simple variables.

Python : Behavior of class and instance variables

I have following two code samples
Example 1:
class MyClass(object):
def __init__(self, key, value):
self._dict = self._dict.update({key:value})
m = MyClass('ten',10)
print m._dict
Output:
AttributeError: 'MyClass' object has no attribute '_dict'
Example2:
class MyClass(object):
_dict = {}
def __init__(self, key, value):
self._dict = self._dict.update({key:value})
m = MyClass('ten',10)
print m._dict
Output:
None
I am quite surprised with above behavior
Why the example2 compiled successfully by just addition of _dict = {}
line, and line present at class scope.
also why None output?
I believed class scope variables has no relation with instance variable
(special with self)
Any Explaination?
Your 'example 2' defines a single dictionary at the class level. All instances of the class will share that same dictionary, at least unless you reassign _dict on the instance.
See this question for a detailed explanation:
Why do attribute references act like this with Python inheritance?
As for why you're getting None - the update method changes its dict in place, and returns None.
The None output is because dict.update returns None. It modifies the dictionary itself, but does not return anything. So you probably wanted self._dict.update({key:value}). However, self._dict doesn't exist at initialization. So it would make more sense to do self._dict = {key: value}. If you're trying to modify the object's internal dictionary, then you should do self.__dict__.update({key:value}). However, this is bad practice. A better idea would be to write setattr(self, key, value). The reason Example2 is working successfully is because if you try to do getattr(instance, thing) (which is what instance.thing does), and thing is not in instance.__dict__, then instance.__class__.__dict__ will be checked instead.
Because the _dict in Example 2 is a class variable so it's an attribute of MyClass where as the _dict in Example 1 is an instance variable so it's a instance attribute.
Example 1: you are trying to update an object that is yet to be created. therefore error.
Example 2: When working in the inner scope of the function, if you modify the variable it makes changes to the previously defined _dict. But if you assign the value, it makes a new variable with the same name in the inner scope.
This will work.
class MyClass(object):
_dict = {}
def __init__(self, key, value):
self._dict.update({key:value})
This will not.
class MyClass(object):
_dict = {}
def __init__(self, key, value):
self._dict = self._dict.update({key:value})
because you are doing an assigning operation. It makes a new variable. So no changes are made to the _dict in the outer scope. Your _dict in the outer scope is still empty and returns None.
self._dict does not yet exist, so the first version raises that exception. The second one actually falls through looking _dict up on the instance and instead updates the class attribute, then assigns the class-level dictionary to the instance-scope _dict attribute.

How do I reference the object passed to my class when I instantiate?

I have this class
class SECHeader(object):
def __init__(self,header_path):
self.header = open(header_path).read()
I have some methods in this class, one of the methods I am trying to do needs to parse the name
def parsed_name(self):
return header_path.split('-')[-1]
This works fine if in my code I use the name header_path to identify the thing I am trying to operate on
for header_path in header_paths:
header = SECHeader(header_path)
print header.parsed_name()
But if I change the name
for named_path in header_paths:
header = SECHeader(named_path)
print header.parsed_name()
I get a NameError
I played around - if can use any name for the object in the parsed_name function as long as I use the same name for the object I want to process but I can't seem to figure out how to name it so a user does not have to use my naming scheme
specifically if I change the parsed_name function to
def parsed_name(self):
return banana.split('-')[-1]
and in my loop if change it to
for banana in header_paths:
header = SECHeader(banana)
print header.parsed_name()
it works like a charm but that limits the portability of this thing I am working on. as any user would have to reference the path with whatever label I use in the function.
The problem here is that you have header_path declared as a variable for the init function. It's scope is local to the init function.
What you need is to associate header_path as a variable for the class instance.
Class SECHeader(object):
def __init__(self,header_path):
self.header_path = header_path # Instantiate a variable for class object
self.header = open(header_path).read()
def parsed_name(self):
return self.header_path.split('-')[-1] # Call the associated variable
Another way is to actually call the variable that you gave as an argument to SECHeader in parsed_name. This variable name would be in the class namespace.
for banana in header_paths:
header = SECHeader(banana)
print header.parsed_name()
Class SECHeader(object):
def __init__(self,header_path): # header_path takes value of banana
# and ends scope in __init__
self.header = open(header_path).read()
def parsed_name(self):
return banana.split('-')[-1] # banana was passed to class and is known

Categories

Resources