I have a class which has some class variables, methods, etc. Let's call it Cell.
class Cell:
def __init__(self):
self.status = 0
...
I have a list of different instances of this class.
grid = [Cell.Cell() for i in range(x_size*y_size)]
Is it possible to get the upper shown status variable of each of the instances stored in grid in a vectorized manner without looping through the elements of the list?
Not in vanilla Python.
statuses = [x.status for x in grid]
If you are looking for something that abstracts away the explicit iteration, or even just the for keyword, perhaps you'd prefer
from operator import attrgetter
statuses = list(map(attrgetter('status'), grid))
?
I'm trying to create some simple objects that are defined dynamically through a class - to allow me to rapidly iterate through the creation of all possibilities of these objects.
class NSObjects:
def __init__(self, shape, position, shading):
self.shape = shape
self.position = position
self.shading = shading
def __str__(self):
return '{} - {} - {}'.format(self.shape(), self.position(), self.shading())
def NSGenerator_1():
for i in range (0,3):
obj_1_i = NSObjects(shape_init_top + i, posn_init_top+i, shading_init_top+i)
for i in range (3,6):
obj_1_i = NSObjects(shape_init_mid + i, posn_init_mid+i, shading_init_mid+i)
for i in range (6,9):
obj_1_i = NSObjects(shape_init_mid + i, posn_init_mid+i, shading_init_mid+i)
NSGenerator_1()
print(obj_1_2)
At the moment it is telling me that obj_1_2 doesn't exist. For the purpose of this you can assume that I have defined all the init variables to start at 0, 1 or 2 elsewhere in the code. I am basically trying to create a series of objects which will have properties as defined by a mathematical formula.
Thanks in advance for any help you can provide (I only started coding a few weeks ago so this might be a very silly question!)
You only ever assigned to obj_1_i, not obj_1_2, and it was local to the function. There is no way for Python to tell that the _i was meant as a separate variable instead of part of the longer variable name. For a quick fix, try replacing the
obj_1_i = parts with globals()[f'obj_1_{i}'] =.
But rolling numeric indexes into the variable names like that (_1_2) is a code smell. A better design is to actually use them as indexes to a data structure, like a list or dict.
For example, define
obj = {} at the top level (outside of any class or function).
Then you can replace obj_1_2 everywhere with obj[1, 2], etc. If you wrote them that way,obj[1, i] would work as you expect inside those for loops.
I have two classes set up (with some other attributes that are irrelevant).
class Alcohol():
def __init__(FunctionalGroup):
FunctionalGroup.Naming = ["hydroxy", "ol"]
class Halogenoalkane():
def __init__(FunctionalGroup):
FunctionalGroup.Naming = ["chloro", "bromo", "iodo"]
I want to be able to sort a given string such as ethanol or 2-chloromethane into one of these and create an instance based on which class the name fits into. For example:
>>> Name: Ethanol
This is an alcohol.
I am looking for a way to iterate over the FunctionalGroup.Naming list in each class and check if any of them are contained in the string.
What is the best approach to doing this or alternative data structures?
(Sorry if you don't like chemistry I'm just trying to make revising it more interesting)
I am not sure if this is the cleanest way of doing it, and I removed the instance variables and made a constant list in each class instead. This way it is easier to reference, and the list seems like a constant anyhow:
class Alcohol():
Naming = ["hydroxy", "ol"]
def __init__(self):
print ' ---> Alcohol'
class Halogenoalkane():
Naming = ["chloro", "bromo", "iodo"]
def __init__(self):
print ' ----> Halogen'
str = 'hydroxy'
classes = [Alcohol, Halogenoalkane]
chosen_class = object
for cl in classes:
if str in cl.Naming:
chosen_class = cl
print '{} is an:'.format(str)
obj = chosen_class() # instantiate the class
output:
hydroxy is an:
---> Alcohol
I need help on creating an object (a sequence of numbers) in respect to some parameters of a class. Lets say I typed in to the Python IDLE shell:
SuperLotto = make_lottery_set_type('SuperLotto', 6, (1,50))
#means user can create a 'SuperLotto' with 6 numbers in range of 1 to 50
It would make 'SuperLotto' as a new class instance of a class called 'LotteryGameType'.
This is using the code so far:
class LotterySetError(Exception):
pass
def make_lottery_set_type(name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
name = LotteryGameType(name, size, minmax[0], minmax[1])
return name
class LotteryGameType:
def __init__(self, name, set_size, min_set_number, max_set_number):
self.name = name
self.set_size = set_size
self.min_set_number = min_set_number
self.max_set_number = max_set_number
I want to be able to create a sequence of numbers and storing it for later use so I can use it with things like overload operators (e.g. eq and ne).
I want to be able to type into the Python IDLE shell:
SuperLotto([3, 4, 19, 23, 46, 27])
This would create an object under the parameters of SuperLotto, if not under parameters of 'SuperLotto' (say more than 6 numbers), it would raise an error. Any approach would be fine. Does anyone have any ideas on how to approach this?
It sounds like what you want is for make_lottery_set_type to return a new class, presumably one that's a subclass of LotteryGameType, rather than returning an instance of that type.
This is actually pretty easy to do in Python. Class definitions are just normal code, that you can run anywhere, even in the middle of a function. And they have access to the local environment while they're running. And classes themselves are "first-class values", meaning you can pass them around and return them from functions. So:
def make_lottery_set_type(name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
class NewLotteryGameType(LotteryGameType):
def __init__(self, numbers):
super().__init__(name, size, minmax[0], minmax[1])
self.numbers = numbers
return NewLotteryGameType
If you want to add other methods, that's the same as adding methods to any other class. For example:
def make_lottery_set_type(name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
class NewLotteryGameType(LotteryGameType):
def __init__(self, numbers):
super().__init__(name, size, minmax[0], minmax[1])
self.numbers = numbers
def __eq__(self, rhs):
return set(self.numbers) == set(rhs.numbers)
return NewLotteryGameType
So:
>>> SuperLotto = make_lottery_set_type('SuperLotto', 6, (1,50))
>>> super1 = SuperLotto([1,2,3,4,5,6])
>>> super2 = SuperLotto([6,5,4,3,2,1])
>>> super3 = SuperLotto([7,8,9,10,11,12])
>>> super1 == super2
True
>>> super1 == super3
False
(Obviously you can define __eq__ however you want, if set-equality isn't the right rule for your use.)
If you try to inspect the values you're generating, they don't look quite as pretty as you might like. For example, you'd probably rather see SuperLotto rather than NewLotteryGameType in places like this:
>>> super1
<__main__.NewLotteryGameType at 0x10259e490>
>>> SuperLotto.__name__
'NewLotteryGameType'
For that, just add NewLotteryGameType.__name__ = name. You might also want to copy over the docstring from the parent class, or various other things.
More generally, look at functools.update_wrapper (which is designed for wrapping up functions, not classes, but many of the details are the same) for inspiration, and the inspect module docs from your Python version for all of the attributes that classes can have.
In a comment, you ask:
The only problem is that I want NewLotteryGameType to inherit the parameters such as name, set_size, min_set_number, max_set_number from LotteryGameType. So lets say I wanted to type in NewLotteryGameType.set_size in to the Python Shell. I want it to return back to me 6.
That's contradictory. If you want to inherit the instance attributes of LotteryGameType… well, you already do. For example:
>>> super1.set_size
6
If you want them to be accessible off the class, then they can't be instance attributes, they have to be class attributes. And just changing set_size to a class attribute of LotteryGameType and inheriting it won't work, because the whole point of a class attribute is that the same value shared by all instances of the class or any of its subclasses, and the subclasses all need different values.
But you could do something like this:
class LotteryGameType:
def __init__(self, min_set_number, max_set_number):
self.min_set_number = min_set_number
self.max_set_number = max_set_number
def make_lottery_set_type(lottery_name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
class NewLotteryGameType(LotteryGameType):
name = lottery_name
set_size = size
def __init__(self, numbers):
super().__init__(minmax[0], minmax[1])
self.numbers = numbers
def __eq__(self, rhs):
return set(self.numbers) == set(rhs.numbers)
return NewLotteryGameType
(Notice that I had to rename the first make_ parameter to lottery_name so it was different from the class attribute name, because of the way scopes work.) Now, name and set_size are not instance attributes, nor are they class attributes of LotteryGameType—but they're class attributes of each NewLotteryGameType. So:
>>> SuperLotto = make_lottery_set_type('SuperLotto', 6, (1,50))
>>> SuperDuperLotto = make_lottery_set_type('SuperDuperLotto', 8, (1,100))
>>> SuperLotto.set_size
6
>>> SuperDuperLotto.set_size
8
What if you create instances of those types? Well, Python looks for attributes in the instance, then in the most-derived class, and then the base classes. So as long as you don't create instance attributes with the same name (notice that I removed the extra params, and the code that set instance attributes, from the LotteryGameType.__init__ method), it does just what you'd want:
>>> super1 = SuperLotto([1,2,3,4,5,6])
>>> super1.set_size
6
>>> duper1 = SuperDuperLotto([1,2,3,4,5,6,7,8])
>>> duper1.set_size
8
Of course this means that LotteryGameType is no longer a usable type on its own; only its subclasses are usable. But that's probably what you wanted anyway, right? You could even consider making it explicitly an abstract base class to make sure nobody accidentally tries to use a direct LotteryGameType instance.
If you're feeling brave, you might want to read up on metaclasses and see how you could adapt this whole design into use a LotteryGameMetaclass, so each new class is an instance of that metaclass instead of a subclass of the (abstract) base class. The source for the new enum module in 3.4, or the near-equivalent external flufl.enum package, might make good sample code. Then you can play with both and see how similar and how different they are.
I have a class to assign some parameters:
class body:
def __init__(self, name, number, L):
self.name = name
self.number = number
self.L = L
And I would like to assign these parameters to 10 almost equal bodies like:
for i in range(0, 10):
body[i].name = "test_name"
body[i].number = i
body[i].L = 1.
And to be able to change, lets say, the parameter L of body 3 from 1 to 2:
body[3].L = 2
Thank you very much for the help.
Note that body is a class. Using body[i] suggests you may be intending to use body as a list. If you want to create a list of 10 instances of body, do not name the list body as well. You could instead name the list bodies and define it with a list comprehension:
bodies = [body("test_name", i, 1.) for i in range(0, 10)]
bodies[3].L = 2
By the way, PEP8 Style Guide recommends all classes follow the CapWords convention. So to conform with the convention, body should be Body. By following this convention, everyone reading your code will understand immediately what is a class and what is not.