【问题标题】:Method not found although exists in same py file - python虽然存在于同一个py文件中但找不到方法-python
【发布时间】:2023-04-09 10:09:01
【问题描述】:

我是python新手,我的背景是VB。我收到错误为“NameError:未定义名称'GetASetting'”。

日志:

[INFO              ] Kivy v1.8.0
Purge log fired. Analysing...
Purge 60 log files
Purge finished !
[INFO              ] [Logger      ] Record log in C:\Users\Sudheer\.kivy\logs\kivy_14-07-18_10.txt
[INFO              ] [Factory     ] 157 symbols loaded
[DEBUG             ] [Cache       ] register <kv.lang> with limit=None, timeout=Nones
[DEBUG             ] [Cache       ] register <kv.image> with limit=None, timeout=60s
[DEBUG             ] [Cache       ] register <kv.atlas> with limit=None, timeout=Nones
[INFO              ] [Image       ] Providers: img_tex, img_dds, img_pygame, img_gif (img_pil ignored)
[DEBUG             ] [Cache       ] register <kv.texture> with limit=1000, timeout=60s
[DEBUG             ] [Cache       ] register <kv.shader> with limit=1000, timeout=3600s
 Traceback (most recent call last):
   File "C:\Kivy180\Python33\lib\runpy.py", line 160, in _run_module_as_main
     "__main__", fname, loader, pkg_name)
   File "C:\Kivy180\Python33\lib\runpy.py", line 73, in _run_code
     exec(code, run_globals)
   File "D:\OS Files\workspace\Org\__main__.py", line 7, in <module>
     from formcontrol import FormControl
   File "D:\OS Files\workspace\Org\formcontrol.py", line 8, in <module>
     from login.logincodes import LoginControl
   File "D:\OS Files\workspace\Org\login\logincodes.py", line 7, in <module>
     from dbcodes.logins import LoginAccess
   File "D:\OS Files\workspace\Org\dbcodes\logins.py", line 2, in <module>
     from dbcodes.settings import GetASetting, SettingList
   File "D:\OS Files\workspace\Org\dbcodes\settings.py", line 31, in <module>
     class SettingList(object):
   File "D:\OS Files\workspace\Org\dbcodes\settings.py", line 36, in SettingList
     FirstRun_Get = GetASetting(FirstRun)
 NameError: name 'GetASetting' is not defined

class 和 def 都在同一个 .py 文件中。 代码:

def Initiation():
    from os import path
    print(Getcwd())
    folderpath=str(Getcwd()) 
    fpath = folderpath + "/orgapp.ini"
    dbpath = folderpath + "/orgapp.db"
    if path.exists(fpath)==False:

        #Writing Basic Values
        f = open(fpath,'w')
        setlist=SettingList()
        f.write(setlist.FirstRun+'|True' + '\n')
        f.write(setlist.IniPath+'|'+fpath + '\n')
        f.write(setlist.DBPath+'|'+dbpath + '\n')
        f.close()
        print('File Created')


        #Creating default database
        CreateDB(dbpath)

        return True
    else:
        print('File exists')
        return False

def GetASetting(settingtype):
        if settingtype=='': return None
        path = Getcwd() + '/orgapp.ini'
        f1=open(path,'r')
        for k in f1:
            k=k.replace('\n','')
            c= (k.rsplit(sep='|', maxsplit=2))
            if settingtype.lower() == c[0].lower():
                f1.close()
                if c[1]=='': return None
                else: return c[1]
        f1.close()
        return None

class SettingList(object):
    FirstRun = 'FirstRun'
    IniPath='IniPath'
    DBPath='DBPath'

    FirstRun_Get = GetASetting(FirstRun)
    IniPath_Get = GetASetting(IniPath)
    DBPath_Get = GetASetting(DBPath)



def Getcwd():
    from os import getcwd
    p=''
    p=getcwd()
    p=p.replace('\\', '/')
    return p

