我正在尝试通过装饰我的Django(ORM)模型(类定义)来自动编码100个数据库表模型,以从文件名中派生出它们的类名。但我认为我的“装饰深度”太浅了。我的def
方法中是否需要函数__call__
或类定义?是不是可以用这样简单的东西来完成?
# decorators.py
import os
from inspect import get_module
class prefix_model_name_with_filename(object):
'Decorator to prefix the class __name__ with the *.pyc file name'
def __init__(self, sep=None):
self.sep = sep or ''
def __call__(self, cls):
model_name = os.path.basename(getmodule(cls).__file__).split('.')[0]
setattr(cls, '__name__', model_name + self.sep + getattr(cls, '__name__'))
return cls
装饰器的示例用法
# models.py
from django.db import models
import decorators
@decorators.prefix_model_name_with_filename
class ShipMeth(models.Model):
ship_meth = models.CharField(max_length=1, primary_key=True)
模型定义中不存在具有新名称的模型,如果不查看装饰器类(而不是模型类)来查找属性,我就无法使用它!
>>> from sec_mirror.models import ShipMeth
>>> ShipMeth.__name__
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/home/Hobson/.virtualenvs/dev/lib/python2.7/site-packages/django/core/management/commands/shell.pyc in <module>()
----> 1 ShipMeth.__name__
AttributeError: 'prefix_model_name_with_filename' object has no attribute '__name__'
我是否需要以某种方式装饰模块?
答案 0 :(得分:3)
您正在使用类本身作为装饰器,因此只调用其__init__
。您的__call__
永远不会被调用。
改为使用实例:
@decorators.prefix_model_name_with_filename()
关于您更新的问题:装饰器无法更改用于引用封闭命名空间中的对象的实际名称。 (您可以通过将新名称粘贴到特定名称空间来强制它,但是您可以确保将名称放入的名称空间是最初定义对象的名称空间。)装饰器语法:
@deco
class Foo(object):
...
相当于
class Foo(object):
...
Foo = deco(Foo)
请注意,最后一行显示为Foo =
,因为原始类是使用class Foo
定义的。你不能改变它。装饰对象始终重新分配到它原来的名称。
有各种各样的方法来解决这个问题。您可以让装饰器为全局命名空间写一个新名称,或者甚至查看装饰对象的__module__
属性并为该命名空间写一个新名称。然而,这并不是装饰器的用途,而是会让你的代码混乱。装饰器用于修改/包装对象,而不是修改从中访问这些对象的名称空间。
答案 1 :(得分:2)
也许这是元类的工作:
import os
def cls_changer(name, parents, attrs):
model_name = os.path.basename(__file__).split('.')[0]
return type(model_name+name, parents, attrs)
class A(object):
__metaclass__ = cls_changer
pass
print A.__name__
前面的示例只是创建了名称已更改的新类,但是如果您希望模块能够反映您需要的更改(请注意我的python脚本名为 untitled0.py ):
import os
def cls_changer(name, parents, attrs):
model_name = os.path.basename(__file__).split('.')[0]
res = type(model_name+name, parents, attrs)
gl = globals()
gl[model_name+name] = res
return res
class A(object):
__metaclass__ = cls_changer
pass
print A.__name__
print untitled0A
输出:
untitled0A
<class '__main__.untitled0A'>