Python 被 @staticmethod 装饰的方法在调用时,会调用 __init__ 方法?

2020-11-10 21:43:53 +08:00
 AbcHiyi

被测试代码入如下:

class Config:
    def __init__(self, save_path=False, file_name="config.ini"):
        if save_path:
            try:
                self.tgt_lang = self.read_inf(file_name, save_path)
            except errors.FileError:
                self.tgt_lang = update_language_code()
                self.save_ini(file_name, save_path, self.tgt_lang)
        else:
            self.tgt_lang = update_language_code()

    @ staticmethod
    @ file_check
    def read_inf(file_name, path):
        """读取配置文件"""
        c_p = ConfigParser()
        c_p.read(os.path.join(file_name, path), encoding='UTF-8')

        return {i: dict(c_p.items(i)) for i in c_p.sections()}

    @ staticmethod
    def save_ini(file_name, path, data):
    	"""保存配置文件"""
        c_p = ConfigParser()
        c_p.read(path, encoding='UTF-8')

        for section in data.keys():
            for option in data_table[section].keys():
                try:
                    c_p.set(section, option, data_table[section][option])
                except NoSectionError:
                    c_p.add_section(section)
                    c_p.set(section, option, data_table[section][option])

        path = Path(path)
        if not path.is_dir():
            path.mkdir()

        full_path = os.path.join(path, file_name)
        with open(full_path, 'w', encoding='UTF-8') as file:
            c_p.write(file)

这边是测试代码:

class Config(unittest.TestCase):

    def setUp(self):
        self.save_dir = os.path.join(BASE_DIR, 'test_files')

    def tearDown(self):
        # 清扫文件
        try:
            shutil.rmtree(self.save_dir)
        except FileNotFoundError:
            pass


    def test_read_config(self):
     *1 setting.Config(self.save_dir)
     *2 setting.Config.save_ini(
            'config.ini', self.save_dir,
            {
                "test": {'test-check': 'True'}
            }
        )

        config = setting.Config(self.save_dir)

        if 'test' not in config.tgt_lang:
            self.fail('未能从本地文件读取数据')

主要问题是,在测试时,我在*1 和*2 的位置打了断点,并在被测类的'_init_' 方法内打了断点。 发现在调用*2 处的静态方法时,vscode 会跳转到被测类的'_init_'方法中. 我就纳闷了,怎么调用静态方法还会调用'_init_'方法,这不应该啊.

update_language_code()这个函数下载数据挺耗时间的,都是尽量能保存到本地就使用配置文件中的数据,不行再从服务器中下载

下面的代码是一个简化之后的样子,

class B:
    def __init__(selsf):
        print('b class')


class A:
    def __init__(self):
        print('a class')
        self.b = B()

    @staticmethod
    def b():
        print("A.b method")

在单独初始化'A 时'

A()

控制台打印

a class
b class

在调用静态方法 A.b 时

A.b()

控制台打印

b method

这让我更迷惑了,这和我设想的时一样的。但是 vscode 调试代码时为什么还是会跳转到'_init_'代码块?? 让人感觉就像是其中的代码被执行了一样

2569 次点击
所在节点    Python
23 条回复
AbcHiyi
2020-11-10 21:49:21 +08:00
顺道问一句,V2ex 怎么插入图片。刚刚加入这边还不清楚怎么操作。还是说只能使用 markdown 语法来引用网图吗?
singerll
2020-11-10 21:52:23 +08:00
构造函数吧,虽然我不是程序员,大概也知道这个
AbcHiyi
2020-11-10 22:21:50 +08:00
@singerll 是啊 ,按道理来说不应该调用构造函数的。但是调试的时候,调用静态方法总是会从静态方法进去就很奇怪
GodFastion
2020-11-10 22:30:06 +08:00
如果不调用其他函数 __init__会默认执行
mywaiting
2020-11-10 22:31:09 +08:00
盲猜 self.b = B() 这句重载了 def b() 导致的问题???
chashao
2020-11-10 22:32:19 +08:00
我用 pycharm 试了试,不会进__init__
Wincer
2020-11-10 22:33:29 +08:00
你在 *1 处初始化了 Config 的实例:setting.Config(self.save_dir),自然会进入 __init__ 内部
mrchi
2020-11-10 23:09:44 +08:00
@Wincer 确实,不过楼主也说了,问题在于*2 处的方法也会跳转 init 。


@AbcHiyi 会不会是 vscode debug 的问题,尝试直接执行呢
Kvip
2020-11-10 23:18:04 +08:00
看了你的描述,我觉得很奇怪,
我用 pycharm 实测执行了 A.b()后,输出的是`A.b method`,
输出正常,和你输出的`b method`不一致
AbcHiyi
2020-11-11 01:19:32 +08:00
@GodFastion 这个我清楚,问题是 2 处的代码调用静态方法也触发了 init 构造函数
AbcHiyi
2020-11-11 01:20:25 +08:00
@Wincer 问题是在 2 处也会在 debug 时进入
AbcHiyi
2020-11-11 01:21:52 +08:00
@chashao @chashao 也许是 vscode 的 Python 插件的调试 bug
AbcHiyi
2020-11-11 01:24:07 +08:00
@mrchi 直接执行的话,2 处的代码是不会有动作的。主要的问题是不清楚是调试器的 bug 还是 python 本身的问题。
AbcHiyi
2020-11-11 01:28:58 +08:00
@GodFastion 请问以下具体是怎么回事呢?嗯按照我的理解的是在调用静态方法时,构造方法不应该被调用啊。如果默认被调用的话就需要重新设计代码了.
AbcHiyi
2020-11-11 01:30:22 +08:00
也许我应该换个 ide 试试
freakxx
2020-11-11 01:57:04 +08:00
@AbcHiyi #14

哈哈哈,老哥,上个贴你都还没回最后是怎样,又来新的

不确定是不是你这句引起的
config = setting.Config(self.save_dir)

你干脆打多几个 print
在 config 前后写,
然后在 init 里面 print save_dir 的值和做个标记
freakxx
2020-11-11 02:00:01 +08:00
因为有一种可能操作,

你没在 save_ini 里面打断点或者 print,
所以执行完这一条,他直接跳到下一条进入 init 。
js8510
2020-11-11 06:06:32 +08:00
check type of `setting.Config` to see if it's a instance or a class.
js8510
2020-11-11 06:09:43 +08:00
also, you need to make sure that there is no reference to any Config instance inside the `save_ini ` function.
AbcHiyi
2020-11-11 08:31:58 +08:00
@freakxx 哈哈 东西整越大,已经有点控制不住了。以及找到问题了,在别的模块中引入了然后在测试中就造成了这个现象,无意间在终端导入时发现打印的的东西不太对找到的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/723746

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX