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