Python Object Oriented - python

I was kinda playing around with Object Oriented Programming in python and ran into an error i havent encountered before..:
class Main:
def __init__(self, a , b):
self.a = a
self.b = b
def even(self):
start = self.a
slut = self.b
while start <= slut:
if start % 2 == 0:
yield start
start += 1
def odd(self):
start = self.a
slut = self.b
while start <= slut:
if start % 2 != 0:
yield start
start += 1
def display():
evens = list(num.even())
odds = list(num.odd())
print(f"{evens}'\n'{odds}")
num = Main(20, 50)
Main.display()
Take a look at the last class method, where there shouldent be a 'self' as a parameter for the program to Work..Why is that? I thought every class method should include a 'self' as a parameter? The program wont work with it

There should be a self parameter, if it's intended to be an instance method, and you would get an error if you tried to use it as so, i.e., num.display().
However, you are calling it via the class, and Main.display simply returns the function itself, not an instance of method, so it works as-is.
Given that you use a specific instance of Main (namely, num) in the body, you should replace that with self:
def display(self):
evens = list(self.even())
odds = list(self.odd())
print(f"{evens}'\n'{odds}")
and invoke it with
num.display()

Related

Minus equal operator doesnt call property setter python

I have my code setup this way:
class Test():
def __init__(self):
self.offset = [0,0]
#property
def offset(self):
return self._offset
#offset.setter
def offset(self,offset):
print("set")
self._offset = offset
test = Test()
test.offset[1] -= 1
but the setter is being called only once even though I am changing my variable twice, anyone is able to help ?
test.offset[1] -= 1
This line of your code is calling the getter not the setter. You get the list from the test object and then you alter its contents.
Same as if you wrote:
v = test.offset # get the list
v[1] -= 1 # alter the contents of the list

Reference to integer as static variable inside python class

I'm trying to have a static int inside a class in python. But it doesn't work.
Here's an example of what I've implemented :
class MyDict(dict):
STR_DEPTH = -1
def __init__(self, **kwargs):
super(MyDict, self).__init__(**kwargs)
self.__dict__.update(name = kwargs.get("name", ""))
def __str__(self):
self.STR_DEPTH += 1
res = self.name + '\n'
for k in self.keys():
res += '\t'*self.STR_DEPTH + k + " = " + str(self[k])
res += '\n'
self.STR_DEPTH -= 1
return res
def main():
d1 = MyDict(one=MyDict())
d1["two"] = 2
d1["one"]["one"] = 1
d1["one"]["two"] = MyDict(three=3)
d1["four"] = 4
print d1
if __name__ == "__main__":
main()
and i'm expecting :
four = 4
two = 2
one =
two =
three = 3
one = 1
but it doesn't work that way. If i'm not mistaking, int aren't references and it's not the same "STR_DEPTH" in every instances of my class.
I already know the list-of-length-1 trick and the empty-type trick, but do i really need to resort do clumsy unreadable trick ?
Isn't there a better way since i'm inside a class ?
Where you have:
self.STR_DEPTH += 1
replace that with:
MyDict.STR_DEPTH += 1
and the same where you decrement the value.
Assigning to self.STR_DEPTH will create a new instance variable which hides access to the class variable through self. You can use self.STR_DEPTH to access the class variable provided you don't have an instance variable of the same name, but if you want to rebind the class variable you have to refer to it directly.
Note that self.STR_DEPTH += 1 is really just shorthand for self.STR_DEPTH = self.STR_DEPTH + 1 so even if the right hand self.STR_DEPTH picks up the class variable the assignment still happens back to the instance variable.

Instance count not incremented

I was practicing writing a class and ended up with this problem. I wrote a class that should return the value of the function after 5th instance is generated and do nothing for instances less than 5. I wrote the below code, but the instance count is not added every time I create an instance. The display in __init__ shows 1 for the first instance and after that the display is not there.. I would like to know what is that I am missing. I just felt like __init__ is not called after the first instance call. I checked by removing the 'IF' condition in the __call__ and every time the result of the function 10 is displayed but count is not increasing.
class After5(object):
call_count = 0
def __init__(self, funct):
After5.call_count += 1
print('Count{0}'.format(After5.call_count))
self.funct = funct
def __call__(self):
if After5.call_count > 5: #enter code here
res = self.funct()
print('{0}'.format(res))
print('Sending Results{0}'.format(After5.call_count))
return res
#After5
def dummy_funct():
return 5 * 2
dummy_funct()
dummy_funct()
dummy_funct()
dummy_funct()
dummy_funct()
dummy_funct()

Where to change a value so it applies to all methods in python?

