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
dwjgwsm
V2EX  ›  Python

如何在类中将字符串转换成变量名?

  •  
  •   dwjgwsm · 2018-03-31 09:18:11 +08:00 · 4475 次点击
    这是一个创建于 2441 天前的主题,其中的信息可能已经有所发展或是发生改变。
    import numpy as np
    class aa:
    def run(self):
    x='abcd'
    v=np.arange(5)
    exec(x+"=v") #exec 在类中不好使. 如何实现创建变量 abcd=np.arange(5) ?
    print(abcd)

    if __name__ == '__main__':
    r=aa()
    r.run()


    谢谢!
    38 条回复    2018-03-31 14:11:31 +08:00
    honeybeeSwinging
        1
    honeybeeSwinging  
       2018-03-31 09:32:42 +08:00 via iPhone   ❤️ 1
    这是啥语言?
    wwqgtxx
        2
    wwqgtxx  
       2018-03-31 09:35:07 +08:00 via iPhone
    getattr
    chesterzzy
        3
    chesterzzy  
       2018-03-31 09:54:49 +08:00
    setattr(self, '变量名字符串') #设置属性
    getattr(self, '变量名字符串') #获取属性

    #另外兄弟你的缩进得加强
    dwjgwsm
        4
    dwjgwsm  
    OP
       2018-03-31 10:14:01 +08:00
    setattr(self,x,v)
    不行啊,还是 print(abcd)报错啊

    是不是我没表达清楚啊,变量 abcd 不是类 aa 的属性,就是一个局部变量,我要实现的就是 abcd=np.arange(5) 这样的结果

    缩进怎么弄?我发表主题的时候试图前面加空格,但是发表之后空格被删掉了
    是不是要加{} 我再试试
    {import numpy as np
    class aa:
    def __init__(self):
    pass
    def run(self):
    x='abcd'
    locals()['v']=np.arange(5)
    v=np.arange(5)
    exec(x+"=v")
    print(abcd)

    if __name__ == '__main__':
    r=aa()
    r.run()
    }
    wwqgtxx
        5
    wwqgtxx  
       2018-03-31 10:29:22 +08:00 via iPhone
    locals[x] = v
    不就得了
    wwqgtxx
        6
    wwqgtxx  
       2018-03-31 10:30:01 +08:00 via iPhone
    locals()[x] = v
    忘了加括号
    dwjgwsm
        7
    dwjgwsm  
    OP
       2018-03-31 10:38:24 +08:00
    不是楼上想的那样,我希望能够在后面的代码中直接引用 abcd 这个变量,而不是 locals()['abcd']这样引用
    wwqgtxx
        8
    wwqgtxx  
       2018-03-31 10:41:03 +08:00 via iPhone
    我就想问问为什么要这么干
    Swift3030
        9
    Swift3030  
       2018-03-31 10:56:41 +08:00
    python 有 ast 库的吧
    dwjgwsm
        10
    dwjgwsm  
    OP
       2018-03-31 11:08:53 +08:00
    因为在后面代码中引用这些变量的时候全部都得写成 locals()['abcd']这种形式,和其他变量的引用方式不一致,非常不协调.
    比如后面的代码是这样的:

    a=np.array(5)+4
    b=np.array(5)*2
    c=(a>b) & (a>locals()['abcd'])
    ......

    这样整个代码显得非常不协调
    dwjgwsm
        11
    dwjgwsm  
    OP
       2018-03-31 11:09:47 +08:00
    @Swift3030 麻烦详细说说,谢谢!
    congeec
        12
    congeec  
       2018-03-31 11:43:25 +08:00 via iPhone
    @dwjgwsm ast.literal_eval
    wwqgtxx
        13
    wwqgtxx  
       2018-03-31 12:08:57 +08:00
    @dwjgwsm 如果你需要在后面的代码中直接 print(abcd) ,说明'abcd'这个字符串根本就是一个编译期间的常量,那么为什么不直接用 abcd = v 这种操作,然后后面的判断直接用 if a>abcd:不就得了
    如果 x 所指代的字符串是编译期间未知的,那么不管你是在前面赋值还是后面判断的时候都只能已字典取值的形式访问,上面所说的用 AST 模块并不能解决你的问题
    还有,这里的 abcd 既然是个局部变量,那么叫什么名字很重要么,出了函数范围就被删除了,何必那么在乎他的名字
    dwjgwsm
        14
    dwjgwsm  
    OP
       2018-03-31 12:11:34 +08:00
    @congeec ast.literal_eval 和 eval 都是不行的.你没明白我的意思,我的意思是要创建一个变量 abcd,而不是 abcd=eval('v')
    yu099
        15
    yu099  
       2018-03-31 12:17:05 +08:00 via Android
    emmmm,为什么不把变量放到字典里面,然后用到时再取呢
    wwqgtxx
        16
    wwqgtxx  
       2018-03-31 12:17:39 +08:00
    @dwjgwsm 你是要动态创建一个局部变量么,那么问题在于有什么意义呢,这个变量叫 abcd 和叫 a 有什么区别,请贴出你具体的应用场景,要不然别人没办法理解你到底要做什么
    wwqgtxx
        17
    wwqgtxx  
       2018-03-31 12:22:10 +08:00
    你要是问 exec 为什么在函数中无效,那么我倒是可以给你解释,因为 exec 是对 locals()和 globals()进行修改的,而 locals()只是对当前函数内的局部变量的深拷贝,所以对他的修改出了 exec 函数就失效了,也就是你不可能通过 exec 函数达到你的目的
    congeec
        18
    congeec  
       2018-03-31 12:23:27 +08:00 via iPhone
    @dwjgwsm eval('abcd = None') 不行么?
    wwqgtxx
        19
    wwqgtxx  
       2018-03-31 12:25:49 +08:00
    @congeec 在函数内部不会生效的,要是在模块级别倒是可以
    dwjgwsm
        20
    dwjgwsm  
    OP
       2018-03-31 12:27:07 +08:00
    @wwqgtxx x 所指代的字符串就是未知的,看来就是没有别的更好的办法了
    dwjgwsm
        21
    dwjgwsm  
    OP
       2018-03-31 12:27:50 +08:00
    一个更恰当的例子:

    import numpy as np
    class aa:
    def run(self,dict0):
    for k, v in dict0.items():
    exec(k + "=v")
    #############
    print(x1)

    if __name__ == '__main__':
    dict0 = {'x1': np.arange(5), 'y1': np.arange(5) * 2}
    r = aa()
    r.run(dict0)
    for key,value in dict0.items():
    exec(key+"=value")
    print('-------')
    print(x1) #这个在类之外使用就没问题
    dwjgwsm
        22
    dwjgwsm  
    OP
       2018-03-31 12:34:26 +08:00
    @wwqgtxx 不管你取什么名字,这的确不重要, 但你在后面的代码中引用这个变量的时候你都得前面加个 locals()前缀啊
    wwqgtxx
        23
    wwqgtxx  
       2018-03-31 12:35:30 +08:00
    @dwjgwsm 你这种在任何一个 IDE 中都会报错的用法自己看着不觉得扎眼么,至于 python 的设计者为什么这么做的原因很简单,你对一个函数内的局部命名作用域的修改并没有什么意义,出了函数不还是被销毁了
    比如你上面的例子和你
    dict0 = {'x1': np.arange(5), 'y1': np.arange(5) * 2}
    print(dict0['x1'])
    这样写有什么本质上的区别么
    wwqgtxx
        24
    wwqgtxx  
       2018-03-31 12:36:47 +08:00
    问题是你后面为什么要用一个动态的变量名,在一个函数的内部
    x='abcd'
    locals()['v']=np.arange(5)
    v=np.arange(5)
    exec(x+"=v")
    print(abcd)
    这种代码和
    v=np.arange(5)
    x = v
    printf(x)
    这两种代码你能告诉我有什么区别么
    wwqgtxx
        25
    wwqgtxx  
       2018-03-31 12:43:40 +08:00
    说到底,你在模块级别可以那样写只是因为你这样的操作把 x1 这个变量定义成了一个全局变量了,他从这个模块外部是可以被访问的
    而你在一个函数内部声明了一个叫 x1 的变量和声明了一个叫 x2 的变量有什么区别,他都是指向一块栈内存而已,出了这个函数谁也访问不到他,那么他的名字有出了给你看着舒服还有什么意义
    如果你用过 C/C++这种语言就知道了,变量的名字根本就不会被保存下来,编译期间就被擦除了,运行时完全没人知道他叫什么名字
    dwjgwsm
        26
    dwjgwsm  
    OP
       2018-03-31 12:46:57 +08:00
    @wwqgtxx 21 楼的代码简单表示了我想在 aa.run 中批量生成一批局部变量. 实际上我的代码逻辑还不是这样的,实际的逻辑是,类 aa 继承了一个基类,基类隐藏了很多复杂的功能实现,aa.run 每隔几秒钟运行一次,每一次运行完毕,会将 run 中的很多局部变量集中保存到基类中的一个字典变量中,下一次运行时,首先恢复这些局部变量.不知道你明白我的意思了吗
    dwjgwsm
        27
    dwjgwsm  
    OP
       2018-03-31 12:48:19 +08:00
    而且 aa.run 由于运算量大,还采用了多进程
    wwqgtxx
        28
    wwqgtxx  
       2018-03-31 12:53:13 +08:00
    @dwjgwsm “会将 run 中的很多局部变量集中保存到基类中的一个字典变量中”,你就不能直接在基类的字典变量中直接操作么,还要“下一次运行时,首先恢复这些局部变量”不觉得很多余么,如果你说你就是不想每次都调用 xxx_dict['aaa']这种非要用 aaa 这种形式调用,我只能告诉你没有办法 python 不支持引用别名这种操作,你可以去用 C++去,python 中无论如何都不可能实现这样的操作
    在你的上一个问题 /t/439895 中,@chenstack 已经告诉你了,python 的 locals()是不可更改的,你觉得他能修改那是因为他只是一份复制,并不是真正的局部命名域,换句话说不可能动态批量生成一批局部变量
    wwqgtxx
        29
    wwqgtxx  
       2018-03-31 12:55:08 +08:00
    另外你提到了多进程,那么很遗憾的告诉你,如果你想用一个共同基类来在多进程中共享数据,那么你可以试试看,他们之间的数据根本就不会保持同步,你要是说多线程那还可以理解,否则你就需要进行进程间通讯来交换数据
    dwjgwsm
        30
    dwjgwsm  
    OP
       2018-03-31 12:56:00 +08:00
    @wwqgtxx 恩,非常感谢!反正我的想法是无法实现的了,我还是老老实实用 locals()['abcd']吧,就是代码看着太难看了
    wwqgtxx
        31
    wwqgtxx  
       2018-03-31 12:57:13 +08:00
    如果你怕多线程同时修改基类数据的问题,你需要的是加锁,而不是用这种蹊跷意淫
    在函数的开头把基类的 dict 给 copy 一份,在函数结尾再 update 回去,当然记得在 copy 和 update 的时候加锁,要不然会出现很多意想不到的问题
    dwjgwsm
        32
    dwjgwsm  
    OP
       2018-03-31 12:59:08 +08:00
    @wwqgtxx 这个你不用担心,我用 Manager 把它传走了
    wwqgtxx
        33
    wwqgtxx  
       2018-03-31 12:59:22 +08:00
    另外一点,能不要用 locals()就不要用,你自己创建一个 dict 不好么,locals()存在的目的只是为了用来读取的,任何修改 locals()的行为都是未定义的,也就是说天知道会在什么环境什么版本就就会崩掉
    dwjgwsm
        34
    dwjgwsm  
    OP
       2018-03-31 13:07:54 +08:00
    run 里面的代码是会经常改变的(写各种交易策略的),如果将来真的崩了我就只有坚守老版本了
    wwqgtxx
        35
    wwqgtxx  
       2018-03-31 13:28:31 +08:00
    @dwjgwsm 你自己用一个 dict 来进行操作不好么,总是用 locals()和 exec()这种函数天知道时候会出错
    dwjgwsm
        36
    dwjgwsm  
    OP
       2018-03-31 13:44:18 +08:00
    @wwqgtxx 也可以, 反正我的想法也无法实现, c=(a>b) & (a>locals()['abcd']) 和 c=(a>b) & (a>dict0['abcd']) 谁也不比谁好看
    wwqgtxx
        37
    wwqgtxx  
       2018-03-31 14:02:35 +08:00
    @dwjgwsm 还有个办法,用一个 data 类来存储
    class DefaultNamespace(object):
    def __init__(self, default_value=None):
    super(DefaultNamespace, self).__setattr__("_default_value", default_value)

    def __getattribute__(self, item):
    try:
    return super(DefaultNamespace, self).__getattribute__(item)
    except AttributeError:
    pass
    except KeyError:
    pass
    return super(DefaultNamespace, self).__getattribute__("_default_value")

    def __getstate__(self):
    return self.__dict__

    然后你在函数开头来 data = DefaultNamespase()
    后面就直接用 data.abcd = xxxx 还有 if(data.abcd > xxx) 这种就行了,看着也相对舒服一点
    dwjgwsm
        38
    dwjgwsm  
    OP
       2018-03-31 14:11:31 +08:00
    @wwqgtxx 好的,非常非常感谢!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3551 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 04:33 · PVG 12:33 · LAX 20:33 · JFK 23:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.