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

时间:2014-06-15 19:47:08

标签: python

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

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

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

3 个答案:

答案 0 :(得分:1)

首先,您不必按文件分隔python类 - 更常见的是按功能将它们分组到模块和包(参考What's the difference between a Python module and a Python package?)。此外,200个类似的类听起来像一个非常不寻常的设计 - 他们真的需要或者你可以,例如使用dict存储一些属性?

当然,您可以编写一个小的python脚本,在csv中读取,并生成一个或多个.py个包含类的文件(写入文件的文本行)。

根据自定义的级别,应该只有几行代码。

如果此列表发生更改,您甚至不必将类写入文件:您可以generate them on the fly

如果你告诉我们你得到了多远或者有关问题的更多细节,我们可以帮助完成代码...

答案 1 :(得分:1)

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

但是我想:如果你有充分的理由这样做,比如为一堆文件制作类模板,那么你可以稍后进入并扩展它们?假设我计划编写一个 lot 代码,所以我想自动化样板代码部分,这样我就不会因为繁琐的工作而陷入困境。

原来为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()

以上将这样格式的csvfile作为其第一个参数(此处保存为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中工作。

答案 2 :(得分:0)

不要生成.py个文件,而是阅读csv并执行dynamic type creation。这样,如果csv发生变化,您可以确保动态重新生成类型。

相关问题