【笔记14】python动态创建对象(类实例)、动态赋值、动态生成变量

Python 专栏收录该内容
13 篇文章 0 订阅

本次链接全集

为了方便查阅,在此先放个链接全家桶。

初衷

突发奇想想要动态创建一系列对象,具体是这样的:

class Assign(object):
    def __init__(self, h):
        self.a = h + 10
        self.b = h * 10
for i in range(10):
    var_i = Assign(i)

其实很容易想到用个字典存储,创建dict_assign = {},对应的往里放往外取dict_assign['var' + str(i)],但是这写起来就非常的长,并且很不直观。经过查阅,发现有很多pythonic的办法:【转载】 Python动态生成变量Python动态变量名定义与调用

一下相中用内置函数exec这个看上去特别简洁的方法,但是中间因为智商耽误很多时间。

实现

基础

工具要先用,再慢慢摸索怎么用,首先先看一下 Python3 exec 函数Python format 格式化函数

exec 执行储存在字符串的语句,因此我们只需要

for i in range(10):
    exec('var_{} = {}'.format(i, i))

就可以动态创建一系列的变量,并赋值。

动手

因此我的想法是:先创建对象动态创建变量将对象赋值给这个变量,实现起来是这样的:

class Assign(object):
    def __init__(self, h):
        self.a = h + 10
        self.b = h * 10
for i in range(10):
     exec('var_{} = {}'.format(i, Assign(i)))

然而!报了这样的错:

var_0 = <main.node object at 0x00000203A7F8F308>
^
SyntaxError: invalid syntax

在我困惑并查阅了很久的资料后,我突然醒悟:这是把对象的类型信息和内存信息返回来了,这样赋值就会报错。参考Python进阶-自定义类基础中:

这两个方法的区别在于,__repr__是给机器或者程序员看的字符串,而__str__是给用户看的字符串。一般遵循的原则是,__str__的结果就是用来给print函数输出的,而__repr__得到的字符串,有一部分甚至可以直接用eval函数让机器进一步执行(打基础的同学不建议用这种技巧)。
用print函数输出某个类实例时,会优先输出类__str__方法的返回值,如果没有就输出__repr__方法的返回值,如果没有自定义__repr__覆盖,那么原生的object.__repr__也直接输出该实例的类型信息和内存信息,比如刚才见过的<__main__.cat object at 0x00000207CB212668>。

作者:SyPy
链接:https://www.jianshu.com/p/232e55d7195d
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

深究下去我还应该补一下基础知识:python 深入理解 赋值、引用、拷贝、作用域

解决的办法很简单,就是对象也动态创建,实现起来是这样的:

class Assign(object):
    def __init__(self, h):
        self.a = h + 10
        self.b = h * 10
for i in range(10):
     exec('var_{} = Assign({})'.format(i, i))

补充:生成对象的方法、eval()、exec()及其相关函数

Python中9种生成新对象的方法
Python中的eval()、exec()及其相关函数

新的问题

exec在主函数中定义是没问题的,但是放到函数里就不能正常运行了,报错如下:

NameError: name ‘var_0’ is not defined

我们看这个对象的地址var_0 = <__main__.function.<locals>.class object at 0x0000019791BEE2C8>,是个局部变量,详见cookbook大法好: 9.23 在局部变量域中执行代码

为了修正这样的错误,你需要在调用 exec() 之前使用 locals() 函数来得到一个局部变量字典。
之后你就能从局部字典中获取修改过后的变量值了。

实际上对于 exec() 的正确使用是比较难的。大多数情况下当你要考虑使用 exec() 的时候,
还有另外更好的解决方案(比如装饰器、闭包、元类等等)。

看了大佬的建议我怒拍大腿!在此放上:9.8 将装饰器定义为类的一部分,以及我的笔记 【笔记2】python中@的用法


  1. 【转载】 Python动态生成变量. https://www.cnblogs.com/dcb3688/p/4347688.html ↩︎

  2. Python动态变量名定义与调用. https://www.cnblogs.com/technologylife/p/9211324.html ↩︎

  3. Python3 exec 函数. https://www.runoob.com/python3/python3-func-exec.html ↩︎

  4. Python format 格式化函数. https://www.runoob.com/python/att-string-format.html ↩︎

  5. Python进阶-自定义类基础. https://www.jianshu.com/p/232e55d7195d ↩︎

  6. python 深入理解 赋值、引用、拷贝、作用域. https://www.cnblogs.com/jiangzhaowei/p/5740913.html ↩︎

  7. Python中9种生成新对象的方法. https://blog.csdn.net/xiemanr/article/details/77922917 ↩︎

  8. Python中的eval()、exec()及其相关函数. https://www.cnblogs.com/yyds/p/6276746.html ↩︎

  9. 9.23 在局部变量域中执行代码. https://python3-cookbook.readthedocs.io/zh_CN/latest/c09/p23_executing_code_with_local_side_effects.html ↩︎

  10. 9.8 将装饰器定义为类的一部分. https://python3-cookbook.readthedocs.io/zh_CN/latest/c09/p08_define_decorators_as_part_of_class.html ↩︎

  11. 【笔记2】python中@的用法. https://blog.csdn.net/occamo/article/details/80842311 ↩︎

  • 3
    点赞
  • 0
    评论
  • 22
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值