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

时间:2015-07-14 13:43:23

标签: 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仍然有效,但它的表现并不像我想要的那样?正如在它被加载,功能“做事”,但它似乎不接受论点。没有括号实例化一个类有什么好处吗?

请注意,我无需帮助使用此代码,我只是想了解为什么会这样。

2 个答案:

答案 0 :(得分:4)

  

有人可以帮助我理解为什么在Python中你需要用括号实例化一个类,即使除了self之外没有构造函数参数。

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

在python中,一切都是一流的对象,甚至是类(和函数!)本身。为了使一个类成为第一个类对象,接下来该类需要它自己的类(metaclass)来定义它的行为。我们将类称为“元类”,以避免在讨论类和类类时产生混淆。

要回答问题的第二部分:当您使用MainViewController代替MainViewController()时会发生“事情”,因为MainViewController 是一个成熟的对象,就像任何其他对象一样。

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

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

class MyClass: 
    pass

执行此操作时,您实际上正在创建metaclass known as type的新实例。

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

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

type元类是所有类的基本元类。所有python“新风格类”(不再那么“新”,因为它们在python 2.1中实现,我相信)属于类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__()

所有用户定义的类都是这种情况,btw;如果在类中包含__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()时,您可以看到__call__ MyMeta方法发生在其他任何事情之前(包括__new__之前和__init__之前) 。

答案 1 :(得分:2)

因为函数调用需要()。执行MyClass()后,您正在呼叫MyClass。表达式MyClass计算类本身,它是一个对象。