How to dynamically create classes - python

I am relatively new to Python and am asking myself if it is possible to create classes where names are dynamically created within a function?
Code:
def create_dummy_elements():
rows = [A,B,C,D,E,F,G,H,I]
columns = [A,B,C,D,E,F,G,H,I]
for r in range (rows):
for c in range (columns):
***** = element(1,1,1,False)
My result should be 81 objects of the class "element" named like AA,AB,AC,AD, ...
* is what I am actually asking for ...

You can make a list of these objects, but it's not ideal to create variable names dynamically.
Something like this:
my_list_of_elements = []
for r in range (rows):
for c in range (columns):
my_list_of_elements.append(element(1,1,1,False))
Then you can access them by index number, for example: my_list_of_elements[n]
or to match the two-dimensional style for loops you have:
my_list_of_elements = []
for r in range (rows):
temp = []
for c in range (columns):
temp.append(element(1,1,1,False))
my_list_of_elements.append(temp)
then you can do my_list_of_elements[i][j] to access the i-th row and the j-th column.
If you prefer a string index, a dictionary would serve you well:
my_dict_of_elements = {}
for r in range (rows):
for c in range (columns):
my_dict_of_elements["element"+(r*c+c)] = element(1,1,1,False)
which will give you access like this my_dict_of_elements["element0"] for example.
As mentioned in the comment by atomicinf on this post, you can use the globals() dict, but it seems we both agree there are better practices.

I think you can just can create list as suggested farmerjoe, but if you really want to add namespases to global, you can do it like
class element(object):
def __init__(self, *args):
self._args = args
def __repr__(self):
return ' '.join(map(str, self._args))
rows = ['A','B']
columns = ['A','B']
for r in rows:
for c in columns:
exec('%s%s = element(r,c,False)' % (r,c))
print AB
output will be
A B False

Although it's possible to create classes and named instance of classes dynamically in Python, doing so is generally frowned upon. It's considered more "Pythonic" and elegant to store collections of such things in a container of some sort such as a list or dictionary, and then access them when necessary by index or key. Here's how that might apply to your problem:
class Element(object):
def __init__(self, name, a=None, b=None, c=None):
self.name, self.a, self.b, self.c = name, a, b, c
def __str__(self):
classname = self.__class__.__name__
return('{classname}('
'name={self.name}, b={self.a}, '
'c={self.b}, d={self.c})'.format(classname=classname,
self=self))
board = {} # empty dictionary
for row in 'ABCDEFGHI':
for col in 'ABCDEFGHI':
name = row+col
board[name] = Element(name) # assign a named Element instance
# sample usage
board['AB'].a = 42
print board['AB'] # Element(name=AB, a=42, b=None, c=None)
board['GD'].c = 'something'
print board['GD'] # Element(name=GD, a=None, b=None, c=something)
Note: I don't really know what to call most of the attributes of the Element class, so am just using a, b, and c in the above for illustration purposes.

Related

Printing part of object's string

Let's say I have a class like this:
class Cls:
def __init__(self, a,b,c):
self.a = a
self.b = b
self.c = c
def __str__(self):
return f"{self.a} {self.b} {self.c}"
and I want to print only the first two items. I can do this by brute force:
c = Cls(1,2,3)
print(str(c)[:3])
But, is there a more elegant (Pythonic) way to do this?
Your slice only works if the first 2 items are only 1 digit each.
You should split the string into a list using whitespace delimiters and slice that.
c = Cls(12, 345, 6)
print(*str(c).split()[:2])

Counting the occurence of instances of a certain class in list of lists

I have list of lists in which I want to count the number of B() and C() instances and am looking for a suitable method to do this. Using collections.Counter() and the .count() function have resulted in strange results, and I suspect I do not fully understand how list of lists work in python, or how lists of class instances work in python.
This is the list of lists:
lst = [[B() for w in range(x)] for h in range(y)]
with
class A():
def __init__(self, name):
self.name = name
class B(A):
def __init__(self, name = "B"):
A.__init__(self, name)
def update(self):
if random.random() < 0.05:
return C()
else: return self
class C(A):
def __init__(self, name = "C"):
A.__init__(self, name)
And, I use the below code to randomly change B() instances in lst into C() instances:
for row in range(y):
for column in range(x):
lst[row][column] = lst[row][column].update()
How do I count the number of B() and C() instances in the list?
You can use isinstance()
You can check what class an element is with isinstance().
Here is an example:
>>> a = C()
>>> isinstance(a, C)
True
So if you have your list, you can do:
occurrences_of_B = sum(isinstance(i, B) for r in list for i in r)
occurrences_of_C = sum(isinstance(i, C) for r in list for i in r)
you can get the occurrences of the B() and C() classes.
Essentially, we are using a generator comprehension to apply the isinstance() function to every element in the list. We then use sum on the generator as True evaluates to 1 and False to 0, so we will get the total count.
As a side note, although I said it is not good practice to name a list 'array', it is actually worse to name it exactly 'list' as this prevents you from being able to use the list() function! Better would probably be lst or l. :)

