gpt4 book ai didi

python - 使用动态创建的函数动态添加属性

转载 作者:行者123 更新时间:2023-12-01 05:21:12 26 4
gpt4 key购买 nike

我想实现一些像这样工作的东西:

memo = Note("memo",5)
report = Note("report",20)

notebook = Notebook(memo,report)

print str(notebook.memo) # 5 expected
print str(notebook.report) # 20 expected

灵感来自: http://znasibov.info/blog/html/2010/03/10/python-classes-dynamic-properties.htmlHow to implement property() with dynamic name (in python),我实现了以下代码:

class Note:
def __init__(self,name,size):
self.name = name
self.size = size

class Notebook(object):
def __new__(cls,*notes):
notebook = object.__new__(cls)
setattr(notebook,'_notes',{note.name : note.size for note in notes})
functions = [lambda notebook : notebook._notes[note.name] for note in notes]
for note,function in zip(notes,functions) :
#version 1
setattr(notebook.__class__, note.name, property(function))
#version 2 -- note : __class__ removed
#setattr(notebook, note.name, property(function))
return notebook

注意:我知道在这个最小代码中使用 __new__ 而不是 __init__ 是不合理的,但稍后当我使用 的子类时将需要这样做笔记本

如果我使用版本 1:1. 它不打印 520,而是打印 2020。我不明白为什么。打印函数会显示具有不同地址的函数数组。2. 受上面给出的博客条目的启发,我使用了 __class__,但我不确定它的作用。它使该属性(property)成为类(Class)属性(property)? (对我来说这真的很糟糕)

如果我使用版本 2:打印类似 property object at 0x7fb86a9d9b50 的内容。这似乎有道理,但我不确定我是否理解为什么它不为版本 1 打印相同的内容。

有没有办法使用任一版本(或另一种完全不同的方法)来解决此问题?

<小时/>

编辑

提出了解决该问题的有趣答案。这里是相应的代码:

class Note:
def __init__(self,name,value):
self.name = name
self.size = value
def _get_size(self,notebook_class=None): return self.size+1

class Notebook(object):
def __new__(cls,*notes):
notebook = object.__new__(cls)
notebook._notes = {note.name : note.size for note in notes}
for note in notes : setattr(notebook.__class__, note.name, property(note._get_size))
return notebook

问题是:现在这个测试代码没有给出所需的输出:

memo1 = Note("memo",5)
report1 = Note("report",20)
notebook1 = Notebook(memo1,report1)
print str(notebook1.memo) # print 6 as expected (function of Note return size+1)
print str(notebook1.report) # print 21 as expected

memo2 = Note("memo",35)
report2 = Note("report",40)
notebook2 = Notebook(memo2,report2)
print str(notebook2.memo) # print 36 as expected
print str(notebook2.report) # print 41 expected

print str(notebook1.memo) # does not print 6 but 36 !
print str(notebook1.report) # does not print 21 but 41 !

我想这是可以预料的,因为该属性已添加到类中......无论如何要克服这个问题吗?

最佳答案

不过还有一些食物。为了简单地获得您想要在第一组代码中执行的操作,您可以做到这一点,而无需所有额外的技巧。

最简单的方法是直接将属性设置为所需的属性。 (代码合并在不合适的庄园只是为了节省空间)

class Note:
def __init__(self, name, value): self.name, self._size = name, value
size = property(lambda x: x._size+1)

class Notebook(object):
def __new__(cls, *notes):
notebook = object.__new__(cls)
notebook._notes = {note.name: note.size for note in notes}
for note in notes: setattr(notebook, note.name, note.size)
return notebook


memo1, report1 = Note("memo", 5), Note("report", 20)
notebook1 = Notebook(memo1, report1)

print(notebook1.memo, notebook1.report) # 6 21

memo2, report2 = Note("memo", 35), Note("report", 40)
notebook2 = Notebook(memo2,report2)

print(notebook2.memo, notebook2.report) # 36 41
print(notebook1.memo, notebook1.report) # 6 21
notebook1.memo += 5
print(notebook1.memo) # 11
print(memo1.size) # 6
memo1.size += 5 # AttributeError: can't set attribute

第二种方法是让笔记本真正成为您传递给它的所有笔记的容器。这样它就会简单地更新原始类对象,并且基本上只是它们的持有者。

class Note2(object):
def __init__(self, name, value): self.name, self._size = name, value
def _set_size(self, value): self._size = value
size = property(lambda x: x._size+1, _set_size)
def __repr__(self): return str(self.size) #simple trick to gain visual access to .size

class Notebook2(object):
def __new__(cls, *notes):
notebook = object.__new__(cls)
notebook._notes = {note.name: note.size for note in notes}
for note in notes: setattr(notebook, note.name, note)
return notebook

memo1, report1 = Note2("memo", 5), Note2("report", 20)
notebook1 = Notebook2(memo1, report1)
print(notebook1.memo, notebook1.report) # 6 21
memo2, report2 = Note2("memo", 35), Note2("report", 40)
notebook2 = Notebook2(memo2, report2)
print( notebook2.memo, notebook2.report) # 36 41
print(notebook1.memo, notebook1.report) # 6 21
notebook1.memo.size += 16
print(notebook1.memo) # 23
print(memo1) # 23, Notice this will also set the original objects value to the new value as well
notebook1.memo += 15 # TypeError: unsupported operand type(s) for +=: 'Note2' and 'int' - It is true without making it as a property does make it less effective to work with

还应该可以按照您提供的链接中的建议,使每个 Note 类成为带有前导下划线的 Notebook 成员(即 notebook._memo),然后为 Notebook 创建一个属性,将 Note 名称链接到大小(即notebook.memo将是notebook._memo.size的链接)。希望这些示例有所帮助。

<小时/>

原始答案。

有趣的想法,简单地让它在这里工作是对原始版本的修改:

class Note(object):
def __init__(self,name, size):
self.name = name
self._size = size

def _get_size(self, notebook_class=None):
return self._size

def _set_size(self, notebook_class=None, size=0):
self._size = size

class Notebook(object):
def __new__(cls,*notes):
notebook = object.__new__(cls)
for note in notes:
setattr(notebook.__class__, note.name, property(note._get_size, note._set_size))
return notebook

但是,无论如何,当您将每个 Note 类摄取到 Notebook 中时,您似乎都会删除它们,这样您就可以做一些更容易的事情:

class Note(object):
def __init__(self, name, size):
self.name = name
self.size = size

class Notebook(object):
def __new__(cls, *notes):
notebook = object.__new__(cls)
for note in notes:
setattr(notebook.__class__, note.name, note.size)
return notebook

为了提供更多帮助,我真的需要知道目标或您想要实现的目标的总体想法。以如此奇怪的方式设置属性似乎令人困惑,但只在创建类时执行一次,而不是能够动态添加和删除它们的示例。

希望这有帮助

关于python - 使用动态创建的函数动态添加属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22325492/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com