我可以动态创建类定义,例如:
class_name = 'Human'
base_classes = (object,)
attributes = {'name':'',
'books':list(),
'say_hello':lambda self: sys.stdout.write('Hello!')}
Human = type(class_name, base_classes, attributes)
uzumaxy = Human()
uzumaxy.name = 'Maxim'
uzumaxy.books.append('Programming via .NET')
print(uzumaxy.name) # Out: "Maxim"
print(uzumaxy.books) # Out: "['Programming via .NET']"
grandrey = Human()
grandrey.name = 'Andrey'
grandrey.books.append('Programming via python')
print(grandrey.name) # Out: "Andrey"
print(uzumaxy.name) # Out: "Maxim"
print(grandrey.books) # Out: "['Programming via .NET', 'Programming via python']"
print(uzumaxy.books) # Out: "['Programming via .NET', 'Programming via python']", but i'm expecting: "['Programming via .NET']"
似乎,属性“name”是实例级的,但为什么属性“books”是类级别的? 如何使用实例级属性动态创建类型的定义?求助。
答案 0 :(得分:3)
实际上,name
和books
都属于班级。只是字符串是不可变的,所以当你使用uzumaxy.name = "Maxim"
时,你会添加一个名为name
的新属性来隐藏类name
,而对于uzumaxy.books.append("Programming via .NET")
,你就是访问现有(类)books
并进行修改。您的代码等同于:
class Human(object):
name = ''
books = []
def say_hello(self):
sys.stdout.write("Hello!")
请注意相同的行为。传统上,我们通过这样写Human
来解决这个问题:
class Human(object):
def __init__(self):
self.name = ''
self.books = []
def say_hello(self):
sys.stdout.write("Hello!")
现在每个实例都有自己的name
和books
。要使用动态创建的类型执行此操作,您基本上会执行相同的操作,并为其指定__init__
:
def init_human(self):
self.name = ''
self.books = []
attributes = { '__init__': init_human,
'say_hello': lambda self: sys.stdout.write("Hello!") }
答案 1 :(得分:2)
他们都是班级。 name
只是不可变的,因此乍一看它看起来并不像是级别的。大多数修改它的尝试都会创建一个具有相同名称的新实例级属性。
就像以正常方式编写类一样,您需要在构造函数中创建实例属性:
def __init__(self):
self.name = ''
self.books = []
def say_hello(self):
# This prints a newline. The original didn't.
print 'Hello!'
Human = type('Human', (object,), {
'__init__': __init__,
'say_hello': say_hello,
})