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

标签 python oop tkinter

我开始学习 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__ 之前)。

关于python - 为什么没有构造函数参数的类需要括号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31408433/

相关文章:

ruby - 这两段代码有什么区别?

python - 在 Amazon Linux 上安装 Tkinter

python - 为什么我在进行此 api 调用时得到类型方法的对象不可 JSON 序列化

python - 程序结束后保持 matplotlib 图形打开

java - 改变继承的super方法

php - 获取对象字段的更短符号

python - macOS tkinter : how does filetypes of askopenfilename work

python - 如何更改 Button 小部件的文本大小?

python - 是否可以动态定义函数参数的名称?

python - "AttributeError: ' SelectorList ' object has no attribute ' 在Scrapy Cloud中获取'"