Polymorphism OOP : Instance of 'child' has no 'basic_attack' memberpylint (no-member) - oop

I'm trying to understand Polymorphism in OOP, i've built a monster parent class, from this main class you can inherit oarcs, wizards and giants..but the main attack method is coded in the parent monster class, and have only a string that is put in a variable name basic_attack
The problem is when i call this attack variable in oarcs, wizards or giants in the child classes, i get this error Instance of 'oarc' has no 'basic_attack' memberpylint(no-member)
please go easy on me and feel free to review my code below.
class monster:
def __init__(self, damage, speed, skill):
self.damage = damage
self.speed = speed
self.skill = skill
def attack(self):
basic_attack = "you've been attacked by "
return basic_attack
class oarc(monster):
def __init__(self, damage, speed, skill, oarc_data):
super().__init__(damage, speed, skill)
self.oarc_data = oarc_data
def attack(self):
return self.basic_attack + self.oarc_data
class wizard(monster):
def __init__(self, damage, speed, skill, wizard_data):
super().__init__(damage, speed, skill)
self.wizard_data = wizard_data
def attack(self):
return self.basic_attack + self.wizard_data
class giant(monster):
def __init__(self, damage, speed, skill, giant_data):
super().__init__(damage, speed, skill)
self.giant_data = giant_data
def attack(self):
return self.basic_attack + self.giant_data
oarc_object = oarc(56, 150, 'ugly', 'Oarc')
wizard_object = wizard(20, 100, 'fast', 'Wizard')
giant_object = giant(100, 20, 'strong', 'Giant')
list = [oarc_object, wizard_object, giant_object]
for each in list:
print(each.attack)
print(oarc_object.attack())

Ok, basically looks like self.basic_attack is never set. Could probably fix with self.basic_attack = basic_attack in def __init__() of class Monster.
The basic_attack = "you've been attacked by " under def attack() in class Monster is not the same as setting basic_attack. That basic_attack is constrained to the attack() function.
For example, let's abstract at non-OOP code;
# define a
a = 0
def test():
# define out
a = 2
# output out
return a
print(test())
>> 2
print(a)
>> 0
Now, if we did not redefine a in test():
# set a
a = 0
# define test
def test():
return a
print(test())
>> 0
print(a)
>> 0
Now if a was only defined within test();
# define test
def test():
# set a
a = 2
# output
return a
print(test())
>> 2
print(a)
>> NameError: name 'a' is not defined
Here's a short Intro to OOP in Python;
Quick & easy; Object-oriented Programming from the ground up with Examples from Pikachu and Bay Area Rapid Transit (BART)
And here's a bit more in-depth application of OOP to post to LinkedIn;
LinkedOut

Related

OOP Inheritance with DRY principles

Suppose I am writing a class of the form
class Base
def __init__(self):
self.a = 1
self.b = 2
def foo(self):
# ...
def bar(self):
# ...
And, I derive another class from Base called AdvancedBase. Normally, at least what I've seen in Java, etc..., we call the parent method first. For example...
class AdvancedBase(Base):
def __init__(self):
super().__init__()
self.c = 3
def foo(self):
super().foo()
def bar(self):
super().bar()
But, suppose that AdvancedBase needs to do a majority of a parent method, except in a different order. For example, AdvancedBase.__init__ should be like:
class AdvancedBase(Base):
def __init__(self):
self.a = 1
magical_v = do_magical_stuff()
self.b = magical_v
self.c = 3
What would be the preferred, DRY way to implement this? For example, suppose a later version of a protocol came out and a client library needed to support the later revision. Would it even be done in this is a/inheritance form?

How can i use Pool instead of Process & Pipe