python tensors with named field access

I would like to use in Python something akin to -- or better than -- R arrays. R arrays are tensor-like objects with a dimnames attribute, which allows to straightforwardly allows to subset tensors based on names (strings). In numpy recarrays allow for column names, and pandas for flexible and efficient subsetting of 2-dimensional arrays. Is there something in Python that allows similar operations as slicing and subsetting of ndarrays by using names (or better, objects that are hashable and immutable in Python)?
How about this quick and dirty mapping from lists of strings to indices? You could clean up the notation with callable classes.
def make_dimnames(names):
return [{n:i for i,n in enumerate(name)} for name in names]
def foo(d, *args):
return [d[x] for x in args]
A = np.arange(9).reshape(3,3)
dimnames = [('x','y','z'),('a','b','c')]
Adims = make_dimnames(dimnames)
A[foo(Adims[0],'x','z'),foo(Adims[1],'b')] # A[[0,2],[1]]
A[foo(Adims[0],'x','z'),slice(*foo(Adims[1],'b','c'))] # A[[0,2],slice(1,2)]
Or does R do something more significant with the dimnames?
A class compresses the syntax a bit:
class bar(object):
def __init__(self,dimnames):
self.dd = {n:i for i,n in enumerate(dimnames)}
def __call__(self,*args):
return [self.dd[x] for x in args]
def __getitem__(self,key):
return self.dd[key]
d0, d1 = bar(['x','y','z']), bar(['a','b','c'])
A[d0('x','z'),slice(*d1('a','c'))]
http://docs.scipy.org/doc/numpy/user/basics.subclassing.html
sublassing ndarray, with simple example of adding an attribute (which could be dinnames). Presumably extending the indexing to use that attribute shouldn't be hard.
Inspired by the use of __getitem__ in numpy/index_tricks, I've generalized the indexing:
class DimNames(object):
def __init__(self, dimnames):
self.dd = [{n:i for i,n in enumerate(names)} for names in dimnames]
def __getitem__(self,key):
# print key
if isinstance(key, tuple):
return tuple([self.parse_key(key, self.dd[i]) for i,key in enumerate(key)])
else:
return self.parse_key(key, self.dd[0])
def parse_key(self,key, dd):
if key is None:
return key
if isinstance(key,int):
return key
if isinstance(key,str):
return dd[key]
if isinstance(key,tuple):
return tuple([self.parse_key(k, dd) for k in key])
if isinstance(key,list):
return [self.parse_key(k, dd) for k in key]
if isinstance(key,slice):
return slice(self.parse_key(key.start, dd),
self.parse_key(key.stop, dd),
self.parse_key(key.step, dd))
raise KeyError
dd = DimNames([['x','y','z'], ['a','b','c']])
print A[dd['x']] # A[0]
print A[dd['x','c']] # A[0,2]
print A[dd['x':'z':2]] # A[0:2:2]
print A[dd[['x','z'],:]] # A[[0,2],:]
print A[dd[['x','y'],'b':]] # A[[0,1], 1:]
print A[dd[:'z', :2]] # A[:2,:2]
I suppose further steps would be to subclass A, add dd as attribute, and change its __getitem__, simplifying the notation to A[['x','z'],'b':].

Returning an lvalue from a function in python

