我是Python新手,主要来自Java编程。
我目前正在思考如何实例化Python中的类。
我理解__init__()
:就像Java中的构造函数一样。但是,有时python类没有__init__()
方法,在这种情况下我假设有一个默认构造函数就像在Java中一样?
使从Java转换到python稍微困难的另一个原因是,在Java中,您必须使用类型定义类的所有实例字段,有时还要定义初始值。在python中,所有这些似乎都消失了,开发人员可以动态定义新的字段。
例如,我遇到过这样的程序:
class A(Command.UICommand):
FIELDS = [
Field( 'runTimeStepSummary', BOOL_TYPE)
]
def __init__(self, runTimeStepSummary=False):
self.runTimeStepSummary = runTimeStepSummary
"""Other methods"""
def execute(self, cont, result):
self.timeStepSummaries = {}
""" other code"""
令人困惑的事情(并且稍微让我感到恼火)是这个A类没有名为timeStepSummaries的字段但是方法中间的开发人员如何才能定义新字段?或者我的理解不正确?
所以要清楚,我的问题是在Python中我们可以在运行时动态地为类定义新字段,就像在这个例子中一样,或者这个timeStepSummaries变量是一个像私有变量一样的java实例吗?
编辑:我正在使用python 2.7
答案 0 :(得分:23)
我理解
__init__()
:就像Java中的构造函数。
更准确地说,Python __new__
是构造函数方法,__init__
是初始化程序。当您执行SomeClass('foo', bar='baz')
时,type.__call__
方法基本上会执行:
def __call__(cls, *args, **kwargs):
instance = cls.__new__(*args, **kwargs)
instance.__init__(*args, **kwargs)
return instance
通常,如果需要,大多数类将定义__init__
,而__new__
更常用于不可变对象。
但是,有时python类没有 init ()方法,在这种情况下,我假设有一个默认构造函数,就像在Java中一样?
我不确定旧式课程,但新式课程就是这种情况:
>>>> object.__init__
<slot wrapper '__init__' of 'object' objects>
如果未定义显式__init__
,则将调用默认值。
所以要清楚,我的问题是在Python中我们可以在运行时动态定义类的新字段,就像在这个例子中一样
是
>>> class A(object):
... def __init__(self):
... self.one_attribute = 'one'
... def add_attr(self):
... self.new_attribute = 'new'
...
>>> a = A()
>>> a.one_attribute
'one'
>>> a.new_attribute
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'new_attribute'
>>> a.add_attr()
>>> a.new_attribute
'new'
可以随时将属性添加到实例中:
>>> a.third_attribute = 'three'
>>> a.third_attribute
'three'
但是,可以限制可以通过类属性__slots__
添加的实例属性:
>>> class B(object):
... __slots__ = ['only_one_attribute']
... def __init__(self):
... self.only_one_attribute = 'one'
... def add_attr(self):
... self.another_attribute = 'two'
...
>>> b = B()
>>> b.add_attr()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in add_attr
AttributeError: 'B' object has no attribute 'another_attribute'
(重要的是要注意__slots__
主要用作内存优化 - 不要求对象具有用于存储属性的字典 - 而不是作为运行的一种形式 - 时间改变预防。)
答案 1 :(得分:4)
Python对象的属性通常存储在字典中,就像您使用{}
创建的那样。由于您可以随时向字典添加新项目,因此您可以随时向对象添加属性。并且由于任何类型的对象都可以存储在字典中,而无需事先声明类型,因此任何类型的对象都可以存储为对象的属性。
简而言之,my_object.abc = 42
(通常)只是my_object.__dict__["abc"] = 42
的简写。
可以通过定义__dict__
属性来定义没有__slots__
的对象,或者以某种其他方式覆盖某些特殊方法和存储属性,尽管大多数时候你不应该这样做这一点。
答案 2 :(得分:0)
这个答案适用于新式Python类,它是object
的子类。 2.2中添加了新式类,它们是PY3中唯一可用的类。
>>> print object.__doc__
The most base type
类本身是元类的实例,通常是type
:
>>> print type.__doc__
type(object) -> the object's type
type(name, bases, dict) -> a new type
根据上述docstring,您可以直接实例化元类以创建类:
>>> Test = type('Test', (object,), {'__doc__': 'Test class'})
>>> isinstance(Test, type)
True
>>> issubclass(Test, object)
True
>>> print Test.__doc__
Test class
调用类由元类__call__
方法处理,例如type.__call__
。这反过来调用类__new__
构造函数(通常是继承的)和调用参数,以便创建实例。然后它调用__init__
,它可以设置实例属性。
大多数对象都有__dict__
,可以动态设置和删除属性,例如self.value = 10
或del self.value
。通常不好的形式是直接修改对象的__dict__
,并且实际上不允许类(即包括类dict以禁用直接修改)。如果您需要动态访问属性,请使用built-in functions getattr
,setattr
和delattr
。
数据模型为customizing attribute access定义了以下特殊方法:__getattribute__
,__getattr__
,__setattr__
和__delattr__
。类还可以定义描述符协议方法__get__
,__set__
和__delete__
,以确定其实例作为属性的行为方式。请参阅descriptor guide。
查找属性时,object.__getattribute__
首先使用类的C3 method resolution order搜索对象的类和基类:
>>> Test.__mro__
(<class '__main__.Test'>, <type 'object'>)
请注意,类中定义的数据描述符(例如,插槽的property
或member
)优先于实例dict。另一方面,非数据描述符(例如,函数)或非描述符类属性可以由实例属性遮蔽。例如:
>>> Test.x = property(lambda self: 10)
>>> inspect.isdatadescriptor(Test.x)
True
>>> t = Test()
>>> t.x
10
>>> t.__dict__['x'] = 0
>>> t.__dict__
{'x': 0}
>>> t.x
10
>>> Test.y = 'class string'
>>> inspect.isdatadescriptor(Test.y)
False
>>> t.y = 'instance string'
>>> t.y
'instance string'
使用super
代理方法解析顺序中下一个类的属性访问权限。例如:
>>> class Test2(Test):
... x = property(lambda self: 20)
...
>>> t2 = Test2()
>>> t2.x
20
>>> super(Test2, t2).x
10