How to write a class that makes
an list for each instance. I am
concerned on the class part.
I know how to make a int , double
or string, but I need an list
(string).
The list will have later values
assigned to it, when it is an
instance and there will be
custom methods in the class
for the objects/instances.
Classes in Python can have their member variables instantiated within the __init__ function, which is called upon creation of the class object. You should read up on classes here if you are unfamiliar with how to create one. Here is an example class that instantiates a list as a member and allows appending to the list:
class ListContainer:
def __init__(self):
self.internal_list = [] # list member variable, unique to each instantiated class
def append(elem):
self.internal_list.append(elem)
def getList():
return self.internal_list
list_container_1 = ListContainer()
list_container_1.append('example')
print list_container_1.getList() # prints ['example']
list_container_2 = ListContainer()
print list_container_2.getList() # prints []
Related
I inherit features from one parent class (__Parent) to two different child classes for constructing a nested data structure. The init() method of ChildTwo initiallizes the parent class using super() thereby setting i_am_from_child to "Two". It then appends an instance of ChildOne to the inherited list var. It is this appending that behaves unexpected when using list.append(). The init() of ChildOne also initializes the parent class in the same way, setting its i_am_from_child to "One", but without appending its inherited list var.
Therfore the list var of the instance of ChildOne stored in ChildTwo's var[0] should have a length of 0 as it is empty. This behaviour is obtained when using numpy append. However pythons list.append() results in an instance of ChildOne beingg strored at that location.
import numpy as np
class __Parent:
var = []
i_am_from_child = None
def __init__(self, which:str=None) -> None:
self.i_am_from_child = which
print(f"Parent initiallized by Child{which}")
def how_long(self) -> int:
return len(self.var)
def from_child(self) -> str:
return self.i_am_from_child
class ChildOne(__Parent):
def __init__(self) -> None:
print("Initiallizing ChildOne")
super().__init__(which="One")
print(f"ChildOne: len(self.var) = {len(self.var)}")
class ChildTwo(__Parent):
def __init__(self) -> None:
print("Initiallizing ChildTwo")
super().__init__(which="Two")
# two options in question
self.var.append(ChildOne()) # this behaves unexpected
#self.var = np.append(self.var, ChildOne()) # this behaves as expected
#####################################################################
X = ChildTwo() # instance of ChildTwo
Y = X.var[0] # copy of ChildOne instance created by ChildTwo constructor
print(f"type(X) = {type(X)} and type(Y) = {type(Y)}")
print(f"X is from Child{X.from_child()} and Y=X.var[0] is from Child{Y.from_child()}")
# something weird with var happens when using diffent append methods
print()
print(f"ChildOne: self.function() = {Y.how_long()} should be 0")
print(f"ChildTwo: self.function() = {X.how_long()} should be 1")
print(f"Type of Y.var[0] is {type(Y.var[0])}")
Using print() I checked the correct sequence of method calles, additionally the types are correct. But Y.var[0] should be empty, i.e. [] and thus should have length zero. Commenting out the python append and uncommenting the numpy append statements in ChildTwo.init() produces the desired behaviour.
It's because you're declaring var as a class variable, which is shared between all instances of that class, rather than as an instance variable. When you type self.var, python first looks in the instance attribute dictionary, and if an attribute with the name var doesn't appear there, it looks in the instance's class dictionary, where it finds the shared var attribute. If you want each instance to treat them separately, you need to assign that variable in the __init__ method.
class Parent:
def __init__(self):
self.var = []
I have noticed the following in setting a class variable:
from ingest.models import WBReport
wb=WBReport()
wb.date = '2019-01-09'
The above does not set the date for the class. For example, calling this method, it prints None:
#classmethod
def load_asin(cls):
print cls.date
However, if I add another method to set that variable it does work. For example:
#classmethod
def set_date(cls, date):
cls.date=date
from ingest.models import WBReport
wb=WBReport()
wb.set_date('2019-01-09')
Why does the first method (wb.date=X)not work but the second one (wb.set_date(X)) does?
Instance variables and class variables exist separately. wb.date = '2019-01-09' sets an instance variable on the object wb, not the class variable WBReport.date, which is what the class method set_date sets.
The call to the class method is roughly equivalent to WBReport.date = '2019-01-09'.
Let's say I have a class called Test with an attribute items. Then I create a subclass called Best. Which has a method that modifies the classes attribute items. But it even modifies Test's items and I what it to modify items only for Best.
class Test():
items = []
class Best(Test):
def method(self):
type(self).items.append("a test")
>>> Best().method()
>>> Best.items
["a test"]
>>> Test.items
["a test"] # This is what I don't want.
You have declared items as an attribute of the superclass itself, so all instances of Test and it's subclasses will share the same list. Instead declare it in Test's __ init __ method, so there is one list per instance.
In Best, just append to self.items, and only the Best instance's list will be updated.
class Test(object):
def __ init __(self)
self.items = []
class Best(Test): # Best must inherit from Test
def method(self):
self.items.append("a test")
In Python you can get what you are asking by using "private" members...
class Base(object):
def __init__(self):
self.__mine = 42 # note the double underscore
def baseMethod(self):
return self.__mine
class Derived(Base):
def __init__(self):
Base.__init__(self)
self.__mine = 99
def derivedMethod(self):
return self.__mine
obj = Derived()
print(obj.baseMethod(), obj.derivedMethod()) ## ==> 42, 99
this works because at compile time Python will replace the name __mine with _Base__mine when compiling Base and with _Derived__mine when compiling Derived.
Note however that in Python while this is possible in my experience it's not used very often. Deriving a class in many cases is just not needed thanks to "duck typing" and to delegation, something that is not possible in languages like C++ or Java.
The only possible way to do this is to create a new items on the subclass -- where else is this new list meant to come from? Also type(self) is redundant. The lookup machinery looks up attributes on the class if it cannot find the attribute on the instance. Better yet, if you don't need an instance then declare the method to be a class method.
eg.
class Test:
items = []
#classmethod
def method_test(cls):
cls.items.append('test')
class Best(Test):
items = []
#classmethod
def method_best(cls):
cls.items.append('best')
Test.method_test()
assert Test.items == ['test']
assert Best.items == []
Test.items = []
Best.method_test()
Best.method_best()
assert Test.items == []
assert Best.items == ['test', 'best']
Note that method_test works on the Best class when called from the Best class.
Your Best class is modifying Test (which I assume it's supposed to be inheriting from) because Best doesn't have its own items list. When you access Best.items, you're accessing the list where it is inherited from (i.e. from Test class). If you want a different list, you need to create it explicitly in the subclass Best:
class Best(Test):
items = [] # hide the inherited list with our own list
# ...
Your code doesn't do what you describe.
For one thing, Best is not a subclass of Test.
For another Best.method() produces
NameError: name 'self' is not defined
items is a Test class attribute.
t = Test()
t.items.append(1)
changes Test.items.
As defined B.items gives an AttributeError.
Even if I change:
class Best():
def method(self):
...
Best.method() does not run; method is an instance method. I need to use Best().method(). But then I get the items AttributeError.
class Best(Test):
def method(self):
...
does what you desribe. Best().method() modifies the Test.items - because the Test class attribute is shared with the subclass.
As shown in other answers, simply defining items for Best decouples its value from the Test class attribute
class Best(Test):
items = ['other']
...
How to make dictionary element an object in Python?
I made a class…
class Qs:
def __init__(self,list1,id,quest="",mark=1):
self.__list1=list1
self.__id=id
self.__quest=quest
self.__mark=mark
self.__list1.update({self.__id:{self.__quest:self.__mark}})
How can I store objects in a dictionary so I can call functions in this class like this?
dictionary[1].print()
what you probably want is another class that includes a dictionary in it:
class QuestionCollection:
def __init__(self):
self.listofquestions = dict()
def print(self,question_number):
print(dictionary[question_number])
Then you could do this:
classobject = MyClass()
classobject.listofquestions[1] = Qs(...)
classobject.print(1)
or,
classobject = MyClass()
print(classobject.dictionary[1])
Then, you could extend this class to include other functions that operate on your entire dictionary.
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