Можно ли создавать именованные функции в Python, подобные макросу C? - PullRequest
3 голосов
/ 20 декабря 2011

Извините за запутанный заголовок.

Я хотел бы сделать следующее: (Аналогично 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 с помощью макросаопределить.Причина, по которой я не использую класс, заключается в том, что создаваемая мной «структура» будет «привязана» к базе данных (в данном случае это просто текстовый файл в каком-либо формате).И я не хочу занимать какую-либо память, связанную с объектом - я буду представлять структуру как число (если хотите, идентификатор объекта)

Ответы [ 3 ]

1 голос
/ 20 декабря 2011

Мне кажется, что то, что вы ищете, уже предоставлено встроенным 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.

Примечание: это не реализует никакой установщик или получатель, но, как уже отмечалось в комментариях, это на самом деле не требуется при использовании классов.

1 голос
/ 20 декабря 2011

Это должен быть шаг в направлении того, что вы хотите:

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"))
0 голосов
/ 23 декабря 2011

Похоже, что это не так просто сделать в python - после некоторых исследований. Единственный способ добавить внутреннюю функцию в глобальное пространство имен - это изменить dict globals (), что довольно неудобно.

>>> 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)
...