I am trying to create a list within a class and then declaring elements in that list.
I don't even know if this is the right way for python. I have some java background.
I didn't add 10 elements in the list manually because I feel creating a dynamic list will be more useful.
class Levels:
def __init__(self):
self.type = "A"
self.size = [] # trying to create a list for 10 elements.
self.makespace(self.size) # running this method to create 10 spaces and then declare them.
def makespace(self, size):
for i in range(0,10):
if(size[i] == None):
size[i] = "free"
print(i)
else:
print("Didn't work")
print(i)
test = Levels()
Your problem lies in here.
if(size[i] == None):
size[i] = "free"
print(i)
At this moment, size is empty, it doesn't contain any elements so why are you
checking size[i] == None?
You probably think that a python list behaves like an array in Java where it initializes everything with null? Even though here you are not declaring the size of the list inside the init constructor, so I'm curious how you thought of that.
Your code should look like this:
class Levels:
def __init__(self):
self.type = "A"
self.size = [] # trying to create a list for 10 elements.
self.makespace(self.size) # running this method to create 10 spaces and then declare them.
def makespace(self, size):
#This will fill the emty list with 10 None(null) values
for i in range(0,10):
size.append(None)
test = Levels()
Also a bonus:
class Levels:
def __init__(self):
self.type = "A"
self.size = []
#Notice that I'm not passing self as an argument when I call makespace()
self.makespace()
def makespace(self):
#This will fill the emty list with 10 None(null) values
for i in range(0,10):
self.size.append(None)
test = Levels()
Self is the this keyword in python, the difference is that in Python you need to pass it as an argument only when declaring methods, not when you call them and also you can name it whatever you want!
Hope this helps!
This code won't work because size[i] does not exist. Instead use size.append(...). Also you should pass a number to makespace so that you can make space for an arbitrary number of items.
class Levels:
def __init__(self, kind='A', size=10):
self.kind = kind
self.size = [ 0 for _ in range(10) ]
These slight changes make your code more robust and more pythonic.
First but the least important is that type is a builtin-method (also a class and also a type) so kind is often substituted.
Second You can pass default arguments to the constructor (or any function) as you should generally avoid having constants inside functions like that. Here you can arbitrarily set a Level's kind, as well as the initial space required.
Third Using list-comprehension you can create a list of arbitrary size (or elements). The syntax is
[ expression for args in iterable ]
which allows for any expression to be generated based on arguments passed from an iterable. Read more about list comprehension and other datastructure here.
As for your makespace you shouldnt really need it, however you could change the implementation so you can allocate more space (using self.size.append(...)) or overwriting currently used space.
Best of luck!
If you want to have 10 free spaces in the list upon initializing, change
self.size = []
to
self.size = [“free”] * 10
If you want to start with an empty list and add 10 free spaces in your makespace loop, simply use
self.size.append(“free”)
Also, you really don’t need to pass size to makespace. Since you’re already passing self, I would just reference self.size from inside the makespace function.
Related
I have created a class and am attempting to create a function that will, in essence, act as a binary operator between two objects of that class. The function I was trying to create is called 'combine'.
I know I could create the function outside of the class, but I want it to be associated with the class.
Background (not really necessary for answering the question) - the class is modelling the S4 mathematical group and is some practice with objects and classes for me. My next function was to be to simplify an element into it's simplest expression in cycles, which I am confident that I could do, but I would rather get this one sorted first.
When I create a function with one argument, it runs fine - as demonstrated in the code below, with the function 'cycletype', which works as expected.
class s4:
# Define an element of s4, elementlist is a nested list, which is a list of the cycles composing the element.
def __init__(self, elementlist):
self.elementlist = elementlist
# One simple function is to ascertain the cycletype of the element.
def cycletype(self):
cycles = []
for i in self.elementlist:
cycles.append(len(i))
return cycles
# Combining two elements using the group operation is the first function to define.
def combine(first, second):
for i in second:
first.append(i)
return first
double = s4([[1,2],[3,4]])
triple = s4([[1,2,3]])
print(combine(double,triple))
I was expecting [[1,2],[3,4],[1,2,3]] to be printed, however, it showed a NameError, not recognising combine.
You should be creating a new instance from the lists wrapped by the two arguments:
class S4:
# Define an element of S4, elementlist is a nested list, which is a list of the cycles composing the element.
def __init__(self, elementlist):
self.elementlist = elementlist
# One simple function is to ascertain the cycletype of the element.
def cycletype(self):
cycles = []
for i in self.elementlist:
cycles.append(len(i))
return cycles
# Combining two elements using the group operation is the first function to define.
def combine(self, first, second):
return S4(first.element_list + second.element_list)
It also appears that you could simply define __add__ instead of combine,
# Simplified implementation, no error checking
def __add__(self, second):
return S4(self.element_list + second.element_list)
allowing you to write
print(double + triple)
instead of
print(combine(double, triple))
There's two problems with the code
putting the function inside the class means that it's a method. So, you have to access it using the object s4.combine(s1), not just combine(...). Otherwise, it would be a function, not a method.
After you change that: you can't write for i in second, because instances of your class are not iterable. You have to implement __iter__ to be able to use that syntax
This is because the combine function isn't present in the global scope ( I hope that's what its called, I mess up names real bad).
You can only call functions present in the global scope, in the case of classes, you need objects to call these functions as these functions are part of those specific classes and not the global scope in general.
Hope this helped
There's a scope problem, you defined combine within the s4 class, so you should call it from a instance of s4. Anyways, here's is how I would do it.
class s4:
# Define an element of s4, elementlist is a nested list, which is a list of the cycles composing the element.
def __init__(self, elementlist):
self.elementlist = elementlist
# One simple function is to ascertain the cycletype of the element.
def cycletype(self):
cycles = []
for i in self.elementlist:
cycles.append(len(i))
return cycles
# Combining two elements using the group operation is the first function to define.
def combine(self, second):
#Here I changed first to self, first would be the s4 class that calls the function, in this example double and second would be the one that you want to combine
first = self.elementlist
for i in second.elementlist:
first.append(i)
return first
double = s4([[1,2],[3,4]])
triple = s4([[1,2,3]])
##As double() is defined within the s4 class, you can only call it from an instance of s4 (in this case you could use doble.combine() or triple.combine())
print(double.combine(triple))
Hope it helps.
I have created a class with around 100+ instance variables (as it will be used in a function to do something else).
Is there a way to translate all the instance variables; into an array list. Without manually appending each instance variable.
For instance:
class CreateHouse(object):
self.name = "Foobar"
self.title = "FooBarTest"
self.value = "FooBarValue"
# ...
# ...
# (100 more instance variables)
Is there a quicker way to append all these items to a list:
Quicker than:
theList = []
theList.append(self.name)
theList.append(self.title)
theList.append(self.value)
# ... (x100 elements)
The list would be used to perform another task, in another class/method.
The only solution (without totally rethinking your whole design - which FWIW might be an option to consider, cf my comments on your question) is to have a list of the attribute names (in the order you want them in the final list) and use getattr
class MonstruousGodClass(object):
_fields_list = ["name", "title", "value", ] #etc...
def as_list(self):
return [getattr(self, fieldname) for fieldname in self._fields_list]
Now since, as I mentionned in a comment, a list is NOT the right datatype here (from a semantical POV at least), you may want to use a dict instead - which makes the code much simpler:
import copy
def as_dict(self):
# we return a deepcopy to avoid unexpected side-effects
return copy.deepcopy(self.__dict__)
I have run across a few examples of Python code that looks something like this:
class GiveNext :
list = ''
def __init__(self, list) :
GiveNext.list = list
def giveNext(self, i) :
retval = GiveNext.list[i]
return retval
class GiveABCs(GiveNext):
i = -1
def _init__(self, list) :
GiveNext.__init__(self, list)
def giveNext(self):
GiveABCs.i += 1
return GiveNext.giveNext(self, GiveABCs.i)
class Give123s(GiveNext):
i = -1
def _init__(self, list) :
GiveNext.__init__(self, list)
def giveNext(self):
Give123s.i += 1
return GiveNext.giveNext(self, Give123s.i)
for i in range(3):
print(GiveABCs('ABCDEFG').giveNext())
print(Give123s('12345').giveNext())
the output is: A 1 B 2 C 3
If I were more clever, I could figure out how to put the string literals inside the constructor...but that is not crucial right now.
My question is on the use of classes this way. Yes, an instance of the class gets created each time that that the call within the print() gets made. Yet the i's are 'permanent' in each class.
This strikes me as less of an object-oriented approach, and more of a way of using classes to accomplish encapsulation and/or a functional programming paradigm, since the instances are entirely transitory. In other words, an instance of the class is never instantiated for its own purposes; it is there only to allow access to the class-wide methods and variables within to do their thing, and then it is tossed away. In many cases, it seems like the class mechanism is used in a back-handed way, in order to leverage inheritance and name resolution/spacing: an instance of the class is never really required to be built or used, conceptually.
Is this standard Python form?
Bonus question: how would I put the string literals inside each class declaration? Right now, even if I change the _init__ for GiveABCs to
GiveNext.__init__(self, 'wxyz')
it completely ignores the 'wxyz' literal, and uses the 'ABCDEF' one - even though it is never mentioned...
Please don't learn Python with this code. As mentioned by others, this code goes against many Python principles.
One example: list is a Python builtin type. Don't overwrite it, especially not with a string instance!
The code also mixes class and instance variables and doesn't use super() in subclasses.
This code tries to simulate an iterator. So simply use an iterator:
give_abcs = iter('ABCDEFG')
give_123s = iter('12345')
for _ in range(3):
print(next(give_abcs))
print(next(give_123s))
# A
# 1
# B
# 2
# C
# 3
If you really want to fix the above code, you could use:
class GiveNext :
def __init__(self, iterable) :
self.i = - 1
self.iterable = iterable
def giveNext(self) :
self.i += 1
return self.iterable[self.i]
giveABCs = GiveNext('ABCDEFG')
give123s = GiveNext('12345')
for _ in range(3):
print(giveABCs.giveNext())
print(give123s.giveNext())
It outputs:
A
1
B
2
C
3
This code in the OP is an incredible amount of crap. Not only it is long, unreadable, misuses OO features, and does not use Python features at all (an iterator being a standard Python feature). Here is a suggestion for a more Pythonist approach:
giveABCs = iter('ABCDEFG')
give123s = iter('12345')
for i in range(3):
print(next(giveABCs))
print(next(give123s))
About your bonus question: I guess you are modifing the _init__() method of GiveABCs and Give123s. It is normal that whatever code you put in there has no effect, because the Python constructor is __init__() (with 2 leading underscores, not 1). So The constructor from GiveNext is not overloaded.
The answer people have already given for using the value of a variable in the assignment of another is:
to create a dictionary and,
use dict[oldVariable] instead of defining a new one
I don't think that works in the context of what I'm trying to do...
I'm trying to define a class for a vector which would take a list as an input and assign an entry in the vector for each element of the list.
My code looks something like this right now:
class vector:
def __init__(self, entries):
for dim in range(len(entries)):
for entry in entries:
self.dim = entry #here I want to assign self.1, self.2, etc all the way to however
#many elements are in entries, but I can't replace self.dim with
# dict[dim]
def __str__(self):
string = []
for entry in range(1,4):
string.append(self.entry)
print(string)
How do I do this?
What you are doing here is a bit strange, since you are using a variable named "dim" in a for, but you do not do anything with that variable. It looks like you want to use a class as if it was an array... why don't you define an array within the class and access it from the outside with the index? v.elements[1] ... and so on?
Example:
class Vector:
def __init__(self, entries):
self.elements = []
for e in entries:
self.elements.append(self.process(e))
def __str__(self):
buff = ''
for e in self.elements:
buff += str(e)
return buff
Hope this helps.
If I'm reading your question correctly, I think you're looking for the setattr function (https://docs.python.org/2/library/functions.html#setattr).
If you wanted to name the fields with a particular string value, you could just do this:
class vector:
def __init__(self, entries):
for dim in range(len(entries)):
for entry in entries:
#self.dim = entry
setattr(self, str(dict[dim]), dim)
That will result in your object self having attributes named with whatever the values of dict[dim] are and values equal to the dim.
That being said, be aware that an integer value is generally a poor attribute name. You won't be able to do print obj.1 without error. You'd have to do getattr(obj,'1').
I agree with #Ricardo that you are going about this strangely and you should probably rethink how you're structuring this class, but I wanted to directly answer the question in case others land here looking for how to do dynamic naming.
I have been having trouble getting python to generate a (non-predetermined) number of class instances. Basically have classes be able to reproduce themselves.
class foo:
def __init__(self, name):
self.name = name
while True:
newinstance(foo) #what would the code be for this?
#or maybe
foo.newinstance #just something that could update itself
Basically generate a new instance any number of times. Thanks ahead of time.
This will do what you're asking for, but you'll want to hold onto the values somehow:
while True:
foo(some_name)
This will loop forever, so a more realistic option might be:
names = ["Ned", "Felix", "Guy"]
fooses = [foo(name) for name in names]
Use a list comprehension:
instances_of_foo = [foo("bar") for i in range(number_of_instances)]
Also, if you would like to pass different arguments to each instance, you can create of list of args instead of using range().
list_of_args = [args_for_instance_one, args_for_instance_two,...]
instances_of_foo = [foo(arg) for arg in list_of_args]