def CreateDB(dbpath):
    import sqlite3

    conn = sqlite3.Connection(dbpath, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
    conn.execute('''
    create table login
    (loginid text, password text)    
    ''')

    #default user
    id='admin'
    pw='1234'
    conn.execute("insert into login (loginid, password) values (?,?)",(id,pw))


    conn.commit()
    conn.close()

我通过将 def 放在类中进行了解决,但是,上面的代码应该可以工作,请您告诉我我上面犯了什么错误,我检查了名称并且它们是正确的?

【问题讨论】:

    标签: python


    【解决方案1】:

    GetASetting 需要存在才能使用它。根据您的代码的结构方式,它不会。在类定义之前定义GetASetting

    【讨论】:

    • 我用完整的代码编辑了这个问题,当我改变函数/方法的位置时,它就会生效。我现在明白你说的了。但是,我该如何纠正,这是在 python 中编码的正确方法吗,在 VB 中,此流程代码不会生效,请您更详细地解释一下。感谢您的宝贵时间。
    • @surpavan:请看下面我的回答。
    【解决方案2】:

    正如 Ignacio 所说,GetASetting 需要存在才能使用它。确切的原因是:类定义和函数签名(参数的默认值可能包含可执行代码)在 Python 解释器第一次遇到它们时执行——因此,你的函数 GetASetting 需要存在于此时间已经。 (另一方面,这也意味着您也可以在类定义中使用if/else 和其他控制流语句。)

    无论如何,如果你不想要这个(而且你通常不想要——由于你遇到的那种不直观的错误),你应该为你的类使用构造函数:

    class SettingList(object):
        # All code in here is executed when the interpreter first
        # encounters the class definition
        def __init__(self): # The same applies for this line
            # This code only run when __init__() is actually called.
            self.FirstRun = 'FirstRun'
            self.IniPath='IniPath'
            self.DBPath='DBPath'
    
            # Now, the function definition below poses no problem.
            self.FirstRun_Get = GetASetting(FirstRun)
            self.IniPath_Get = GetASetting(IniPath)
            self.DBPath_Get = GetASetting(DBPath)
    
    def GetASetting(settingtype):
        # […]
        return None
    
    
    # usage example
    settings = SettingList()
    print(settings.FirstRun_Get) 
    

    这在可测试性方面也是一个好主意——现在 SettingList 的每个实例都在创建时进行初始化,这样理论上,您可以模拟文件访问等依赖项,即磁盘上的设置文件。

    【讨论】:

    • 是的,但是现在我需要对类进行实例化,是否可以不实例化?像单一方法等?
    • 不,你不是在初始化这个类,而是它的一个实例。除此之外,类的全部意义在于创建它的实例。如果您想要全局状态(我会避免这种情况,请参阅我关于可测试性的声明),请不要使用类(或 evil singleton-pattern)并将其定义在模块范围内。我知道这在 Java 之类的语言中是不可能的(我不了解 VB),但在 Python 中却是这样,这样做是有意义的。 :)
    • 当然,你可以定义一个 class method 来初始化你的类,但我强烈建议不要这样做,因为 1. 你会再次引入全局状态,2. 你仍然依赖于调用在正确的时间使用方法,即在其他任何地方使用该类之前。但是现在你又依赖于执行顺序,完全掩盖了你代码的依赖关系。
    • 如何在Application级别定义全局变量,我用的是kivy框架,理解一下会有帮助。
    • 在 Python(以及 Kivy)中,您可以简单地在模块范围内定义变量(= 未缩进的所有内容),例如您在上面定义的所有功能都位于模块范围内。然后,只需通过它们的名称,它们就可以在模块的其余代码中全局访问。此外,如果需要,您可以将此模块(包括其全局变量)导入另一个模块。看看这个answer到一个相关的问题,但暂时忽略前两句话,而是看代码示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-21
    • 1970-01-01
    • 2012-03-28
    • 2014-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多