Python Class - required positional Argument - python-3.x

I am a bit confused what exactly is wrong in here. I've seen plenty of questions about below error but still can't find the right answer for my code. I am just starting with classes in Python and I wanted to decode a bit ( I got 5 different functions for different type of API data).
class Weather:
def __init__(self, R):
self.R = R = requests.get(
"http://api.openweathermap.org/data/2.5/weather?q=" + CITY + "," + COUNTRY + "&appid=xxx")
def temp(self):
"""Temp function with conversion to C degree"""
JSON_OBJECT = self.R.json()
TEMP_K = (JSON_OBJECT["main"]["temp"])
TEMP_C = TEMP_K - 273.15
return (TEMP_C)
Idea is to put those 2 into "variables" to avoid repetition:
requests.get(
"http://api.openweathermap.org/data/2.5/weather?q=" + CITY + "," + COUNTRY + "&appid=xxx")
JSON_OBJECT = self.R.json()
My error looks like that:
TypeError: temp() missing 1 required positional argument: 'self'
This is the line where error appears:
print("Current tempreture in {} is: {} C.".format(CITY, Weather.temp()))

You have defined temp as a method of the Weather class.
That means you should call it from an instance of the Weather class.
In this case, I would suggest not using a class at all.
A general piece of Python wisdom states that if you have a class with two methods, one of which is __init__, then you basically have a function. So use a function:
import requests
def get_weather_json(city, country):
R = requests.get("http://api.openweathermap.org/data/2.5/weather?q=" + city + "," + country + "&appid=xxx")
return R.json()

Related

How to use str(x) to call a variable

im coding a game, and i have Square class
class Square:
def __init__(self, name, pos) -> None:
self.name = name
self.pos = pos #pos is (x,y)
self.unit = None
when i create a Square i give it the name Square+"x"+"y" using :
Square(("square"+str(x)+str(y)), (x,y))
But i dont know how to call this object. Let's say i want to change the unit that is on this square, i'd like to do
square+str(x)+str(y).unit = warrior
or something of the sort. How do use str(x) and str(y) to call my object?
I tried doing
square+str(x)+str(y).unit = warrior
but of cours square is not a string and cannot be added to strings.
"square"+str(x)+str(y).unit = warrior
obviously does not work either.
So i tried changing the name, to ("square", str(x)+str(y)) But then if i try to give my unit a square :
unit.square = ("square",str(x)+str(y))
this will not call the Square object, it is giving an attribute to my unit that is a pair of strings.
To sumarize, id like to be able to do :
for x in range(n):
for y in range(n):
square + str(x) + str(y) = Square(name, (x,y))
square + str(x) + str(y).unit = warrior
I suggest a bit of reading from w3schools to understand python objects.
In short you initialize an object by calling its class name and storing it into a variable.
I also suggest to use a bit more variable to make your code more readable.
//store the name
squareName = "square" + str(x) + str(y)
//store the "Square" object
mySquare = Square(squareName, (x,y))
//Change the property "unit"
mySquare.unit = newUnit

Calling a method inside another method within the same class function

I'm trying to calibrate a model that has 12 unknown parameters inside it and as input only 5. I'm building a class for it as for example:
class model:
def __init__(self,input_1,input_2,input_3,...):
self.input_1=input_1
self.input_2=input_2
self.input_3=input_3
.
.
. #Only inputs here, no pmts
Then I've defined the functions as:
def integral(self, input_1, pmt1, pm2, pm3.... )
integral,err= quad(f(input,pmt1,pmt2,pmt3)) #I'm simplifying here, the function is longer
return integral
def model_price(self,input_1,input_2,input_3):
price = pm3 + self.integral(self)/input_3
return price
def loss_function(self):
err = (self.input_1 - self.model_price)
pen = 0
return err + pen
def minimization(self,x0,bnds):
params = {"pm1": {"x0": 0.0746, "lbub": [1e-4,4.9]}, #1
"pmt2": {"x0": 0.3369, "lbub": [1e-4,4]}, #2
"pm3": {"x0": 0.3369, "lbub": [1e-4,4]}, #3
....
}
x0 = [param["x0"] for key, param in params.items()]
bnds = [param["lbub"] for key, param in params.items()]
results =minimize(self.loss_function(), x0, tol = 1e-3, method='SLSQP', options={'maxiter': 1e3 }, bounds=bnds)
return results
I tried passing the x0 and bounds outside the function when I tried to use but is not working. I always get:
TypeError: integral() missing 12 required positional arguments: 'pmt1, pmt2, pmt3,
Error message is pretty clear, you are trying to call method integral with single argument and you need to pass 12 arguments.
So instead of self.integral(self) you need self.integral(arg1, … , arg12)