I have a first tree class that does some calculations, and another forest class that contains trees and does more calculations.
The tree class uses the Pipe() connection mecanism to fit a tree : the resulting nodes and leaves need to be recv() by the tree.
The forest class, after fitting a certain number of tree, uses also the Pipe() connection mecanism to compute other things depending on the trees, which are also recv() by the forest.
When the number of tree rises in the forest, i am running into OSError : Too many open files and cant increase the ulimit since i have no root access on the machine where the code is running.
I am gessing that using Pool() will not have theese problems. But i do not understand how i can transmit information using Pool between child and main processes. For the moment, i use an idiom that looks like :
from multiprocessing import Pipe, Process
class tree:
def __init__(self):
self.random_number = 5 # Choosed by fair roll dice
def start_fit(self):
self.parent_conn, child_conn = Pipe(duplex=False)
self.process = tree_fitter(self.random_number, child_conn)
self.process.start()
return None
def join_fit(self):
self.fitting_result = self.parent_conn.recv()
self.process.join()
self.parent_conn.close()
del self.parent_conn
del self.process
return None
class tree_fitter(Process):
def __init__(self, random_number, connection):
self.connection = connection
self.new_randm_number = 2 # Choosed by fair roll dice
def run(self):
result = self.new_randm_number * random_number
self.connection.send(result)
self.connection.close()
return 0
class forest:
def __init__(self,n_trees):
self.n = n_trees # Number of trees
self.trees = [tree() for i in range(0,self.n)]
def compute_more_complicate_things(self):
processes = []
parents = []
results = []
for i in range(0,self.n):
self.trees[i].start_fit()
for i in range(0,self.n):
self.trees[i].join_fit()
parent_connection, child_connection = Pipe(duplex=False)
parents.append(parent_connection)
processes.append(forest_cumulative_mean(self, i,child_connection))
for i in range(0,self.n):
processes[i].start()
for i in range(0,self.n):
results.append(parents[i].recv())
processes[i].join()
parents[i].close()
print(i, end=" ")
del processes
del parents
del results
self.cumusum_of_result = results
class forest_cumulative_mean(Process):
def __init__(self, forest, i, connection):
self.trees = forest.trees[:i]
self.connection = connection
def run(self):
result = sum([t.result for t in self.trees])
self.connection.send(result)
self.connection.close()
return 0
1° How can i transform it to the Pool idiom without changing too much the structure of my code (this is of course a dummy example (i did not try to run it), i have a lot more code around it..).
2° Will this tackle the error i have about spanning too many processes ?

Python getter/setter for static class variable

I currently have some code like:
class Bird:
pass
class Swallow(Bird):
__max_airspeed_velocity = 10
def __init__(self, laden):
self.laden = laden
#property
def max_velocity(self):
return self.__max_airspeed_velocity
#property
def current_velocity(self):
if self.laden:
return self.__max_airspeed_velocity / 2
else:
return self.__max_airspeed_velocity
class Parrot(Bird):
__max_in_cage_velocity = 8
def __init__(self, dead):
self.dead = dead
#property
def max_velocity(self):
return self.__max_in_cage_velocity
#property
def current_velocity(self):
if self.dead:
return 0
else:
return self.__max_in_cage_velocity
swallow = Swallow(True)
parrot = Parrot(False)
# Direct variable access is fine
swallow.__max_airspeed_velocity # 10
Swallow.__max_airspeed_velocity # 10
# Getter only works on instance. I see that it references "self", but it only looks at a class variable.
# In practice, this is an obvious reason why it doesn't work. But in theory there should still be a way?
swallow.max_velocity # 10
Swallow.max_velocity # Error
Now let's say I wanted a function that compared birds. I sometimes want to ask about theoretical birds (the classes), and sometimes actual birds (instances).
def compare_max_velocity(bird1, bird2):
return bird1.max_velocity > bird2.max_velocity # only works on instances
compare_max_velocity(Swallow, Parrot) # can I do this using built-ins?
compare_max_velocity(swallow, parrot) # easy
Can I write this function using getters? Do I have to resort to making my own get_max_velocity() function (or direct variable access)?

Two Class instances in Python not different

