How to get python class instance variables inside __init__? - python

I'd like to know if there's a way to get class instance variables that are inside an init.
I've seen something verify close what I am looking for except that I am looking for a way to get instance variables and not class variables.
Linked subject: Looping over class variable's attributes in python
Say I have a class such as:
class Identity:
table = "tb_identity"
def __init__(self, id="", app_name="", app_code="", state="", criticality=""):
self.id = id
self.app_name = trigram_name
self.app_code = trigram_irt
self.state = state
self.criticality = criticality
I'd like to be able to get a list of with instance variables name like:
["id","app_name","app_code","state","criticality"]
With something such as :
members = [getattr(Identity,attr) for attr in dir(Identity) if not attr.startswith("__")]
Im only getting "tb_identity" and not even "table".
But that's not the main problem, I am looking for something like:
["id","app_name","app_code","state","criticality"]
Is there any proper way to get these variables inside init ?
Thank you for your time.
Edit: Any way of doing this without instanciation?

Try
class Identity:
table = "tb_identity"
def __init__(self, id="", app_name="", app_code="", state="", criticality=""):
self.id = id
self.app_name = 'trigram_name'
self.app_code = 'trigram_irt'
self.state = state
self.criticality = criticality
print(self.__dict__.keys())
i = Identity()
Output
dict_keys(['id', 'app_name', 'app_code', 'state', 'criticality'])

Related

How to access attribute of object from another object's method, which is one of attributes in Python?

I would like to know if it's possible, and if yes, how to access attribute(s) of a "super" class instance, when having composition implemented.
Example provided below is only to provide idea here and setup common ground on further explanations.
I want to have access to "id" attribute for an instance of MiniVan directly from object "door" (type DoorElement).
My Code
class Car:
def __init__(self, _id):
self.id = _id
class CarElement:
def __init__(self, name):
self.name = name
def get_car_id(self):
# Body which will access value of attribute "id"
return car_id
class MiniVan(Car):
def __init__(self, _id):
super(MiniVan, self).__init__(_id)
self.door = DoorElement('door')
self.engine = EngineElement('engine')
class DoorElement(CarElement):
def __init__(self, name):
super(DoorElement, self).__init__(name)
class EngineElement(CarElement):
def __init__(self, name):
super(EngineElement, self).__init__(name)
def main():
mini_van = MiniVan(123)
id_from_door = mini_van.door.get_car_id()
id_from_engine = mini_van.engine.get_car_id()
print(id_from_door) # Expected output 123
print(id_from_engine) # Expected output 123
if __name__ == '__main__':
main()
Expected:
Printed out twice "123"
What I've tried:
Passing required attribute during creating object
I know that I could just define init method with passing "car_id" but for some reasons I would love to avoid it if possible. If not, I would propably just go for it.
to set class attribute, and then call it from CarElement class within classmethod e.g.:
#classmethod
def get_id(cls):
return Car.id
But issue with this solution is that, I can have many child-classes for Car class (MiniVan, Truck, etc.) and I want have it still working.
Trying to use descriptor
def __get__(self, instance, owner):
return instance.id
But I could understand it wrong, and actually getter (as far as I understand clean code) should return instance of a class and not any attribute.
Additional Info
I will ALWAYS use CarElement (or child classes) instances as attributes of instance of Car (or child classes) instances - different usage will be treated as use-error
There can be a lot of different child classes of Car class, but always within inheritance way ( Car <- RacingCar(Car) <- FormulaOneCar(RacingCar) ) but no composition
In order for your code to work, you would have to initialize all CarElement-s with car_id. Currently, the error you are getting comes from lack of such a variable in the scope of the method. My idea of a change is this:
class CarElement:
def __init__(self, name, car_id):
self.name = name
self.car_id = car_id
def get_car_id(self):
# Body which will access value of attribute id
return self.car_id
I can't see any other magic way.

Inheritance without inheriting, is there create dinamically attributes that point to other class variables?

I'm struggling to solve with this problem.
I'd like to have the name variable to be like a pointer to the value of self.model.name. If the value of _class.model.name is changed the _class.name should change accordingly.
Can't find a way to basically map dynamically the Class attributes with any Model attributes without inheriting.
class Model(object):
name = 'foo'
parent = 'foo_p'
class Class(object):
model_class = Model
def __init__(self):
self.model = self.model_class()
setattr(self, 'name', self.model.name)
_class = Class()
print _class.model.name # foo
_class.model.name = 'foo_1'
print _class.name # this should be foo_1
Thanks!
Use a property to create a single dynamically computed attributes:
class Class(object):
_model_class = Model
#property
def name(self):
return Class._model_class.name
This causes all instances of Class to run the name method whenever the attribute name is looked up. This allows the value to be dynamically computed on each lookup.
_class = Class()
print(_class.name) # 'foo'
Model.name = 'bar'
print(_class.name) # 'bar'
If you want to dynamically fetch many or all attributes from somewhere else, consider using __getattr__:
class Class(object):
_model_class = Model
def __getattr__(self, name):
# name is a *string* containing the name of the attribute to fetch
return getattr(Class._model_class, name)
The __getattr__ is only triggered for attributes that are not on the class/instance. This makes it rather straightforward to use with manually defined attributes. Note that you can use arbitrary code to restrict what is fetched - e.g. raise AttributeError if name is not in some whitelist.
Along with MisterMiyagi's answer - but in case you want to still want to keep the concerns separated (even though it really doesn't seem like you do)
class Class(object):
model_class = Model
def __init__(self):
self.model = self.model_class()
setattr(self, 'name', self.model.name)
# This is what we'll be changing
#property
def model_name(self):
return self.model.name
# This method will get called whenever we change the model_name
#model_name.setter
def model_name(self, new_name):
self.model.name = new_name
self.name = new_name
_class = Class()
_class.model_name # foo
_class.model_name = "bar" # both _class.model.name == bar and _class.name == bar now

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.

