defining a variable in a class [duplicate] - python

This question already has answers here:
How can I access "static" class variables within methods?
(6 answers)
Closed 2 years ago.
I am trying to place a method in a class that will replace null values with running average of non null values. Please refer to the code below:
class ElNinoData(object):
# Your implementation here
add = 0
counter = 0
average = 0
# methods
def __init__(self , object):
self.object = object
def get_humidity(self):
if not math.isnan(self.object['humidity']):
global add
global counter
global average
add += self.object['humidity']
counter += 1
average = add/counter
else:
self.object['humidity'] = average
return self.object['humidity']
While executing this class in a method, I am getting the following error:
<ipython-input-40-c52c3ac6484b> in get_humidity(self)
19 global average
20
---> 21 add += self.object['humidity']
22 counter += 1
23 average = add/counter
NameError: name 'add' is not defined
Could anyone please explain the error,I am relatively new to python?

class ElNinoData(object):
add = 0
The add here is not a global variable,
global add
therefore this does not give access to it, but instead looks for that actual global.
add += self.object['humidity']
+= requires the variable to exist already (so that the old value can be added to), and you don't have a global add, nor a local one - you have a class attribute.
To access it directly, you can use ElNinoData.add, just as you would from code outside the class. Similarly for the other class attributes.
Looking up the class attribute via the instance - self.add - also succeeds. However, modifying the value then attaches a separate attribute to the instance, and leaves the class attribute unaffected.

If you want the members to be specific to an object, change it to this
class ElNinoData(object):
# Nothing here
# methods
def __init__(self , object):
self.add = 0
self.counter = 0
self.average = 0
self.object = object
and continue to refer to them with self..
If you want them to be class-wide, leave them where they are, but refer to them via ElNinoData..
In any case, you shouldn't use global here.

I think the problem is that your values add, counter and average are not global.
In order to set these values on your class instance, you have to use self instead.
Something like this:
def get_humidity(self):
if not math.isnan(self.object['humidity']):
self.add += self.object['humidity']
self.counter += 1
self.average = add/counter
else:
self.object['humidity'] = average
return self.object['humidity']

What you are missing here is that you have initialized the variables but not given them any values and then you are adding the values using +=, due to which python is throwing you this error.
Refer to the below code:-
class ElNinoData(object):
# Your implementation here
add = 0
counter = 0
average = 0
# methods
def __init__(self , object):
self.object = object
def get_humidity(self):
if not math.isnan(self.object['humidity']):
global add
global counter
global average
add = 0
counter = 1
add += self.object['humidity']
counter += 1
average = add/counter
else:
self.object['humidity'] = average
return self.object['humidity']
t = {'humidity' : 10}
a =ElNinoData(t)
a.get_humidity()

Related

Python PNL OOP, how to use attribute from another class

I am planning to design a program to track profit and loss of my stock account, then I used Python and hope to solve it in a Object Oriented way.
Code:
class PNL(object):
stock_amount = {}
def __init__(self,cash,position):
self.cash = cash
self.position = position
def buy(self,Stock,amount):
pass
def sell(self,Stock,amount):
pass
def stock_amt(self,Stock):
if Stock().symbol not in stock_amount:
stock_amount[Stock().symbol] = 0
else:
return stock_amount
class Stock():
def __init__(self,symbol,timestamp,price):
self.symbol = symbol
self.time = timestamp
self.price = price
a = PNL(0,0)
APPL = []
APPL.append(Stock('APPL',0,10))
APPL.append(Stock('APPL',1,12))
a.stock_amt('APPL')
for stock in APPL:
if stock.time == 0:
print stock.price
But this doesn't work fine, anyone has idea on that?
Firstly you need to fix the class PNL, when you declare the methods with Stock, as its an argument/parameter, you'd better choose another name, or write it in lowercase to make difference with the class Stock.
Just think you will give an instance to these methods, no need to write the type, and by the way, no need to instantiate again the class inside the method by doing Stock().symbol, you'll give an instance, or directly the attribute symbol if you prefer.
Also, the stock_amount can be stored as a instance attribute, as below :
class PNL(object):
def __init__(self,cash,position):
self.cash = cash
self.position = position
self.stock_amount = {}
def buy(self,stock,amount):
pass
def sell(self,stock,amount):
pass
def stock_amt(self,stock):
if stock.symbol not in self.stock_amount:
self.stock_amount[stock.symbol] = 0
else:
return self.stock_amount
Then when you call your classes, i think you wanted to loop on the list APPL you've built (then just call a.stock_amt(stock_object_created) :
a = PNL(0,0)
APPL = []
APPL.append(Stock('APPL1',0,10))
APPL.append(Stock('APPL2',1,12))
for stock in APPL:
a.stock_amt(stock)
if stock.time == 0:
print stock.price
print a.stock_amount
#>>>10
#>>>{'APPL2': 0, 'APPL1': 0}

