Reputation: 322
I am trying to call a method on an other class and give the called class a reference of the current class along with some other parameters. But somehow it takes the self given as a parameter as the self of the called class.
Let me show you:
import os, sys
from wsPart import wsPart
class thermo(wsPart):
functional = False ## see line 8
file = '/sys/bus/w1/devices/28-00000833e8ff/w1_slave'
def __init__(self, name, logger):
super().__init__(name, logger)
functional = True
def read(self):
fileobject = open(self.file)
filecontent = fileobject.read()
fileobject.close()
self.logger.writeLog(self,"Completed Meassurement") ##Problem on this line
return filecontent
So I call the class logger
and the method writeLog
on it. Giving the Parameters message and a reference of the class thermo (self).
import datetime
from wsPart import wsPart
class logger():
logfile = "/var/log/wheaterstation.log"
name = "Logger"
def writeLog(self, sender, message):
conn = open(self.logfile, "w")
now = str(datetime.datetime.now().isoformat())
conn.write("[" + now + "]" + " (" + sender.getName() + "): " + message + "\n") ##Problem on this line
conn.close()
As you can see I put the parameters self
because its a method that belongs to a class, the sender
should be the reference to the class thermo that was passed as self in the thermo class. Lastly there is the message
which was passed in the thermo class as well.
But this just gives me the error:
Traceback (most recent call last):
File "scrLib/wsControl.py", line 61, in <module>
controller = controller()
File "scrLib/wsControl.py", line 22, in __init__
self.thermo = thermo("Thermometer", logger)
File "/home/joco/git/wheaterstation/scrLib/thermo.py", line 10, in __init__
super().__init__(name, logger)
File "/home/joco/git/wheaterstation/scrLib/wsPart.py", line 8, in __init__
self.logger.writeLog(self, "created")
TypeError: writeLog() missing 1 required positional argument: 'message'
So it seems that the self
parameter which was passed in the thermo class is interpeted as the self
of the class logger
which gets it all mixed up.
Can you guys help me here?
The full code + additional comments can be viewed Here
Edit:
Both the logger and the thermo class get initialized in the file wsPart.py
:
class controller():
name = ""
logger = None
thermo = None
dbConnector = None
def __init__(self):
##THis created the controller and all the other objects
self.name = "Controller"
##Create Objects
self.logger = logger()
self.logger.writeLog(self,"logger created") ##This line Works
self.thermo = thermo("Thermometer", logger)
self.dbConnector = dbConnector("DBConnector",logger)
Upvotes: 0
Views: 198
Reputation: 140286
yes, bad idea to call the instance and the class name the same. Here:
self.logger = logger()
self.logger.writeLog(self,"logger created") ##This line Works
self.thermo = thermo("Thermometer", logger)
self.dbConnector = dbConnector("DBConnector",logger)
You're passing the class itself to your constructors. So the methods are seen as static/expect one more parameter. You need to change the 2 last lines to pass the instance you just created:
self.thermo = thermo("Thermometer", self.logger)
self.dbConnector = dbConnector("DBConnector", self.logger)
more importantly, you need to use different names for classes and instances of the same objects to avoid that confusion (python convention for class names is starting each word with upper case (camelcase) ex: Logger
. Other languages don't use that convention, but python is a lot about conventions).
With a different name you'd have gotten a NameError
exception and you would have fixed the error yourself.
Aside: don't "initialize" members like this in the class definition:
name = ""
logger = None
thermo = None
dbConnector = None
those are creating class members, not instance members. Remove those, and let __init__
create instance members like you're currently doing. __init__
is called no matter what, and those lines above just add to the confusion (except for some corner cases, only constants should be declared that way)
Upvotes: 1
Reputation: 77932
Totally unrelated but code in comments is unreadable so I post this as an answer:
this does not work as you seem to expect:
class Whatever(): functional = False ## see line 8
def __init__(self, name, logger):
super().__init__(name, logger)
functional = True
Python has no "implied this" sor here in __init__
you're not creating an instance attribute but a local variable. You want self.functional = True
Make sure you close files
def read(self): fileobject = open(self.file) filecontent = fileobject.read() fileobject.close()
If anything wrong happens between open()
and fileobject.close()
, the file is not garanteed to be properly closed. You want eiher a try/finally
block ie
f = open(path)
try:
do_something_with(f)
finally:
f.close()
or much better a with
block:
with open(path) as f:
do_something_with(f)
which will ensure the file is closed whatever happens.
write
mode truncates the file
def writeLog(self, sender, message): conn = open(self.logfile, "w") now = str(datetime.datetime.now().isoformat()) conn.write("[" + now + "]" + " (" + sender.getName() + "): " + message + "\n") ##Problem on this line conn.close()
as documented, opening a file in write mode truncates the file. You probably want the "append" mode instead here.
Logging is not as trivial as just writing to a file (concurrency issues, need to send the log message to some other destination, logging levels etc), and even if you don't need more (at least the moment) your solution is quite inefficient (opening a file is expensive).
Python has a very comprehensive logging package in it's standard lib. I wholefully agree that it requires a bit of learning to configure and use properly but that's still a huge win compared to the time you'll spend trying to make a naive half-backed custom implementation works properly on production, AND this is a knowledge that you will need for just any serious project anyway.
Upvotes: 0