dynamically create a type [duplicate]

This question already has answers here:
How to avoid having class data shared among instances?
(7 answers)
Closed 9 years ago.
I can create class definition dynamically, like there:
class_name = 'Human'
base_classes = (object,)
attributes = {'name':'',
'books':list(),
'say_hello':lambda self: sys.stdout.write('Hello!')}
Human = type(class_name, base_classes, attributes)
uzumaxy = Human()
uzumaxy.name = 'Maxim'
uzumaxy.books.append('Programming via .NET')
print(uzumaxy.name) # Out: "Maxim"
print(uzumaxy.books) # Out: "['Programming via .NET']"
grandrey = Human()
grandrey.name = 'Andrey'
grandrey.books.append('Programming via python')
print(grandrey.name) # Out: "Andrey"
print(uzumaxy.name) # Out: "Maxim"
print(grandrey.books) # Out: "['Programming via .NET', 'Programming via python']"
print(uzumaxy.books) # Out: "['Programming via .NET', 'Programming via python']", but i'm expecting: "['Programming via .NET']"
Seems, attribute "name" is instance-level, but why attribute "books" is class-level?
How I can dynamically create definition of type with instance-level attributes? Thx for help.
Actually, both name and books are class-level. It's just that strings are immutable, so when you use uzumaxy.name = "Maxim", you're adding a new attribute called name hiding the class name, while for uzumaxy.books.append("Programming via .NET"), you're accessing the existing (class) books and modifying it. Your code is equivalent to this:
class Human(object):
name = ''
books = []
def say_hello(self):
sys.stdout.write("Hello!")
Note the same behavior. Traditionally, we'd fix that by writing Human like this:
class Human(object):
def __init__(self):
self.name = ''
self.books = []
def say_hello(self):
sys.stdout.write("Hello!")
Now each instance has its own name and books. To do this with a dynamically-created type, you do essentially the same thing, giving it an __init__:
def init_human(self):
self.name = ''
self.books = []
attributes = { '__init__': init_human,
'say_hello': lambda self: sys.stdout.write("Hello!") }
They're both class-level. name is simply immutable, so it doesn't look class-level at first glance. Most attempts to modify it will create a new instance-level attribute with the same name.
Just like when writing a class the normal way, you need to create instance attributes in the constructor:
def __init__(self):
self.name = ''
self.books = []
def say_hello(self):
# This prints a newline. The original didn't.
print 'Hello!'
Human = type('Human', (object,), {
'__init__': __init__,
'say_hello': say_hello,
})

create an instance of class in python 2.7

I wrote a code:
class NewsStory(object):
def __init__(self, guid, title, subject, summary, link):
NewsStory.guid = guid
NewsStory.title = title
NewsStory.subject = subject
NewsStory.summary = summary
NewsStory.link = link
def getGuid(self):
return self.guid
def getTitle(self):
return self.title
def getSubject(self):
return self.subject
def getSummary(self):
return self.summary
def getLink(self):
return self.link
When I added an instance as:
test = NewsStory('foo', 'myTitle', 'mySubject', 'some long summary', 'www.example.com')
print test.getGuid() gives me foo, which is correct. However, if I continuously created two instances:
test = NewsStory('foo', 'myTitle', 'mySubject', 'some long summary', 'www.example.com')
test1 = NewsStory('foo1', 'myTitle1', 'mySubject1', 'some long summary1', 'www.example1.com')
both print test.getGuid() and print test1.getGuid() gave me foo1 but no foo. Why does it happen? And is there a method that I can modify my class definition or functions inside the class to avoid the new created instance overwriting the old one?
Thank you.
You'll need to make those variables in your __init__ function instance variables instead of class variables.
Instance variables look like this:
self.guid = guid
Class variables look like this:
NewsStory.guid = guid
Class variables are the same for all members of the class, but instance variables are unique to that instance of the class.
The __init__ method is called after an instance of the class is created. The first argument, called self by convention, is the instance of the class. NewsStory is the class itself.
In your code, you're creating class variables. You want instance variables:
self.guid = guid
You are modifying class variables, which are common to all the objects. What you should do is to create those variables in the object, like this
self.guid = guid
self.title = title
self.subject = subject
self.summary = summary
self.link = link

Categories

Resources