Can't assign to function call syntax error when trying to subtract variables in python

I'm attempting to create a rudimentary stock trading algorithm. One thing included in that algorithm is, after deciding how many of a stock to buy, subtracting the correct amount of money from the user's total. The problem occurs on the line "int(money_data) -= int(round(float(stockamounts[i]) * float(prices[i])))". The syntax error points to "int(money_data). "I hope I explained the problem in a way that makes sense. Thank you for any help.
for i in stock_symbols:
stock_url = "https://www.nasdaq.com/symbol/" + str(i)
stock_data = requests.get(stock_url)
file = open("data.txt", "w")
file.write(str(stock_data.content))
file.close()
file = open("data.txt", "r")
stock_data = file.read()
file.close()
stock_data = re.findall(r'<div id="qwidget_lastsale" class="qwidget-dollar">(.*?)</div>', str(stock_data))
for i in stock_data:
print(str(i.strip('$')))
price = i.strip('$')
prices.append(price)
stock_amounts = []
print(str(stock_symbols[0]) + " | " + str(round(float(money_amount) / float(prices[0]))))
stock_amounts.append(round(float(money_amount) / float(prices[0])))
for x in range(len(prices)):
print(str(stock_symbols[x]) + " | " + str(round(float(money_amount) / float(prices[x]))))
stock_amounts.append(round(float(money_amount) / float(prices[x])))
print(len(stock_amounts))
for i in stock_amounts:
print(stock_amounts[i])
int(money_data) -= int(round(float(stock_amounts[i]) * float(prices[i])))
print(money_data)
As the error says, you
can't assign to [a] function call
Why?
Say you have a function f:
>>> def f(x);
... return 3*x+4
When you
>>> f(4) = 5
what do you actually mean? You can't logically explain what should happen in a case like this, because basically (and in this example), that's like saying 16 = 5, which, I hope you agree, doesn't make sense.
"But, I did something different"
Yes, you used a variable in the call and used the -= operator.
Still, the a -= b operator is short for a = a-b (although you could overload them to do different stuff), and that's clearly an assignment (even if you overload, it remains an assignment).
How do I fix this?
You have two (and a half) possibilities:
use a normal assignment: just expand to a longer form as in val = int(val-to_sub)
add an extra line val -= to_sub; val = int(val) (please actually add an extra line and don't use ;)
(1/2) leave the int() away. If you are careful to only add, subtract, multiply with or divide through ints (or use // for divisions), you are sure that the value stays an int

python print statement with timestamp

My requirement is to have a function that works exactly like print but adds a timestamp at top. Currently I use something like:
def tprint(var):
print(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))+" :: "+str(var))
Though it gives me all required output for a specific set – e.g.,
tprint("dummy"+" print")
2017-11-09 19:38:42 :: dummy print
I am not able to completely morph it for print statement. For example, tprint("hi","hello") and tprint("a =", a, sep='0', end='') fail.
My requirement is not to ideally make these two statements work. But to write an alternative function for print that works for all print arguments but gives an additional timestamp along with it. I am sure this may not be a straight forward solution. But do not want to miss if someone has already figured out any similar approach.
Edit:
After reviewing what you wanted, why not just pass your desired values to a function that uses the built-in print()? Like so:
def tprint(*args, **kwargs):
stamp = str(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
print(stamp + ' :: ', *args, sep = kwargs['sep'], end = kwargs['end'])
a = 'Hello World'
tprint("a =", a, sep='0000', end='')
>>> [whatever the timestamp is] :: 0000a =0000Hello World
In order to provide a better response, I would really need to know what your expected output would be given an example. So far you have only said what does or does not work, but not why or how it should look.
Original Response:
Use the *args parameter in your function definition. It lets you supply an optional (unspecified) number of arguments in your function call and collects them into a list.
By definition, keyword arguments must come after all *args parameter. **kwargs packs them into a dictionary to iterate over. More information is available in this and that on SO.
So you can do something like this:
def tprint(*args, **kwargs):
tempa = ' '.join(str(a) for a in args)
tempk = ' '.join([str(kwargs[k]) for k in kwargs])
temp = tempa + ' ' + tempk # puts a space between the two for clean output
print(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + " :: " + temp)
a = 'Hello World!'
tprint("a =", a, sep='0', end='')
>>> 2017-11-09 09:35:37.148780 :: a = Hello World! 0 # I used datetime.datetime.now()

How to get a list of areas out of a class bassed system

So I am in an intro to python class and we are just getting into class basses coding in python. I am looking to get a list of areas out of the plants in my list so that I can then take those areas, get a sum, and then subtract them from the area in the bed. I am having the trouble figuring out how to make a list of the area of the plants in my bed, which is only blueberries for now. Any ideas are greatly appreciated.
class crop:
name = "Crop"
sizeW = 0
sizeL = 0
areaOfCrop=sizeL * sizeW
def print(self):
print("This is a ",self.name," and is ",self.sizeW,"X",self.sizeL, "and has an area of ",self.areaOfCrop)
def willItFit(self, W, L):
return self.sizeW <= W and self.sizeL <= L
def sameAs(self, crop):
return self.name == crop.name
class plant(crop):
name = "Plant"
sizeW = 1
sizeL = 1
areaOfCrop = sizeL * sizeW
class parsley(plant):
name = "Parsley"
class shrub(crop):
name = "Shrub"
sizeW = 2
sizeL = 2
areaOfCrop = sizeL * sizeW
class blueberries(shrub):
name = "Blueberries"
class tree(crop):
name = "tree"
sizeW = 3
sizeL = 3
areaOfCrop = sizeL * sizeW
class dwarfPeach(tree):
name = "Dwarf Peach"
class bed:
sizeL = int(input("What is the length? "))
sizeW = int(input("What is the width? "))
crops = [blueberries()] # The list of crops in this bed
areaOfAllCrops = [crops[areaOfCrop()]] #this is where my problem is
def print(self):
print("The bed is ", self.sizeL," x ", self.sizeW)
for c in self.crops:
c.print()
def maxSizeAvailable(self):
''' area of bed-total area of all crops in be '''
return (self.sizeW, self.sizeL)
def add(self, newCrop):
dimension = self.maxSizeAvailable()
if newCrop.willItFit(dimension[0], dimension[1]):
self.crops.append(newCrop)
def remove(self, existingCrop):
for c in self.crops:
if c.sameAs(existingCrop):
self.crops.remove(c)
def checkFit(self, crop):
dimension = self.maxSizeAvailable()
return crop.willItFit(dimension[0], dimension[1])
b = bed()
b.print()
You can add up the areas of the crop instances in the crops list with sum(x.areaOfCrop for x in crops). This is a generator expression that gets passed to the builtin function sum.
But I think you have a larger conceptual issue that will cause you problems later on even you get your immediate issue squared away. The issue is that you're exclusively using class attributes in your code, rather than instance attributes. While there are some situations where class attributes are useful, the overwhelming majority of the time you want to be dealing with instance attributes instead.
To create instance attributes, you need to make the assignments in a method, and assign to self.attr instead of just attr. Usually the place to initialize your instance attributes is the __init__ method, which Python will call for you after it creates the new instance.
To give an example, your crop class should probably start with:
class crop:
def __init__(self):
self.name = "Crop"
self.sizeW = 0
self.sizeL = 0
self.areaOfCrop = sizeL * size
# ...
Some of those values could be passed as arguments, rather than always getting set to the same constant. That leads me to a design question: Do you need all of your different plants to be instances of separate classes, or could they all be different instances of one class, with different data in their instance attributes attributes? (Don't be too concerned if you don't know the answer yet. It takes some experience with OOP to get good at designing classes.)

Resources