<p>您可以使用元类控制实例创建(例如),并确保名称是唯一的。假设<code>__init__</code>方法接受一个没有默认值的参数<code>name</code></p>
<pre><code>class MyClass(object):
def __init__(self, name, *args, **kwargs):
self.name = name
</code></pre>
<p>显然,实例可以与此同名。让我们使用<code>metaclass</code>(使用兼容的python2/3语法)</p>
^{pr2}$
<p>哪些输出:</p>
<pre class="lang-none prettyprint-override"><code>a.name: hello
b.name: goodbye
Duplicate Name caught
</code></pre>
<p>使用<code>metaclass</code>技术,您甚至可以避免使用<code>name</code>作为参数,并且可以为每个实例自动生成名称。在</p>
<pre><code>import itertools
class MyMeta(type):
_counter = itertools.count()
@classmethod
def as_metaclass(meta, *bases):
'''Create a base class with "this metaclass" as metaclass
Meant to be used in the definition of classes for Py2/3 syntax equality
Args:
bases: a list of base classes to apply (object if none given)
'''
class metaclass(meta):
def __new__(cls, name, this_bases, d):
# subclass to ensure super works with our methods
return meta(name, bases, d)
return type.__new__(metaclass, str('tmpcls'), (), {})
def __call__(cls, *args, **kwargs):
obj = type.__call__(cls, *args, **kwargs)
obj.name = '%s_%d' % (cls.__name__, next(cls._counter))
return obj
class MyClass(MyMeta.as_metaclass()):
pass
a = MyClass()
print('a.name:', a.name)
b = MyClass()
print('b.name:', b.name)
c = MyClass()
print('c.name:', c.name)
</code></pre>
<p>输出:</p>
<pre class="lang-none prettyprint-override"><code>a.name: MyClass_0
b.name: MyClass_1
c.name: MyClass_2
</code></pre>
<p>要完成关于防止<code>a.name = b.name</code>(或任何其他已在使用的名称)的问题和答案,可以使用基于<code>descriptor</code>的方法</p>
<pre><code>class DescName(object):
def __init__(self):
self.cache = {None: self}
def __get__(self, obj, cls=None):
return self.cache[obj]
def __set__(self, obj, value):
cls = obj.__class__
if value in cls._names:
raise AttributeError('EXISTING NAME %s' % value)
try:
cls._names.remove(self.cache[obj])
except KeyError: # 1st time name is used
pass
cls._names.add(value)
self.cache[obj] = value
class MyClass(object):
_names = set()
name = DescName()
def __init__(self, name, *args, **kwargs):
self.name = name
a = MyClass('hello')
print('a.name:', a.name)
b = MyClass('goodbye')
print('b.name:', b.name)
try:
c = MyClass('hello')
except AttributeError:
print('Duplicate Name caught')
else:
print('c.name:', c.name)
a.name = 'see you again'
print('a.name:', a.name)
try:
a.name = b.name
except AttributeError:
print('CANNOT SET a.name to b.name')
else:
print('a.name %s = %s b.name' % (a.name, b.name))
</code></pre>
<p>具有预期的输出(在<code>__init__</code>或赋值期间不能重用名称)</p>
<pre class="lang-none prettyprint-override"><code>a.name: hello
b.name: goodbye
Duplicate Name caught
a.name: see you again
CANNOT SET a.name to b.name
</code></pre>
<p>编辑:</p>
<p>由于OP赞成这种方法,因此<code>metaclass</code>和{<cd7>}的组合方法包括:</p>
<ul>
<li><code>name</code>类属性作为<code>descriptor</code>在类创建过程中由<code>metaclass</code>添加</li>
<li><code>name</code>在实例到达<code>__init__</code>之前每个实例初始化一次</li>
<li><p><code>name</code>赋值操作的唯一性</p></li>
<li><p>在<code>descriptor</code>类中存储控制名称唯一性的<code>set</code>和{<cd18>}来消除类本身的污染</p></li>
</ul>
<pre class="lang-py prettyprint-override"><code>import itertools
class MyMeta(type):
class DescName(object):
def __init__(self, cls):
self.cache = {None: self, cls: set()}
self.counter = {cls: itertools.count()}
def __get__(self, obj, cls=None):
return self.cache[obj]
def __set__(self, obj, value):
self.setname(obj, value)
def setname(self, obj, name=None):
cls = obj.__class__
name = name or '%s_%d' % (cls.__name__, next(self.counter[cls]))
s = self.cache[cls]
if name in s:
raise AttributeError('EXISTING NAME %s' % name)
s.discard(self.cache.get(obj, None))
s.add(name)
self.cache[obj] = name
def __new__(meta, name, bases, dct):
cls = super(MyMeta, meta).__new__(meta, name, bases, dct)
cls.name = meta.DescName(cls) # add the name class attribute
return cls
@classmethod
def as_metaclass(meta, *bases):
class metaclass(meta):
def __new__(cls, name, this_bases, d):
# subclass to ensure super works with our methods
return meta(name, bases, d)
return type.__new__(metaclass, str('tmpcls'), (), {})
def __call__(cls, *args, **kwargs):
# Instead of relying on type we do the new and init calls
obj = cls.__new__(cls, *args, **kwargs)
cls.name.setname(obj)
obj.__init__(*args, **kwargs)
return obj
class MyClass(MyMeta.as_metaclass()):
def __init__(self, *args, **kwargs):
print('__init__ with name:', self.name)
a = MyClass()
b = MyClass()
c = MyClass()
a.name = 'my new name'
print('a.name:', a.name)
try:
a.name = b.name
except AttributeError as e:
print(e)
else:
print('a.name %s == %s b.name' % (a.name, b.name))
</code></pre>
<p>预期输出:</p>
<pre class="lang-none prettyprint-override"><code>__init__ with name: MyClass_0
__init__ with name: MyClass_1
__init__ with name: MyClass_2
a.name: my new name
EXISTING NAME MyClass_1
</code></pre>