python - 如何动态创建新的python类文件?

标签 python

我目前有一个包含 200 多个条目的 CSV 文件,其中每一行都需要制作成自己的类文件。这些类将继承自具有一些字段变量的基类,这些变量将继承并根据 CSV 文件设置值。此外,python 模块的名称需要基于 CSV 文件的条目。

我真的不想手动制作超过 200 个单独的 python 类文件,并且想知道是否有一种方法可以轻松地做到这一点。谢谢!

编辑* 我绝对更像是一个 java/C# 编码器,所以我对 python 不太熟悉。 更多细节:我正在尝试为现有的网络游戏创建一个 AI,我可以通过实时流文本框从中提取实时数据。 玩家每回合可以使用 200 多个 Action ,而且每个 Action 都大不相同。我可能会在使用移动类时创建新的实例,但是每次使用移动时我都必须遍历所有移动及其效果的数据库,这看起来效率很低。因此,我正在考虑为每个 Action 创建类,名称与文本框中出现的名称相同,以便我可以更快地创建该特定 Action 的新实例。

最佳答案

正如其他人所说,您通常希望为此类事情生成运行时类,而不是创建单独的文件。

但我想:如果您有充分的理由这样做,比如为一堆文件制作类模板,以便您以后可以进去扩展它们,那该怎么办?假设我计划编写很多代码,所以我想自动化样板代码部分,这样我就不会被困在繁琐的工作中。

事实证明,为 Python 类编写一个简单的模板引擎并不那么难。这是我的尝试,它能够从 csv 文件进行模板化。

from os import path
from sys import argv
import csv

INIT = 'def __init__'

def csvformat(csvpath):
    """ Read a csv file containing a class name and attrs.

    Returns a list of the form [['ClassName', {'attr':'val'}]].
    """
    csv_lines = []
    with open(csvpath) as f:
        reader = csv.reader(f)
        _ = [csv_lines.append(line)
                for line in reader]
    result = []
    for line in csv_lines:
        attr_dict = {}
        attrs = line[1:]
        last_attr = attrs[0]
        for attr in attrs[1:]:
            if last_attr:
                attr_dict[last_attr] = attr
                last_attr = ''
            else:
                last_attr = attr
        result.append([line[0], attr_dict])
    return result

def attr_template(attrs):
    """ Format a list of default attribute setting code. """
    attr_list = []
    for attr, val in attrs.items():
        attr_list.append(str.format('    if {} is None:\n', attr, val))
        attr_list.append(str.format('      self.{} = {}\n', attr, val))
        attr_list.append('    else:\n')
        attr_list.append(str.format('      self.{} = {}\n', attr, attr))
    return attr_list

def import_template(imports):
    """ Import superclasses.

    Assumes the .py files are named based on the lowercased class name.
    """
    imp_lines = []
    for imp in imports:
        imp_lines.append(str.format('from {} import {}\n',
            imp.lower(), imp))
    return imp_lines

def init_template(attrs):
    """ Template a series of optional arguments based on a dict of attrs.
    """
    init_string = 'self'
    for key in attrs:
        init_string += str.format(', {}=None', key)
    return init_string

def gen_code(foldername, superclass, name, attrs):
    """ Generate python code in foldername.

    Uses superclass for the superclass, name for the class name,
    and attrs as a dict of {attr:val} for the generated class.

    Writes to a file with lowercased name as the name of the class.
    """
    imports = [superclass]
    pathname = path.join(foldername, name.lower() + '.py')
    with open(pathname, 'w') as pyfile:
        _ = [pyfile.write(imp) 
                for imp
                in import_template(imports)]
        pyfile.write('\n')
        pyfile.write((str.format('class {}({}):\n', name, superclass)))
        pyfile.write((str.format('  {}({}):\n', 
            INIT, init_template(attrs))))
        _ = [pyfile.write(attribute) 
                for attribute
                in attr_template(attrs)]
        pyfile.write('    super().__init__()')

def read_and_generate(csvpath, foldername, superclass):
    class_info = csvformat(csvpath)
    for line in class_info:
        gen_code(foldername, superclass, *line)

def main():
    read_and_generate(argv[1], argv[2], argv[3])

if __name__ == "__main__":
    main()

上面的代码将这样格式的 csv 文件作为其第一个参数(此处保存为 a.csv):

Magistrate,foo,42,fizz,'baz'
King,fizz,'baz'

第一个字段是类名,后面是属性名及其默认值。第二个参数是输出文件夹的路径。

如果我创建一个名为 classes 的文件夹,并在其中创建一个具有基本类结构的 classes/mysuper.py:

class MySuper():
    def __init__(*args, **kwargs):
        pass

然后像这样运行代码:

$ python3 codegen.py a.csv classes MySuper

我得到了包含以下内容的文件 classes/magistrate.py:

from mysuper import MySuper

class Magistrate(MySuper):
  def __init__(self, fizz=None, foo=None):
    if fizz is None:
      self.fizz = 'baz'
    else:
      self.fizz = fizz
    if foo is None:
      self.foo = 42
    else:
      self.foo = foo
    super().__init__()

classes/king.py:

from mysuper import MySuper

class King(MySuper):
  def __init__(self, fizz=None):
    if fizz is None:
      self.fizz = 'baz'
    else:
      self.fizz = fizz
    super().__init__()

您实际上也可以加载并使用它们!

$ cd classes
classes$ python3 -i magistrate.py
>>> m = Magistrate()
>>> m.foo
42
>>> m.fizz
'baz'
>>>

上面生成的是我习惯的 Python 3 代码,因此您需要进行一些小的更改才能在 Python 2 中运行。

关于python - 如何动态创建新的python类文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24233477/

相关文章:

python - 从功能上打乱列表

python - 如何使用未检测到的 chromedriver 单击弹出元素

python - 输出 HTML 无序列表 python

python - 将简单的命令式算法转换为函数式风格

python - 在 django 模板中访问查询集对象

python - SQLite INNER JOIN in python : sqlite3. OperationalError: no such column:

python - window : Python + OpenCV + Qt: "import cv2" gives "dll not found" error

python - python 脚本完成后清除所有 c++ 对象

python - 打开 csv 文件时 pandas 中的日期时间转换错误

python - Tastypie的自定义授权中create_list指的是什么?