我希望使用元类来添加基于原始类的辅助方法。如果我想要添加的方法使用self.__attributeName
,我会得到一个AttributeError
(因为名称重整),但对于现有的相同方法,这不是问题。
这是一个简化的例子
# Function to be added as a method of Test
def newfunction2(self):
"""Function identical to newfunction"""
print self.mouse
print self._dog
print self.__cat
class MetaTest(type):
"""Metaclass to process the original class and
add new methods based on the original class
"""
def __new__(meta, name, base, dct):
newclass = super(MetaTest, meta).__new__(
meta, name, base, dct
)
# Condition for adding newfunction2
if "newfunction" in dct:
print "Found newfunction!"
print "Add newfunction2!"
setattr(newclass, "newfunction2", newfunction2)
return newclass
# Class to be modified by MetaTest
class Test(object):
__metaclass__ = MetaTest
def __init__(self):
self.__cat = "cat"
self._dog = "dog"
self.mouse = "mouse"
def newfunction(self):
"""Function identical to newfunction2"""
print self.mouse
print self._dog
print self.__cat
T = Test()
T.newfunction()
T.newfunction2() # AttributeError: 'Test' object has no attribute '__cat'
有没有办法添加newfunction2
可以使用self.__cat
?
(不将self.__cat
重命名为self._cat
。)
也许更基本的一点,为什么self.__cat
对于这两种情况都不会以同样的方式对待,因为newfunction2
现在是Test
的一部分?
答案 0 :(得分:6)
当编译类中的方法时,会发生名称重整。像__foo
这样的属性名称被转换为_ClassName__foo
,其中ClassName
是定义方法的类的名称。请注意,您可以对其他对象的属性使用名称修改! / p>
在你的代码中,newfunction2
中的名称错误不起作用,因为在编译函数时,它不是类的一部分。因此,__cat
的查找不会像__Test_cat
那样转变为Test.__init__
。如果需要,您可以显式查找属性名称的受损版本,但听起来您希望newfunction2
是通用的,并且能够添加到多个类中。不幸的是,这不适用于名称修改。
确实,防止在您的类中定义的代码访问您的属性是使用名称修改的全部原因。通常,如果您正在编写代理或mixin类型,并且您不希望您的内部使用属性与您正在代理或混入的类的属性(您不会知道)发生冲突,那么它是值得打扰的。提前)。
答案 1 :(得分:1)
回答你的两个问题:
self.__cat
到newfunction2
之后更改self._Test__cat
。 这种破坏是在不考虑句法位置的情况下完成的 标识符,只要它出现在类的定义中。
让我为你制造它,它说当你的翻译遇到一个名字错误的名字时读取的地方并不重要。 如果它出现在类的定义中,那么该名称只会被损坏,在您的情况下,它不是。因为它不直接"在"一个类定义。因此,当它显示为self.__cat
时,它会将其保持在self.__cat
,不将文本替换为self._Test__cat
,因为它不是{\ n}在Test
类中定义。
答案 2 :(得分:0)
您可以使用<Test instance>._Test__cat
访问__cat
课程中的Test
属性。 (<Test instance>
替换为self
或Test
类的任何其他实例)
答案 3 :(得分:0)
class B:
def __init__(self):
self.__private = 0
def __private_method(self):
'''A private method via inheritance'''
return ('{!r}'.format(self))
def internal_method(self):
return ('{!s}'.format(self))
class C(B):
def __init__(self):
super().__init__()
self.__private = 1
def __private_method(self):
return 'Am from class C'
c = C()
print(c.__dict__)
b = B()
print(b.__dict__)
print(b._B__private)
print(c._C__private_method())