为什么我可以在Python的抽象类中访问派生类的变量?

为什么我可以在Python的抽象类中访问派生类的变量?,python,Python,我很惊讶下面的代码运行时没有出错 # ABC class Foo(object): __metaclass__ = ABCMeta a = 1 def __init__(self, b, c): self.b = b self.c = c def get_scaled_a(self): return self.a / Bar1.a # why can I access Bar1.a? @abstrac

我很惊讶下面的代码运行时没有出错

# ABC
class Foo(object):
    __metaclass__ = ABCMeta

    a = 1

    def __init__(self, b, c):
        self.b = b
        self.c = c

    def get_scaled_a(self):
        return self.a / Bar1.a # why can I access Bar1.a?

    @abstractmethod
    def class_type(self):
          pass


# Derived class 1
class Bar1(Foo):

    a = 100

    def class_type(self):
       return 'bar1'


# Derived class 2
class Bar2(Foo):

    a = 10

    def class_type(self):
       return 'bar2'


my_bar2_inst = Bar2(0, 0)
print(my_bar2_inst.get_scaled_a())
# 0.1
因为Python假定开发人员是成熟的人。在Python中,您通常可以访问所有属性,而不是由解释器检查您是否有权访问某个属性。这取决于你是否足够成熟,不要破坏任何东西

然而,有一种约定是,以小写字母开头的属性,如
\u foo
\u bar
\u qux
被视为私有属性。这意味着自己访问这些文件通常不是一个好主意。但是没有任何机制可以阻止您访问它们:变量名或多或少地要求您不要访问它。如果你绝对需要它,这是你的责任


现在
Bar
a
Bar
类的成员,而不是
Bar
实例的成员。因此,在其他一些语言中,它被认为是“静态的”。这是您可以访问它的另一个原因。

当您运行
get\u scaled\u a
时,
Bar1
类已经定义,它的
a
属性也已经定义。请记住,类也是对象,而不仅仅是类实例。因此,当定义了
Bar1
时,您可以访问某些属性,而无需创建其实例


它是一个子类这一事实根本不起作用。

您可以访问子类属性,原因与执行此操作相同:

>>> class myobj: pass
>>> def f(obj):
        print(obj.a)
>>> obj1, obj2 = myobj(), myobj()
>>> obj1.a, obj2.a = 1, 2
>>> f(obj1)
1
>>> f(obj2)
2
类只是对象。元类只不过是类对象工厂

这是另一个例子。假设我有一个创造者:

你认为这样行吗?如果你说是的,你是对的:

>>> s = MakeMeASandwich(Reuben)
# reuben with mayo!
你为什么认为这会起作用?可能是因为函数没有理由不能访问
mayo
。就在那里。它不是隐藏的。所以,它当然可以做到


再次强调:元类只不过是一个类制造工厂。它与其他工厂非常相似(尽管他们确实有一些你可能不需要的漂亮的额外的铃铛和口哨)

我没有答案,但是你的用户名很搞笑,我笑得很厉害。为什么你不能访问
Bar1.a
?这不是私事。Python甚至没有私有属性。这与
a
无关,但是如果您使用的是Python 3,元类语法是
class Foo(metaclass=ABCMeta):
@hiroprotation谢谢!这一变化有什么原因吗?我试图在文档中找到一些解释,但没有用。@SibbsBombling:除此之外,新语法意味着在输入类主体之前就知道元类,这样就可以存在
\uuuuu prepare\uuuu
之类的东西。您是否意外地重新定义了
对象
?您通常无法向确切类型为
object
@user2357112的对象添加属性。我当时很轻率,很粗心。我会做得更好
>>> Reuben = type('Reuben', (), {'mayo':False}) # <-- shortcut for making a class
>>> def MakeMeASandwich(sandwich_type):
        sandwich_type.mayo = True
        return sandwich_type()
>>> s = MakeMeASandwich(Reuben)
# reuben with mayo!