Python pass a class reference to another class during construction

I'm intending to create a data distributor class as a mutable class:
class DataDistributor(object):
def __init__(self):
self.target_trackid = -1
def next_sen(self):
self.target_trackid += 1
return self.target_trackid
So that I can globally keep a pointer on my data.
I have another class:
class Env(object):
def __init__(self, distributor):
self.distributor = distributor
self.target_trackid = 0 # init
def reset(self):
self.target_trackid = self.distributor.next_sen()
So that when I create many Env instances, each Env instance will get a different data point.
So I use this to create my instances:
ddist = DataDistributor()
env = Env(ddist)
envs = [pickle.loads(pickle.dumps(env)) for _ in range(12)]
envs[0].reset()
envs[1].reset()
envs[2].reset()
print envs[0].target_trackid
print envs[1].target_trackid
print envs[2].target_trackid
And the results are all the same: a bunch of 0s.
I'm not exactly sure how Python is handling this :( and if there is a viable solution to achieve what I want to achieve!
How about creating a class variable for keeping track of the objects created? Your simple class structure will be like:
class Env(object):
my_counter = 0 # Your class variable
def __init__(self, param1, param2):
# some initialization
Env.my_counter += 1 # increament everytime object is created
# some logic
Sample run:
>>> e1 = Env('p11', 'p12') # creation of first object
>>> Env.my_counter
1 # value of counter set as 1
>>> e1 = Env('p21', '22') # creation of second object
>>> Env.my_counter
2 # value of counter set as 2
Passing object of different class just for tracking the created object of some other class, it is definitely not the right approach.
pickle.load will create different objects which means the datadistributor variable in each env object will refere

Access class variables with same function

I want to create a function within a class that can access two different members with the same function. For example in the code below, I want both of the lines below to use the 'apply' function on different variables in the class
print(state.apply(rate))
print(state.apply(wage))
I had thought if I put in a dummy variable in the function definition (called exposure), it would replace it with the variables passed to the function (rate and wage in the example below). What is the correct way of doing this in python 3?
class State():
def __init__(self):
self.rate = 0
self.wage = 0
def apply(self, exposure):
self.exposure = self.exposure - 1
return self.exposure
state = State()
rate = State.rate
wage = State.wage
print(state.apply(rate))
print(state.apply(wage))
EDIT: I had made a typo where I had State instead of state in each print statement. I have now corrected this
This would be the only way:
class State:
def __init__ (self):
self.rate = 0
self.wage = 0
def apply (self, exposure):
setattr(self, exposure, getattr(self, exposure) - 1)
return getattr(self, exposure)
>>> state = State()
>>> print(state.apply('rate'))
-1
>>> print(state.apply('wage'))
-1
>>> print(state.apply('wage'))
-2
Note that those are instance variables, so you cannot access them using the type, State, but only using the object, state.
However, I would say, that whatever you are trying, you’re doing it wrong. If you describe your actual problem, we may be able to suggest a way better solution for it instead.

Get the return value from a function in a class in Python

