在Python 3中使用元类重新定义__init__

时间:2018-02-17 16:54:32

标签: python metaclass

我在python中学习元编程3.我的教授确实给了我们这个练习:

编写元类法术,在向导中转换学生的实例。

我这样做了:

MainPage.html

正确调用向导类var i; var MAX_ROWS = 5; var indentations = [0, MAX_ROWS]; var k=Obj.employee.length; console.log(k); for(i = k-1; i > 0; i--){ var table = document.getElementById("myTable"); var row = table.insertRow(1); var cell1 = row.insertCell(0); var cell2 = row.insertCell(1); var cell3 = row.insertCell(2); var cell4 = row.insertCell(3); var cell5 = row.insertCell(4); var cell6 = row.insertCell(5); cell1.innerHTML=Obj.employee[i].email; cell2.innerHTML=Obj.employee[i].image; cell3.innerHTML=Obj.employee[i].status; cell4.innerHTML=Obj.employee[i].mobile; cell5.innerHTML=Obj.employee[i].college; cell6.innerHTML='<button class="btn btn-warning" onclick="deleteRow(this)"><span style="color:white"><i class="fa fa-edit"></i>&nbsp;Delete</span></button>'; if (i <= MAX_ROWS) { var endVal = indentations[indentations.length - 1]; if (i % 5 === 0) { indentations.push(i + MAX_ROWS); } else if (endVal < k && i == 1) { endVal = endVal + MAX_ROWS; indentations.push(endVal); } } } renderTbl(0, 5); console.log(indentations); var before = document.getElementById("myModal"); for (var j = 0, s = indentations.length; j < s; j++) { var start = indentations[j]; var end = start + MAX_ROWS; var btn = document.createElement("div"); btn.className = "btn"; btn.innerHTML = start + " ... " + end; before.insertAdjacentElement("beforeBegin", btn); } var btns = document.querySelectorAll(".btn"); for (var j = 0, s = btns.length; j < s; j++) { var btn = btns[j]; btn.addEventListener("click", function(){ var arr = this.textContent.split("..."); var start = arr[0]; var end = arr[1]; renderTbl(start, end); }); } function renderTbl (start, end, arr) { var table = document.getElementById("myTable"); var rows = table.querySelectorAll("tr"); console.log(rows); end = parseInt(end); start = parseInt(start) + 1; console.log(start) + 1; console.log(end); for (var i = 0; i < k; i++) { console.log(rows[i].innerHTML); if (i < start || i > end) { rows[i].style.display = "none"; } else { rows[i].style.display = "table-row"; } } rows[0].style.display = "table-row"; } 而不是学生类class Spell(type): def __new__(cls, classname, supers, cls_dict): cls_dict['__init__'] = Spell.toWizard() cls_dict['__qualname__'] = 'wizard' return type.__new__(cls, 'wizard', supers, cls_dict) @staticmethod def toWizard(): def init(*args): wizard(args, 'fire_spell') return init class student(metaclass=Spell): def __init__(self, name): self.name = name class person(): def __init__(self, name): self.name = name class wizard(person): def __init__(self, name, magic): self.magic = magic super().__init__(name) if __name__ == '__main__': s = student('name1') print(s.__dict__) s = student('name2') print(s.__dict__) ,但创建的对象为空__init__。我哪里错了?

1 个答案:

答案 0 :(得分:7)

您的init()替换函数会创建本地 wizard()实例,并且不会返回任何内容:

def init(*args):
    wizard(args, 'fire_spell')

这是一个单独的实例,self未触及。

不要使用__new__;产生一个新类。您只重命名了student类,并为其提供了无效的__init__方法。

重写__call__方法以挂钩创建实例。在那里,您可以替换或忽略第一个参数,即student类对象,并在其位置使用wizard类:

class Spell(type):
    def __call__(cls, *args, **kwargs):
        # ignore the cls argument, return a wizard instead
        if 'magic' not in kwargs and len(args) < 2:
            # provide a default magic value
            kwargs['magic'] = 'fire_spell'
        return wizard(*args, **kwargs)

因为student通常只接受一个参数,所以如果没有指定,则上面添加magic参数。

演示:

>>> student('name1')
<__main__.wizard object at 0x10f1e8198>
>>> vars(_)
{'magic': 'fire_spell', 'name': 'name1'}