【问题标题】:Python3.x self as parameter in a method call to an other classPython3.x self 作为对其他类的方法调用中的参数
【发布时间】:2019-07-11 15:54:46
【问题描述】:

我正在尝试调用其他类的方法,并为被调用类提供当前类的引用以及其他一些参数。但不知何故,它将作为参数给出的自我作为被调用类的自我。

让我告诉你:

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

所以我调用类logger 和方法writeLog。提供参数消息和类 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()

如您所见,我输入了参数self,因为它是属于一个类的方法,sender 应该是对在 thermo 类中作为 self 传递的类 thermo 的引用。最后还有 message,它也在 thermo 类中通过。 但这只是给了我错误:

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'

因此,在 thermo 类中传递的 self 参数似乎被解释为 logger 类的 self,这让一切都混淆了。

你们能帮帮我吗?

完整代码+附加cmets可查看Here

编辑:
logger 和 thermo 类都在文件 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)

【问题讨论】:

  • 您确定self.loggerlogger实例 吗?你能edit 展示你是如何初始化它的吗? (注意:我不会访问完整代码的链接)
  • @Jean-FrançoisFabre 我添加了两者都被初始化的部分。

标签: python python-3.x python-2.7 oop reference


【解决方案1】:

是的,将实例和类名命名为相同是个坏主意。这里:

    self.logger = logger()
    self.logger.writeLog(self,"logger created") ##This line Works
    self.thermo = thermo("Thermometer", logger)
    self.dbConnector = dbConnector("DBConnector",logger)

您将 class 本身传递给您的构造函数。因此,这些方法被视为静态/期望多一个参数。您需要更改最后 2 行以传递您刚刚创建的实例:

    self.thermo = thermo("Thermometer", self.logger)
    self.dbConnector = dbConnector("DBConnector", self.logger)

更重要的是,您需要为相同对象的类和实例使用不同的名称以避免这种混淆(python 类名称的约定是以大写(camelcase)开头的每个单词,例如:Logger。其他语言不要' t 使用该约定,但 python 有很多关于约定的内容)。

如果使用不同的名称,您会得到 NameError 异常,并且您可以自己修复错误。

另外:不要在类定义中像这样“初始化”成员:

name = ""
logger = None
thermo = None
dbConnector = None

那些是创建类成员,而不是实例成员。删除这些,让__init__ 像您当前正在做的那样创建实例成员。 __init__ 无论如何都会被调用,而上面的那些行只会增加混乱(除了一些极端情况,只有常量应该这样声明)

【讨论】:

  • @Jocomol “我个人用第一个大写字母命名我的类,例如:Logger”:请注意,无论如何,使用 CamelCase 作为类名是 python 中的约定,所以你应该坚持这一点。
  • 是的,那些日子 C++ 做的太多了,谢谢你的说明
  • @brunodesthuilliers 如果camelCase 不是一个选项,我该怎么办,就像在 Logger 中一样?
  • 你可以保持原样,但你也可以使用logger_class,例如:)(例如,哈哈)
【解决方案2】:

完全不相关,但 cmets 中的代码不可读,因此我将其发布为答案:

  1. 这并不像您预期​​的那样工作:

    类Whatever(): functional = False ## 见第 8 行

    def __init__(self, name, logger):
        super().__init__(name, logger)
        functional = True 
    

Python 在__init__ 中没有“暗示这个”,所以您不是在创建实例属性,而是创建局部变量。你要self.functional = True

  1. 确保关闭文件

    def 读取(自我): 文件对象 = 打开(self.file) 文件内容 = 文件对象.read() 文件对象.close()

如果在open()fileobject.close() 之间发生任何错误,则无法保证正确关闭该文件。你想要一个 try/finally 块 ie

    f = open(path)
    try:
        do_something_with(f)
    finally:
        f.close()

或者更好的是with 块:

    with open(path) as f:
        do_something_with(f)

这将确保无论发生什么都关闭文件。

  1. write 模式截断文件

    def writeLog(self, sender, message): conn = 打开(self.logfile,“w”) 现在 = str(datetime.datetime.now().isoformat()) conn.write("[" + now + "]" + " (" + sender.getName() + "): " + message + "\n") ##这一行的问题 conn.close()

as documented,以写入模式打开文件会截断文件。您可能希望在此处使用“附加”模式。

  1. 当方轮已经存在时,不要重新发明方轮

日志记录并不像写入文件那么简单(并发问题,需要将日志消息发送到其他目的地,日志记录级别等),即使您不需要更多(至少现在)您的解决方案效率很低(打开文件很昂贵)。

Python 的标准库中有一个非常全面的日志记录包。我完全同意,它需要一些学习才能正确配置和使用,但与您尝试使天真的半支持自定义实现在生产中正常工作所花费的时间相比,这仍然是一个巨大的胜利,而且这是一个知识无论如何,您将需要任何严肃的项目。

【讨论】:

  • 谢谢你,我已经尽我所能来实现你的反馈(除了 Nr 4。因为我还没有时间),如果你想看看它,它在 GitHub 下的 Jocomol/小麦站。如果您有任何其他反馈,请随时通过 joelmeier08@gmail.com 与我联系,我将非常感激,因为在编程方面还有很多我不知道的。
猜你喜欢
  • 1970-01-01
  • 2011-09-15
  • 2020-12-16
  • 1970-01-01
  • 2019-05-20
  • 1970-01-01
  • 2020-09-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多