Skip to main content
 首页 » 编程设计

python之为什么没有构造函数参数的类需要括号

2025年05月04日13Terrylee

我开始学习 PHP 编程/OOP。据我对 PHP 最佳实践的了解,如果类不带任何参数,您可以在不带括号的情况下对其进行实例化。

比如

$class = new Class; 

相对于:

$class = new Class(); 

我开始将我的技能扩展到 python,并且昨天浪费了大约 5 个小时试图弄清楚为什么一个函数不会传递参数,即使它非常简单。我的代码:

class MainViewWidgets(MainViewContainer): 
 
    def __init__(self): 
        # instantiating like this prevents MainViewController.getHeaderItems from returning the arg passed to it, however the code still "works" in some sense 
        self.controller = MainViewController  
 
        #this works 
        self.controller = MainViewController() 
 
    def createHeaderOptionCheckbox(self, pane): 
        self.header_string = StringVar() 
        header_checkbox = ttk.Checkbutton(pane, text='Data Contains Headers', variable=self.header_string, onvalue='headers', offvalue='keys') 
        self.header_string.trace('w', self.headerOptionCheckboxChanged) 
        return header_checkbox 
 
    def headerOptionCheckboxChanged(self, *args): 
        print(self.header_string.get()) 
        #will print "headers" or "keys" on checkbox toggle 
        print(self.controller.getHeaderItems(self.header_string.get())) 
        #prints "default" 
 
class MainViewController: 
 
    def __init__(self): 
        self.CheckFile = CheckFile() 
        get_config = GetConfiguration('config.ini') 
        self.config_file = get_config.getProperty('directory', 'input_file') 
        self.csv = CSVReader(self.config_file) 
        self.chosen_index = None 
 
    def getHeaderItems(self, header='default'): 
        return header 

谁能帮我理解为什么在 Python 中你需要用括号实例化一个类,即使除了 self 之外没有构造函数参数。另外,为什么 MainViewController 仍然可以正常工作,但它的行为并不像我想要的那样?因为它被加载了,函数“做了事情”,但它似乎不接受参数。实例化一个没有括号的类有什么好处吗?

请注意,我不需要帮助让这段代码工作,我只是想了解为什么会这样。

请您参考如下方法:

Can someone please help me understand why in Python you need to instantiate a class with parenthesis even if there are no constructor arguments other than self.

原因很简单:当你实例化一个对象时,你实际上是在调用它的类(它本身就是一个对象),并且你使用()调用对象。

在 python 中,一切都是一等对象,甚至是类(和函数!)本身。为了使类成为第一类对象,类需要自己的类 (metaclass) 来定义其行为。我们称类的类为“元类”,以免在谈论类和类的类时混淆。

回答问题的第二部分:当您使用 MainViewController 而不是 MainViewController() 时,“事情”正在发生,因为 MainViewController < em>是一个成熟的对象,就像任何其他对象一样。

所以您可能会问:MainViewController 对象的类(实际上是元类)是什么?


如您所知,您可以像这样创建一个类:

class MyClass:  
    pass 

当您这样做时,您实际上是在创建一个新的 metaclass known as type 实例。 .

请注意,您可以通过这种方式创建相同的类;从字面上看,下面和上面没有区别:

MyClass = type('MyClass', (object,), {})  

type 元类是所有类的基础元类。所有 python“新样式类”(我相信它们是在 python 2.1 中实现的,所以不再那么"new"了)都是 type 类:

print(type(MyClass)) # type 
print(type(list)) # type 
print(type(int)) # type 
# Note that above, type is being used as a "function" (it's really just a callable) 

有趣的是,type 甚至是它自己的元类:

print(type(type)) # type 

所以重申一下:MyClass类实际上是type的实例化。然后,调用 类会导致运行其元类的 __call__ 方法。

当你这样做时:

obj = MyClass() 

...您正在调用 MyClass,这导致(在后台)运行方法type.__call__()。

所有用户定义的类都是这种情况,顺便说一句;如果你在你的类中包含了 __call__ 方法,那么你的类是可调用的,当你调用类实例时会执行 __call__ 方法:

class MyCallable(): 
    def __call__(self): 
        print("You rang?")  
 
my_instance = MyCallable() 
my_instance() # You rang? 

您可以在实际操作中看到这一点。如果您通过子类化 type 创建您自己的元类,则当创建基于您的自定义元类的类实例时,您可能会导致事情发生。例如:

class MyMeta(type): 
    def __call__(self, *args, **kwargs): 
        print "call: {} {} {}".format(self, args, kwargs) 
        return super().__call__(*args, **kwargs) 
 
# Python 3:  
 
class MyClass(metaclass = MyMeta): 
    pass 
 
# Python 2:  
 
class MyClass(): 
    __metaclass__ = MyMeta 
    pass 

现在当你执行 MyClass() 时,你可以看到 MyMeta 的 __call__ 方法发生在其他任何事情之前(包括在 __new__ 和 __init__ 之前)。