I am trying to simply get the value out of my class using a simple function with a return value, I'm sure its a trivial error, but im pretty new to python
I have a simply class set up like this:
class score():
#initialize the score info
def __init__(self):
self.score = 0
self.num_enemies = 5
self.num_lives = 3
# Score Info
def setScore(num):
self.score = num
# Enemy Info
def getEnemies():
return self.num_enemies
# Lives Info
def getLives():
return self.getLives
etc.....
Than I create an instance of the class as such:
scoreObj = score()
for enemies in range(0, scoreObj.getEnemies):
enemy_sprite.add(enemy())
I get the error saying that an integer is expected, but it got an instancemethod
What is the correct way to get this information?
Thanks!
scoreObj.getEnemies is a reference to the method. If you want to call it you need parentheses: scoreObj.getEnemies().
You should think about why you are using a method for this instead of just reading self.num_enemies directly. There is no need for trivial getter/setter methods like this in Python.
The first parameter for a member function in python is a reference back to the Object.
Traditionally you call it "self", but no matter what you call the first parameter, it refers back to the "self" object:
Anytime I get weird errors about the type of a parameter in python, I check to see if I forgot the self param. Been bit by this bug a few times.
class score():
#initialize the score info
def __init__(self):
self.score = 0
self.num_enemies = 5
self.num_lives = 3
# Score Info
def setScore(self, num):
self.score = num
# Enemy Info
def getEnemies(self):
return self.num_enemies
# Lives Info
def getLives(foo): #foo is still the same object as self!!
return foo.num_lives
#Works but don't do this because it is confusing
This code works:
class score():
def __init__(self):
self.score = 0
self.num_enemies = 5
self.num_lives = 3
def setScore(self, num):
self.score = num
def getEnemies(self):
return self.num_enemies
def getLives(self):
return self.getLives
scoreObj = score()
for enemy_num in range(0, scoreObj.getEnemies()):
print enemy_num
# I don't know what enemy_sprite is, but
# I commented it out and just print the enemy_num result.
# enemy_sprite.add(enemy())
Lesson Learned:
Class functions must always take one parameter, self.
That's because when you call a function within the class, you always call it with the class name as the calling object, such as:
scoreObj = score()
scoreObj.getEnemies()
Where x is the class object, which will be passed to getEnemies() as the root object, meaning the first parameter sent to the class.
Secondly, when calling functions within a class (or at all), always end with () since that's the definition of calling something in Python.
Then, ask yourself, "Why am I not fetching 'scoreObj.num_lives' just like so instead? Am I saving processing power?" Do as you choose, but it would go faster if you get the values directly from the class object, unless you want to calculate stuff at the same time. Then your logic makes perfect sense!
You made a simple mistake:
scoreObj.getEnemies()
getEnemies is a function, so call it like any other function scoreObj.getEnemies()

Python instance attribute takes initial value from class attribute with the same name?

class bambino(object):
counter = 7
def __init__(self):
print("bambino.counter is self.counter ?", bambino.counter is self.counter)
self.counter += 1
print("bambino.counter is self.counter ?", bambino.counter is self.counter)
bambi1 = bambino()
print ("bambi1.counter:", bambi1.counter)
print ("bambino.counter:", bambino.counter)
prints:
bambino.counter is self.counter ? True
bambino.counter is self.counter ? False
bambi1.counter: 8
bambino.counter: 7
I understand that by doing self.counter += 1 counter becomes an attribute of the instance not of the class.
But why did bambi1.counter take it's initial value from bambino.counter?
If an attribute is not found in an object, it gets looked up higher in the hierarchy, first in its class, and then, if not found, in the superclasses.
self.counter += 1 is equivalent to self.counter = self.counter + 1. So to assign the bambi1.counter, Python first needs to get the value of bambi1.counter. Since the bambi1 does not initially have a counter, python doesn't find it and has to look it up in its class.
PS: Please capitalize your class names.

Categories

Resources