I'm working on another data acquisition project, which has turned into an object oriented programming question. In “main” at the bottom of my code I make two instances of the Object DAQInput. When I wrote this, I thought my method .getData would refer to the taskHandle of the particular instance, but it does not. When I run, the code does the getData task with the first handle twice, so clearly I don’t really understand object oriented programming in Python. I’m sorry this code will not run without PyDAQmx and a National Instruments board attached.
from PyDAQmx import *
import numpy
class DAQInput:
# Declare variables passed by reference
taskHandle = TaskHandle()
read = int32()
data = numpy.zeros((10000,),dtype=numpy.float64)
sumi = [0,0,0,0,0,0,0,0,0,0]
def __init__(self, num_data, num_chan, channel, high, low):
""" This is init function that opens the channel"""
#Get the passed variables
self.num_data = num_data
self.channel = channel
self.high = high
self.low = low
self.num_chan = num_chan
# Create a task and configure a channel
DAQmxCreateTask(b"",byref(self.taskHandle))
DAQmxCreateAIThrmcplChan(self.taskHandle, self.channel, b"",
self.low, self.high,
DAQmx_Val_DegC,
DAQmx_Val_J_Type_TC,
DAQmx_Val_BuiltIn, 0, None)
# Start the task
DAQmxStartTask(self.taskHandle)
def getData(self):
""" This function gets the data from the board and calculates the average"""
print(self.taskHandle)
DAQmxReadAnalogF64(self.taskHandle, self.num_data, 10,
DAQmx_Val_GroupByChannel, self.data, 10000,
byref(self.read), None)
# Calculate the average of the values in data (could be several channels)
i = self.read.value
for j in range(self.num_chan):
self.sumi[j] = numpy.sum(self.data[j*i:(j+1)*i])/self.read.value
return self.sumi
def killTask(self):
""" This function kills the tasks"""
# If the task is still alive kill it
if self.taskHandle != 0:
DAQmxStopTask(self.taskHandle)
DAQmxClearTask(self.taskHandle)
if __name__ == '__main__':
myDaq1 = DAQInput(1, 4, b"cDAQ1Mod1/ai0:3", 200.0, 10.0)
myDaq2 = DAQInput(1, 4, b"cDAQ1Mod2/ai0:3", 200.0, 10.0)
result = myDaq1.getData()
print (result[0:4])
result2 = myDaq2.getData()
print (result2[0:4])
myDaq1.killTask()
myDaq2.killTask()
These variables:
class DAQInput:
# Declare variables passed by reference
taskHandle = TaskHandle()
read = int32()
data = numpy.zeros((10000,),dtype=numpy.float64)
sumi = [0,0,0,0,0,0,0,0,0,0]
Are class variables. They belong to the class itself and are shared among instances of the class (i.e. if you modify self.data in Instance1, Instace2's self.data is modified as well).
If you want them to be instance variables, define them in __init__.

"Pythonic" way to "reset" an object's variables?

("variables" here refers to "names", I think, not completely sure about the definition pythonistas use)
I have an object and some methods. These methods all need and all change the object's variables. How can I, in the most pythonic and in the best, respecting the techniques of OOP, way achieve to have the object variables used by the methods but also keep their original values for the other methods?
Should I copy the object everytime a method is called? Should I save the original values and have a reset() method to reset them everytime a method needs them? Or is there an even better way?
EDIT: I was asked for pseudocode. Since I am more interested in understanding the concept rather than just specifically solving the problem I am encountering I am going to try give an example:
class Player():
games = 0
points = 0
fouls = 0
rebounds = 0
assists = 0
turnovers = 0
steals = 0
def playCupGame(self):
# simulates a game and then assigns values to the variables, accordingly
self.points = K #just an example
def playLeagueGame(self):
# simulates a game and then assigns values to the variables, accordingly
self.points = Z #just an example
self.rebounds = W #example again
def playTrainingGame(self):
# simulates a game and then assigns values to the variables, accordingly
self.points = X #just an example
self.rebounds = Y #example again
The above is my class for a Player object (for the example assume he is a basketball one). This object has three different methods that all assign values to the players' statistics.
So, let's say the team has two league games and then a cup game. I'd have to make these calls:
p.playLeagueGame()
p.playLeagueGame()
p.playCupGame()
It's obvious that when the second and the third calls are made, the previously changed statistics of the player need to be reset. For that, I can either write a reset method that sets all the variables back to 0, or copy the object for every call I make. Or do something completely different.
That's where my question lays, what's the best approach, python and oop wise?
UPDATE: I am suspicious that I have superovercomplicated this and I can easily solve my problem by using local variables in the functions. However, what happens if I have a function inside another function, can I use locals of the outer one inside the inner one?
Not sure if it's "Pythonic" enough, but you can define a "resettable" decorator
for the __init__ method that creates a copy the object's __dict__ and adds a reset() method that switches the current __dict__ to the original one.
Edit - Here's an example implementation:
def resettable(f):
import copy
def __init_and_copy__(self, *args, **kwargs):
f(self, *args)
self.__original_dict__ = copy.deepcopy(self.__dict__)
def reset(o = self):
o.__dict__ = o.__original_dict__
self.reset = reset
return __init_and_copy__
class Point(object):
#resettable
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return "%d %d" % (self.x, self.y)
class LabeledPoint(Point):
#resettable
def __init__(self, x, y, label):
self.x = x
self.y = y
self.label = label
def __str__(self):
return "%d %d (%s)" % (self.x, self.y, self.label)
p = Point(1, 2)
print p # 1 2
p.x = 15
p.y = 25
print p # 15 25
p.reset()
print p # 1 2
p2 = LabeledPoint(1, 2, "Test")
print p2 # 1 2 (Test)
p2.x = 3
p2.label = "Test2"
print p2 # 3 2 (Test2)
p2.reset()
print p2 # 1 2 (Test)
Edit2: Added a test with inheritance
I'm not sure about "pythonic", but why not just create a reset method in your object that does whatever resetting is required? Call this method as part of your __init__ so you're not duplicating the data (ie: always (re)initialize it in one place -- the reset method)
I would create a default dict as a data member with all of the default values, then do __dict__.update(self.default) during __init__ and then again at some later point to pull all the values back.
More generally, you can use a __setattr__ hook to keep track of every variable that has been changed and later use that data to reset them.
Sounds like you want to know if your class should be an immutable object. The idea is that, once created, an immutable object can't/should't/would't be changed.
On Python, built-in types like int or tuple instances are immutable, enforced by the language:
>>> a=(1, 2, 3, 1, 2, 3)
>>> a[0] = 9
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
As another example, every time you add two integers a new instance is created:
>>> a=5000
>>> b=7000
>>> d=a+b
>>> d
12000
>>> id(d)
42882584
>>> d=a+b
>>> id(d)
42215680
The id() function returns the address of the int object 12000. And every time we add a+b a new 12000 object instance is created.
User defined immutable classes must be enforced manually, or simply done as a convention with a source code comment:
class X(object):
"""Immutable class. Don't change instance variables values!"""
def __init__(self, *args):
self._some_internal_value = ...
def some_operation(self, arg0):
new_instance = X(arg0 + ...)
new_instance._some_internal_operation(self._some_internal_value, 42)
return new_instance
def _some_internal_operation(self, a, b):
"""..."""
Either way, it's OK to create a new instance for every operation.
See the Memento Design Pattern if you want to restore previous state, or the Proxy Design Pattern if you want the object to seem pristine, as if just created. In any case, you need to put something between what's referenced, and it's state.
Please comment if you need some code, though I'm sure you'll find plenty on the web if you use the design pattern names as keywords.
# The Memento design pattern
class Scores(object):
...
class Player(object):
def __init__(self,...):
...
self.scores = None
self.history = []
self.reset()
def reset(self):
if (self.scores):
self.history.append(self.scores)
self.scores = Scores()
It sounds like overall your design needs some reworking. What about a PlayerGameStatistics class that would keep track of all that, and either a Player or a Game would hold a collection of these objects?
Also the code you show is a good start, but could you show more code that interacts with the Player class? I'm just having a hard time seeing why a single Player object should have PlayXGame methods -- does a single Player not interact with other Players when playing a game, or why does a specific Player play the game?
A simple reset method (called in __init__ and re-called when necessary) makes a lot of sense. But here's a solution that I think is interesting, if a bit over-engineered: create a context manager. I'm curious what people think about this...
from contextlib import contextmanager
#contextmanager
def resetting(resettable):
try:
resettable.setdef()
yield resettable
finally:
resettable.reset()
class Resetter(object):
def __init__(self, foo=5, bar=6):
self.foo = foo
self.bar = bar
def setdef(self):
self._foo = self.foo
self._bar = self.bar
def reset(self):
self.foo = self._foo
self.bar = self._bar
def method(self):
with resetting(self):
self.foo += self.bar
print self.foo
r = Resetter()
r.method() # prints 11
r.method() # still prints 11
To over-over-engineer, you could then create a #resetme decorator
def resetme(f):
def rf(self, *args, **kwargs):
with resetting(self):
f(self, *args, **kwargs)
return rf
So that instead of having to explicitly use with you could just use the decorator:
#resetme
def method(self):
self.foo += self.bar
print self.foo
I liked (and tried) the top answer from PaoloVictor. However, I found that it "reset" itself, i.e., if you called reset() a 2nd time it would throw an exception.
I found that it worked repeatably with the following implementation
def resettable(f):
import copy
def __init_and_copy__(self, *args, **kwargs):
f(self, *args, **kwargs)
def reset(o = self):
o.__dict__ = o.__original_dict__
o.__original_dict__ = copy.deepcopy(self.__dict__)
self.reset = reset
self.__original_dict__ = copy.deepcopy(self.__dict__)
return __init_and_copy__
It sounds to me like you need to rework your model to at least include a separate "PlayerGameStats" class.
Something along the lines of:
PlayerGameStats = collections.namedtuple("points fouls rebounds assists turnovers steals")
class Player():
def __init__(self):
self.cup_games = []
self.league_games = []
self.training_games = []
def playCupGame(self):
# simulates a game and then assigns values to the variables, accordingly
stats = PlayerGameStats(points, fouls, rebounds, assists, turnovers, steals)
self.cup_games.append(stats)
def playLeagueGame(self):
# simulates a game and then assigns values to the variables, accordingly
stats = PlayerGameStats(points, fouls, rebounds, assists, turnovers, steals)
self.league_games.append(stats)
def playTrainingGame(self):
# simulates a game and then assigns values to the variables, accordingly
stats = PlayerGameStats(points, fouls, rebounds, assists, turnovers, steals)
self.training_games.append(stats)
And to answer the question in your edit, yes nested functions can see variables stored in outer scopes. You can read more about that in the tutorial: http://docs.python.org/tutorial/classes.html#python-scopes-and-namespaces
thanks for the nice input, as I had kind of a similar problem. I'm solving it with a hook on the init method, since I'd like to be able to reset to whatever initial state an object had. Here's my code:
import copy
_tool_init_states = {}
def wrap_init(init_func):
def init_hook(inst, *args, **kws):
if inst not in _tool_init_states:
# if there is a class hierarchy, only the outer scope does work
_tool_init_states[inst] = None
res = init_func(inst, *args, **kws)
_tool_init_states[inst] = copy.deepcopy(inst.__dict__)
return res
else:
return init_func(inst, *args, **kws)
return init_hook
def reset(inst):
inst.__dict__.clear()
inst.__dict__.update(
copy.deepcopy(_tool_init_states[inst])
)
class _Resettable(type):
"""Wraps __init__ to store object _after_ init."""
def __new__(mcs, *more):
mcs = super(_Resetable, mcs).__new__(mcs, *more)
mcs.__init__ = wrap_init(mcs.__init__)
mcs.reset = reset
return mcs
class MyResettableClass(object):
__metaclass__ = Resettable
def __init__(self):
self.do_whatever = "you want,"
self.it_will_be = "resetted by calling reset()"
To update the initial state, you could build some method like reset(...) that writes data into _tool_init_states. I hope this helps somebody. If this is possible without a metaclass, please let me know.