【问题标题】:Is it possible to create named functions in Python similar to C macro?是否可以在 Python 中创建类似于 C 宏的命名函数?
【发布时间】:2012-01-24 11:58:58
【问题描述】:

抱歉标题混乱。

我想做以下事情:(类似于 Lisp 中的 defstruct

def mkstruct(structname, field_dict):
    # create a function called "structname" and get/set functions
    # called "structname_get(s, field_name)" and "structname_set(s, field_name, value)"

# Create a struct "lstnode"
mkstruct("lstnode", {ndkey : 0, nxt: None})
# Make a new struct
node = lstnode()
node_set(node, "ndkey", 5)
v = node_get(node, "ndkey") # v should be 5

这可以在 C 中使用宏定义来完成。我不使用类的原因是因为我正在创建的“结构”将“绑定”到数据库(在这种情况下只是某种格式的文本文件)。而且我不想占用与对象相关的任何内存 - 我会将结构表示为一个数字(如果你愿意,可以是一个对象 ID)

【问题讨论】:

  • 那么如果没有实际内存,你希望这些 getter 和 setter 做什么?
  • 你能更具体地谈谈你对上课的厌恶吗?如果你把你的函数放在字典里,你基本上只是重新发明了这个类。听起来这就是它的发展方向。
  • 我有一个巨大的树形结构。如果我可以不使用 OID 而不是对象,那么我就不会使用任何对象引用。每个对象访问都被转换为数据库操作(查找和更新)。
  • 您是否发现对象引用在某些方面不好?如果使用对象而不是松散的函数种类增加的内存开销很大,您可能需要重新考虑使用 Python 的决定。

标签: python function macros


【解决方案1】:

这应该是朝着你想要的方向迈出的一步:

def mkstruct(name, attrs):
    def init(self):
        self.id = # not sure how you want to get the id

    def getattr(self, attr):
        if attr not in attrs:
            raise AttributeError(attr)
        # put your database lookup statement here

    def setattr(self, attr, value):
        if attr not in attrs:
            raise AttributeError(attr)
        # put your database update statement here

    return type(
        name,
        (object,),
        __init__=init,
        __getattr__=getattr,
        __setattr__=setattr)

lstnode = mkstruct("lstnode", ("ndkey", "nxt"))

【讨论】:

    【解决方案2】:

    在我看来,您正在寻找的东西已经由 type 内置提供:

    def mkstruct(structname, field_dict):
        return type(structname, (object,), field_dict)
    
    lstnode = mkstruct("lstnode", {'ndkey' : 0, 'nxt': None})
    node = lstnode()
    node.ndkey = 5
    v = node.ndkey
    

    如果您只需要field_dict 中的键成为结构的成员,则可以将'__slots__' 添加到field_dict

    注意:这并没有实现任何 setter 或 getter,但正如 cmets 已经指出的那样,在使用类时这并不是真正需要的。

    【讨论】:

      【解决方案3】:

      看起来这在 python 中并不容易 - 经过一些研究。向全局命名空间添加内部函数的唯一方法是修改 globals() dict,这相当尴尬。

      >>> def mkfunc(funcname):
      ...   def func():
      ...     print "my name is %s" % funcname
      ...   func.__name__ = funcname
      ...   return func
      ... 
      >>> mkfunc("abc")
      <function abc at 0xb773ae64>
      >>> globals()["abc"] = mkfunc("abc")
      >>> abc()
      my name is abc
      

      至于我自己的问题,我满足于做以下事情:

      def mkstruct(fields):
          def maker(args):
              # validate @args against @fields
              oid = db_insert_row(fields)
              return oid
          def getter(oid, fieldname):
              rec = db_retrieve(oid)
              return rec[fieldname]
          def setter(oid, fieldname, value):
              db_update(oid, fieldname, value)
          return (maker, getter, setter,)
      
      lstnode, lstnode_get, lstnode_set = mkstruct({nodekey: 0, nxt: None})
      n = lstnode(nodekey=5)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-08
        • 2013-07-29
        • 1970-01-01
        • 1970-01-01
        • 2022-11-24
        相关资源
        最近更新 更多