I am struggling with a problem that didn't seem to be a big deal in the beginning. I am creating aa class and a sub Subclass and whenever I want to change a value in subclass it should automatically update all the other methods in the class and subclass whenever I do that. Let me give you an example. The value that's supposed to be changed is shift in the change.shift(shift) method.
class Message(object):
'''
code that doesn't matter for this question
'''
def build_shift_dict(self, shift):
'''
code that doesn't matter for this question
'''
return dict
def apply_shift(self, shift):
'''
code that doesn't matter for this question
'''
return newMessage
class PlaintextMessage(Message):
def __init__(self, text, shift):
'''
code that doesn't matter for this question
'''
Message.__init__(self, text)
self.shift = shift
self.encrypting_dict = self.build_shift_dict(self.get_shift())
self.message_text_encrypted = self.apply_shift(self.get_shift())
def get_shift(self):
'''
Used to safely access self.shift outside of the class
Returns: self.shift
'''
return self.shift
def get_encrypting_dict(self):
return self.encrypting_dict
def get_message_text_encrypted(self):
return self.message_text_encrypted
def change_shift(self, shift):
assert 0 <= shift < 26
self.shift = shift
As you can see I need shift to be changed as well within apply_shift(self, shift) and build_shift_dict(self, shift) because the init method in PlaintextMessage(Message) calls does methods. How do I do that? When I call the get_shift(self) method I get the shift value, if I then call the change_shift(self, shift) method and call get_shift(self) again it shows me the updated shift value. So I tried to update self.encrypting_dict = self.build_shift_dict(self.get_shift()) and self.message_text_encrypted = self.apply_shift(self.get_shift()) with the get-Method instead of shift but that doesn't change anything. What am I missing here? Thanks!
In change_shift() just call those other two methods.
def change_shift(self, shift):
assert 0 <= shift < 26
self.shift = shift
self.encrypting_dict = self.build_shift_dict(self.shift)
self.message_text_encrypted = self.apply_shift(self.shift)
You could define build_shift_dict and apply_shift without an argument, other than self, and just use self.shift in those methods - you would still have to call them but you wouldn't have to pass them anything, and you couldn't mess it up by passing those methods an erroneous value from your program.
You could make access to shift a property/attribute using the #property decorator - you won't have to call it and you rid yourself of getter's and setter's - you would need to rename shift to something like _shift or __shift everywhere else in the program.
like:
class Foo:
def __init__(self, shift):
self._shift = shift
#property
def shift(self):
return self._shift
f = Foo(2)
Then you access it with f.shift.

Python 2.7, what's the benefit of this kind of initialization in class?

class LogicGate(object):
def __init__(self, n):
self.label = n
self.output = None # ????????????
def getOutput(self):
self.output = self.performGateLogic()
return self.output
def getLabel(self):
return self.label
class BinaryGate(LogicGate):
def __init__(self, n): # ?????????????????
LogicGate.__init__(self, n)
self.pinA = None # ??????????????
self.pinB = None # ??????????????
def getPinA(self):
return int(raw_input('Enter Pin A input for gate' + self.getLabel() + '-->'))
def getPinB(self):
return int(raw_input('Enter Pin A input for gate' + self.getLabel() + '-->'))
class UnaryGate(LogicGate):
def __init__(self, n): # ??????????????
LogicGate.__init__(self, n)
self.pin = None # ?????????????
def getPin(self):
return int(raw_input('Enter Pin input for gate' + self.getLabel() + '-->'))
class AndGate(BinaryGate):
def __init__(self, n): # ????????????
BinaryGate.__init__(self, n)
def performGateLogic(self):
a = self.getPinA()
b = self.getPinB()
if a == 1 and b == 1:
return 1
else:
return 0
This code belongs to Problem Solving with Algorithms and Date Structures.
When I remove the lines before the comment '# ????????', the code can run normally.
Why does the author write the code like this?
Whether is it a good code style?
Can I always remove these lines before the comment '# ????????' ?
The author writes the code like that because it is good practice to never have uninitialised members and class parents, static checkers moan if you do.
The reason that it is not good practice is for future maintainability - let us say that the base class, LogicGate, was to gain a new property - say propagation_delay and a new method that allowed simulations to called get_response_time which relied on the current output state and the required, possibly new, state. If all the code that was derived from that class did the correct initialisations then it would all work fine, without any changes. If you remove those lines and such a new method was introduced you would have to go back through all of the child classes adding them back in before your final class would work for that method, with the chance that you would miss one.
Daft as it sounds doing things properly now is actually future laziness - it only takes you seconds when you are creating a class to make sure everything is initialised - debugging an uninitialised class can take hours.
First:
The __init__ functions are the constructors of the classes, you can read about them here.
Second:
Your code will run without those lines but the question is why and is it ok to remove them?
For example if you remove the following init
class UnaryGate(LogicGate): # LogicGate is the superclass
def __init__(self, n):
LogicGate.__init__(self, n)
The constructor of the super-class LogicGate will be called directly.
Third:
Ok, so can we remove the self.xxx = None?
class BinaryGate(LogicGate):
def __init__(self, n):
LogicGate.__init__(self, n)
self.pinA = None
self.pinB = None
We could remove those 2 Lines too but consider this code
bg = BinaryGate("binaryGate1")
print bg.pinA
This would throw an error because pinA is undefined.
If you do not remove the self.pinA = None in __init__ the code will run and None will be printed.

Categories