V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
AbcHiyi
V2EX  ›  Python

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

  •  
  •   AbcHiyi · 2020-11-10 21:43:53 +08:00 · 2757 次点击
    这是一个创建于 1468 天前的主题,其中的信息可能已经有所发展或是发生改变。

    被测试代码入如下:

    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_'代码块?? 让人感觉就像是其中的代码被执行了一样

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


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

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

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

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

    你没在 save_ini 里面打断点或者 print,
    所以执行完这一条,他直接跳到下一条进入 init 。
    js8510
        18
    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
        19
    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
        20
    AbcHiyi  
    OP
       2020-11-11 08:31:58 +08:00
    @freakxx 哈哈 东西整越大,已经有点控制不住了。以及找到问题了,在别的模块中引入了然后在测试中就造成了这个现象,无意间在终端导入时发现打印的的东西不太对找到的
    AbcHiyi
        21
    AbcHiyi  
    OP
       2020-11-11 08:32:37 +08:00
    结案了,粗心大意,造成的哈哈哈
    freakxx
        22
    freakxx  
       2020-11-11 14:03:18 +08:00
    @AbcHiyi #20

    哈哈哈,不过我看你两次代码,感觉你这样写 python 爆炸概率很高,

    比如像你在 init 做的操作
    拆出来比较好,

    init 直接定义路径,不做一些操作。
    再定义一个子函数,在用的时候,再进行判断,没有的话再 update 。

    -----------------

    不过我很喜欢你的贴,总有一些弯弯绕绕让我尝试领会另一种奇特姿势。
    AbcHiyi
        23
    AbcHiyi  
    OP
       2020-11-23 16:16:22 +08:00
    @freakxx 哈哈喜欢尝试一些新姿势,挺有趣的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5318 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 09:35 · PVG 17:35 · LAX 01:35 · JFK 04:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.