我开始在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
仍然有效,但它的表现并不像我想要的那样?正如在它被加载,功能“做事”,但它似乎不接受论点。没有括号实例化一个类有什么好处吗?
请注意,我无需帮助使用此代码,我只是想了解为什么会这样。
答案 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
计算类本身,它是一个对象。