[Sorry, I'm new in Python. Although it seems to be a very basic question, I did my share of due diligence before asking this audience, trying to avoid really stupid questions].
I'm trying to figure out the correct idiom for returning an l-value from a function. Assume I've a container of 64 objects, and I want to be able to return a reference to these objects.
class ChessBoard:
def __init__(self):
self.squares = [None for x in range(64)]
square( row, col ):
return self.squares(row*8+col) <---- I'd like this to be l-value
Then, from outside the class I want to:
board = ChessBoard()
board.square(0,0) = Piece( Shapes.ROOK, Colors.White ) <-- I'm getting an error here
board.square(0,1) = Piece( Shapes.BISHOP, Colors.White )
... etc.
So, I would like the function 'at' to return a lvalue (Something like a reference in C++), but I can't find anything resembling a reference or a pointer in the language. If I stored a list in each square containing one Piece, it is possible I could do something like: board.square(0,0)[0] = Piece - but it seems crazy (or maybe not - as I said, I'm new to the language).
How would you approach this data structure?
In Python, everything is a reference. The only problem is that None is immutable, so you can't use the returned reference to change the value.
You also can't override the assignment operator, so you won't get this particular kind of behaviour. However, a good and very flexible solution would be to override the __setitem__ and __getitem__ methods to implement the subscription operator ([]) for the class:
class ChessBoard(object):
def __init__(self):
self.squares = [None] * 64
def __setitem__(self, key, value):
row, col = key
self.squares[row*8 + col] = value
def __getitem__(self, key):
row, col = key
return self.squares[row*8 + col]
Usage:
>>> c = ChessBoard()
>>> c[1,2] = 5
>>> c[1,2]
5
You can try something like this, at the cost of having to put bogus [:] indexers around:
class Board:
def __init__(self):
self.squares=[None for x in range(64)]
def square(self, row, col):
squares=self.squares
class Prox:
def __getitem__(self, i):
return squares[row*8+col]
def __setitem__(self, i, v):
squares[row*8+col]=v
return Prox()
Then you can do
b=Board()
b.square(2,3)[:]=Piece('Knight')
if b.square(x,y)[:] == Piece('King') ...
And so on. It doesn't actually matter what you put in the []s, it just has to be something.
(Got the idea from the Proxies Perl6 uses to do this)
As Niklas points out, you can't return an l-value.
However, in addition to overriding subscription, you can also use properties (an application of descriptors: http://docs.python.org/howto/descriptor.html) to create an object attribute, which when read from, or assigned to, runs code.
(Not answering your question in the title, but your "How would you approach this data structure?" question:) A more pythonic solution for your data structure would be using a list of lists:
# define a function that generates an empty chess board
make_chess_board = lambda : [[None for x in xrange(8)] for y in xrange(8)]
# grab an instance
b = make_chess_board()
# play the game!
b[0][0] = Piece(Shapes.ROOK, Colors.White)
b[0][1] = Piece(Shapes.BISHOP, Colors.White)
# Or use tuples:
b[0][0] = (Shapes.ROOK, Colors.White)
b[0][1] = (Shapes.BISHOP, Colors.White)

How can I refactor these two functions to be more DRY?

I have the following two Python functions:
#classmethod
def serialize_dict(cls, d):
values = []
for column_name in cls().distinguishing_column_names():
value = str(d[column_name])
if value == 'None':
value = ''
values.append(value)
return ' '.join(values)
#classmethod
def serialize_row(cls, row):
values = []
for column_name in cls().distinguishing_column_names():
value = str(row.value(cls()._meta.db_table, column_name))
if value == 'None':
value = ''
values.append(value)
return ' '.join(values)
As you can see, the two functions are identical except for the first line of the for loop. Not very DRY. How could I refactor this code to take out all the repetitions, given that row and d are of different types (dict and a custom type of mine, respectively)?
Why don't you just implement the relevant bits of the dict interface in your custom type?
So that row[column_name] results in the code you want?
You use the __getitem__ special method for this.
Add an if isinstance(arg, dict) to determine whether to treat it as a row or dict, then merge the two methods together.
You could implement the function that serialise the bit into two different lambda functions that can then used as parameters of a single serialisation method:
ds = lambda d , cls , column_name : str(d[column_name])
rs = lambda d , cls , column_name : str(d.value(cls()._meta.db_table, column_name))
def __serialize(cls, d, ser):
values = []
for column_name in cls().distinguishing_column_names():
value = ser(d,cls,column_name)
if value == 'None':
value = ''
values.append(value)
return ' '.join(values)
#classmethod
def serialize_dict(cls, d):
return __serialize(cls, d, ds)
#classmethod
def serialize_row(cls, row):
return __serialize(cls, d, rs)
If the row instance can get hold of the name of its table, add a __ getitem __ method to make it behave like the dictionary. Otherwise, wrap it with a proxy object that knows the table name.

Categories