I've written a script that solves sudoku problems.
To model each slot of a grid, I have in a first time defined Slot and Grid classes like this (complete code elipsed for the sake of simplicity :
class Slot():
def __init__(self,grid):
self.grid = grid
self.values = list(range(9))
def pos(self):
return self.grid.index(self)
class Grid(list):
def __init__(self):
for i in range(9*9):
self.append(Slot(self))
Like this, I can define method for my Slot class using self.pos() and self.values(). For example :
g = Grid()
g[5].pos() -> returns 5, OK !
Now that my full script works just fine, I want to refactor it, and, as a Slot is basically a list belonging to a Grid, I decided it would be great for my Slot to subclass list, like this :
class Slot(list):
def __init__(self,grid):
self.grid = grid
self.append(list(range(9)))
def pos(self):
return self.grid.index(self)
class Grid(list):
def __init__(self):
for i in range(9*9):
self.append(Slot(self))
g = Grid()
g.index(g[5]) -> returns 0, KO !
I've tried to init the list first ie: super().init(list(range(9)), and also a few variations, but nothing seems to work.
What am I missing ?
PS : the g.index(g[5]) is just to describe, I'm aware it's pointless. I'm using this logic in methods inside my objects (self.pos(), etc.)
By making Slot a subclass of list you also make the comparison between Slot instances use the logic defined for lists (since you haven't overridden that).
Since all Slots contain the same value:
self.append(list(range(9)))
g.index() will simply match the first entry the grid yielding 0 as the result.
When you inherited from object (as Slot did in your first example) all instances compared unequal to themselves as is defined in the Python Reference (unless logic is implemented that dictates otherwise).
In short, you'll need to redefine the comparison methods if you need the slots with similar items to be treated differently when compared. In addition to that, you might want to reconsider sub classing from list and, instead, opt for UserList from collections.
Related
I am currently working on the 3.2.1.10 A short journey from procedural to object approachlab from edube.org, course (Python Essentials 2 (Intermediate, v.2.0).
The task is about programming a stack in object oriented style. We have a push and a pop method so far and a simple stack we can fill and take away the last item. Now it should be extended to be able to display the sum of the values in the stack. The complete code given in the lab is as follows:
class Stack:
def __init__(self):
self.__stack_list = []
def push(self, val):
self.__stack_list.append(val)
def pop(self):
val = self.__stack_list[-1]
del self.__stack_list[-1]
return val
class AddingStack(Stack):
def __init__(self):
Stack.__init__(self)
self.__sum = 0
def get_sum(self):
return self.__sum
def push(self, val):
self.__sum += val
Stack.push(self, val)
def pop(self):
val = Stack.pop(self)
self.__sum -= val
return val
stack_object = AddingStack()
for i in range(5):
stack_object.push(i)
print(stack_object.get_sum())
for i in range(5):
print(stack_object.pop())
The code works. As an explanation for using class AddingStack(Stack) it says:
We don't want to modify the previously defined stack. It's already
good enough in its applications, and we don't want it changed in any
way. We want a new stack with new capabilities. In other words, we
want to construct a subclass of the already existing Stack class.
The first step is easy: just define a new subclass pointing to the
class which will be used as the superclass.
This is what it looks like: class AddingStack(Stack):
pass
The class doesn't define any new component yet, but that doesn't mean
that it's empty. It gets all the components defined by its superclass
However, when I run the same code, but just modify the line to:
class AddingStack():
it still works. I don't understand what the benefit of class AddingStack(Stack) is?
However, when I run the same code, but just modify the line to:
class AddingStack():
it still works. I don't understand what the benefit of class AddingStack(Stack) is?
It still works because the methods in AddingStack explicitly call other methods in Stack.
You aren't actually using any inherited methods, which defeats the entire point of inheritance.
Usually the benefit from inheritance in OOP is the ability to crate a class from an existing class, and modify it a bit with ease.
If you really just override every single function in the super-class, then no, don’t use inheritance, it won’t benefit you nothing.
It is very useful in cases when you have a sub-class that only change some of the functions and the things from the super-class, and the rest, will be using the super-class functions.
It works because you are calculating the sum without actually using the elements of the stack, instead accumulating the result in the __sum variable.
You are also not using inheritance, instead delegating to the pop() and push() methods of class Stack.
The objective of the exercise seems to be for you to add up the elements of the stack (which is already implemented in the superclass) and to implement get_sum() such that you iterate through the list of values on the stack and add them up.
I've got two class trees in my Python code:
BaseComponent BaseSeries
/ | \ |
Resistor Capacitor Inductor ESeries
The BaseSeries class tree implements preferred numbers such as the E-series, and generates sets of values between a pair of powers (e.g. [1.0, 2.2, 4.7, 10, 22, 47, 100, 220, 470] for the E3 series with exponents between 1 to 3).
By default, ESeries and any other instance of BaseSeries creates sequences of float objects. I'd like to use these classes to instead create sequences of Resistor, Capacitor and Inductor objects. Ideally, the individual Resistor, Capacitor, Inductor and ESeries classes would remain usable on their own (i.e. not rely on methods being implemented by other classes).
This sounds like a job for multiple inheritance, but I'm a bit confused about how best to implement this in Python (3). Ideally I'd like to just define something like:
class ResistorESeries(Resistor, ESeries):
pass
class CapacitorESeries(Capacitor, ESeries):
pass
class InductorESeries(Inductor, ESeries):
pass
in order to create classes that yield sequences of resistors, capacitors and inductors, but I don't know how best to tell BaseSeries instances to create objects of type Resistor, Capacitor and Inductor. I can think of two ways, but I can't decide which one is best, and I have a feeling there is a simpler, more Pythonic way that I'm missing:
have BaseSeries contain a property or variable pointing to the element type (e.g. Resistor) set either by the constructor, a class variable in the child class (e.g. Resistor.ELEMENT_TYPE = Resistor) or with an abstract property provided by the child class:
class BaseSeries(object):
...
def elements(self):
# loop over numbers in this series
for v in self.values():
yield self.element_type(v)
#property
#abc.abstractmethod
def element_type(self):
return NotImplemented
class ESeries(BaseSeries):
....
class BaseComponent(object):
...
#property
def element_type(self):
return self
class Resistor(BaseComponent):
...
class ResistorESeries(Resistor, ESeries):
# now BaseSeries' `element_type` property is provided by `BaseComponent`
pass
This would mean ESeries cannot be used on its own as a concrete object, as it does not implement this property/variable, which is not ideal.
use self when creating elements in BaseSeries, where self will, as long as Resistor is earlier in the method resolution order, refer to the desired element:
class BaseSeries(object):
...
def elements(self):
# loop over numbers in this series
for v in self.values():
# self here would refer to `Resistor` in
# `ResistorESeries` instances
yield self(v)
class ESeries(BaseSeries):
....
class BaseComponent(object):
...
class Resistor(BaseComponent):
...
class ResistorESeries(Resistor, ESeries):
pass
This has the downside that, in instances of ESeries without being used as a mix-in, self will refer to itself, which does not support the correct __init__ signature.
So, does anyone have an idea of how best to do this in a Pythonic way, with maximum ability to reuse classes on their own?
You are likely mixing some concepts there - notably "instances" and "classes" - your example calls that do self(v) are perplexing.
I can't see from your design why the classes on the BaseComponent tree would need to be inherited along the BaseSeries tree: can't the component type simply be an attribute on the BaseSeries class?
It is simply a matter of using a class attribute, and in the code suggested on your first attempt, use a prosaic if statement.
class BaseSeries:
component = None
def elements(self):
# loop over numbers in this series
for v in self.values():
yield self.component(v) if self.component else v
class Capacitor(BaseComponent):
...
class CapacitorSeries(BaseSeries):
component = Capacitor
If you think you need multiple inheritance, you can just go for your idea of using a property, and use the same "if" statement there. But if both hierarchies are that ortogonal, I don't see why force the use of multiple inheritance, just because the language permits it.
Maybe you prefer to have it the other way around: a factory method on the component tree that will take an ESeries class as input, and extract the values from that ...
Anyway, you are not making clear the disctinction of classes and instances there. Do you need to have a way to produce several subclasses of
"CapacitorESeries", each class for a different value?
Or would you need just instances of "Capacitors", each for a different value produced on the series?
class BaseComponent:
...
#classmethod
def series_factory(self, series):
for value in series.values():
yield self.__class__(value)
Of course, there could be use cases for really needing classes for everything you claim, including the factories for series of classes, but your use of self as a callable in your snippets suggests that your stance on that is not that solid.
In that case, first, you need all methods to make proper use of super. even if they ar enot supposed to exist across both hierarchies, using super will just call the proper method on the superclasses. But for methods like __init__ this is just needed.
If you design a proper __init__ method using super, and always using named parameters, your second strategy will work out of the box, just fixing the instantiating call (to something other than self(v). Using named parameters and passing the remaining parameters to super will ensure each class in the tree consumes what it needs of those parameters - and when Python gets to the root of both your hierarchies and calls object's __init__, no parameter is remaining,
class BaseSeries:
def __init__(self, value_min, value_max, **kwargs):
self.value_min = value_min
selfvalue_max = value_max
super().__init__(**kwargs)
def elements(self):
# loop over numbers in this series
for v in self.values():
yield self.__class__(value_min = self.value_min, value_max=self.value_max, value=value)
class BaseComponent:
def __init__(self, value, **kwargs):
self.value = value
...
class CapacitorESeries(Capacitor, Eseries):
pass
For an assignment I got from school we need to make a chess game. One task is that we need to make a class called chessboard with a couple of methods like place, delete and replace.
My chessboard is a dictionary with the keys as place, in the form of a tuple, and the value as the chess-piece as value. But if I want to give a tuple as argument to my methods it fails.
This is my code:
class ChessBoard:
def __init__(self):
DICT={ (A,1):None,(A,2):None,(A,3):None,(A,4):None,(A,5):None,(A,6):None,(A,7):None,(A,8):None,
(B,1):None,(B,2):None,(B,3):None,(B,4):None,(B,5):None,(B,6):None,(B,7):None,(B,8):None,
(C,1):None,(C,2):None,(C,3):None,(C,4):None,(C,5):None,(C,6):None,(C,7):None,(C,8):None,
(D,1):None,(D,2):None,(D,3):None,(D,4):None,(D,5):None,(D,6):None,(D,7):None,(D,8):None,
(E,1):None,(E,2):None,(E,3):None,(E,4):None,(E,5):None,(E,6):None,(E,7):None,(E,8):None,
(F,1):None,(F,2):None,(F,3):None,(F,4):None,(F,5):None,(F,6):None,(F,7):None,(F,8):None,
(G,1):None,(G,2):None,(G,3):None,(G,4):None,(G,5):None,(G,6):None,(G,7):None,(G,8):None,
(H,1):None,(H,2):None,(H,3):None,(H,4):None,(H,5):None,(H,6):None,(H,7):None,(H,8):None }
def place(self, piece,(row,column)):
self.piece=piece
self.(row,column)=(row,column)
DICT[(row,column)]=self.piece
You are not creating an instance attribute out of your DICT attribute in your init. To set it as an instance attribute you need to add it to your instance as self.DICT
So, your init should looking something like this:
# not showing your full dictionary:
def __init__(self):
self.DICT={ (A,1):None,(A,2):None}
Now, in your other instance methods, you simply access accordingly, as an instance attribute. You are placing a piece at a location, so you seem like you are wanting to set self.piece at row,column. Furthermore, I don't know how your other code looks like, but if your piece argument you are passing in to your place method is only being used in that method, you do not need to set it as an instance attribute.
So, to fix your problem, you can do this:
def place(self, piece,(row,column)):
self.piece=piece
self.DICT[(row,column)]=self.piece
If you in fact are not using piece anywhere else in your code, don't set it as an instance attribute, and you can simply do:
def place(self, piece,(row,column)):
self.DICT[(row,column)] = piece
I think this is what you are trying to achieve,
def place(self, piece, row_column_tuple):
self.piece=piece
self.row_column_tuple=row_column_tuple
DICT[row_column_tuple]=self.piece
Then elsewhere in the code you can call this method like
place(piece, (row, column))
I have a program that loops over a list and then performs a function on the list. The result that is getting returned from the function is different depending on whether I loop over several observations versus just one. For example when I put in the 10th observation by itself, I get one result but when I put in 9 and 10 and loop over them I get a different answer for 10. The only thing I can come up with is that there is some variable in storage that is leftover from performing the function on 9 that is leading to something different for 10. Here's the code for the loop:
for i, k in enumerate(Compobs):
print i+1, ' of ', len(Compobs)
print Compobs[i]
Compobs[i] = Filing(k[0],k[1])
Compobs is just a list like this:
[['355300', '19990531'],[...],...]
The function Filing is from another .py file that I import. It defines a new class, Filing() and performs a bunch of functions on each observation and ultimately returns some output. I'm fairly new to python so I'm at a bit of a loss here. I could post the Filing.py code, but that's over 1,000 lines of code.
Here's the Filing class and the init.
class Filing(object):
cik =''
datadate=''
potentialpaths=[]
potential_files=[]
filingPath =''
filingType=''
reportPeriod=''
filingText=''
current_folder=''
compData=pd.Series()
potentialtablenumbers=[]
tables=[]
statementOfCashFlows=''
parsedstatementOfCashFlows=[]
denomination=''
cashFlowDictionary ={}
CFdataDictionary=OrderedDict()
CFsectionindex=pd.Series()
cfDataSeries=pd.Series()
cfMapping=pd.DataFrame()
compCFSeries=pd.Series()
cftablenumber=''
CompleteCF=pd.DataFrame()
def __init__(self,cik,datadate):
self.cik=cik
self.datadate=datadate
self.pydate=date(int(datadate[0:4]),int(datadate[4:6]),int(datadate[6:8]))
self.findpathstofiling()
self.selectfiling()
self.extractFilingType()
self.extractFilingText()
self.getCompData()
self.findPotentialStatementOfCashFlows()
self.findStatementOfCashFlows()
self.cleanUpCashFlowTable()
self.createCashFlowDictionary()
self.extractCFdataDictionary()
self.createCFdataSeries()
self.identifySections()
self.createMapping()
self.findOthers()
Shouldn't all the variables in the Filing.py get cleared out of memory each time it is called? Is there something I'm missing?
All of the lists, dicts, and other objects defined at the top level of Filing have only one copy. Even if you explicitly assign them to an instance, that copy is shared (and if you don't explicitly assign them, they're inherited). The point is that if you modify them in one instance, you modify them in all instances.
If you want each instance to have its own copy, then get rid of the top-level assignments altogether, and instead assign new instances of the objects in __init__.
In other words, don't do this:
class Foo(object):
x = []
def __init__(self):
self.x = x
Instead, do this:
class Foo(object):
def __init__(self):
self.x = []
Then each instance will have its own, unshared copy of x.
You are defining your class data members as class attributes, not object attributes. They are like static data member of a C++ or Java class.
To fix this, you need to not define them above the __init__ method, but instead, define them in the __init__ method. For example, instead of
tables = []
above __init__ you should have:
self.tables = []
in __init__
I want to create an object which will hold other objects, and call a method on each of the objects it holds. The end goal is to generate a script for a program. Each object contains a command that can be printed with printCommand(), eventually into a file. My original solution was this:
a = ObjectList()
a.appendObject(Object())
b = ObjectList()
b.appendObject(Object())
listOfObjects = [a, b]
for Object in listOfObjects:
Object.printCommand()
I create a list variable, add objects to thw list, then loop over it issuing the command. While this works, I am primarily doing this excersize to teach myself programming, so I want to know if there is a more elegant solution than writing code to append, pop, etc. items to a list in an object. Since list already contains these functions, i was thinking the correct thing to do would be to extend list:
class Object:
def __init__(self):
self.Command = "Script Command"
def printCommand(self):
print(self.Command)
class ObjectList(list):
def printCommand(self):
for Object in self.LISTCONTENTS:
Object.printCommand()
However, I am at a loss as to how I would tell it to iterate over its own contents. What belongs at self.LISTCONTENTS? Where does a list object store its contents, and how do you access them from a method?
You can just iterate over self:
The superclass methods (i.e., __iter__()) are all present. Saying self in the context of a for statement will cause the appropriate methods to be invoked.
class Object:
def __init__(self):
self.Command = "Script Command"
def printCommand(self):
print(self.Command)
class ObjectList(list):
def printCommand(self):
for Object in self:
Object.printCommand()
lst = ObjectList()
lst.append(Object())
lst.append(Object())
lst.printCommand()
The way this works is list implements __iter__ which is called behind the scenes when iterating over an object:
>>> for e in [1,2,3].__iter__():
... print(e)
...
1
2
3
>>> for e in [1,2,3]:
... print(e)
...
1
2
3
(a) Don't ever create a class called Object, that's far too close to object.
(b) There is absolutely no need to inherit from list, and frankly I doubt the need to use your own class at all.
(c) The normal way to invoke a function on every element of a list is to use map. If you need to map with the same function repeatedly, you can use partial to bind that function to map's first argument.
Now go look at the documentation.