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
Related
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'])
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.
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
I would like for the user to specify via input parameters which classes they would like to instantiate. I know how to get the parameter from the request, but how can I instantiate the specified class without using many if statements?
request['classToUse'] = Class1
newClass = request['classToUse']()
Allow the user to specify a string representing one of the available classes. Look up the class by the string provided.
# map class names to classes
avail = dict((cls.__name__, cls) for cls in (Spam, Eggs, Toast))
#app.route('/hello')
def hello():
name = request.args['name']
obj = avail[name]()
return 'you created a {}'.format(name)
Navigating to /hello?name=Toast will create an instance of the Toast class.
if request contains Class1 at classToUse, then your code should work. A basic example to show:
class A(object):
def __init__(self):
self.a = 5
d = {'a': A}
my_obj = d['a']()
print my_obj.a
returns
5
here you can see, that it is instantiated with ()
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,
})