文章目录
- 1、成员
- (1)变量
- (2)方法
- 2、嵌套
- 3、主动调用其它类的方法
- 4、特殊成员
- (1)__init\_\_()方法
- (2)__call\_\_()方法
- (3)__getitem\_\_()方法
- (4)__setitem\_\_()方法
- (5)with obj_name as val_name语法
- (6)构造方法__new\_\_()
- (7)其它的
1、成员
(1)变量
- 实例变量(字段/属性)
- 对象实例化后,创建的对象有一个类指针指向内存中的类,因此对象才可以调用类的方法
- 实例变量是对象所私有的
- 实例变量分为公有和私有
- 公有实例变量,即默认的实例变量,在类的内部和外部均可访问
- 私有实例变量,使用字段修饰符的实例变量,在类的外部不可访问
class Foo:
def __init__(self, name, age):
self.name = name # 公有实例变量
self.__age = age # 私有实例变量
# 在外部可以通过下面这种方法访问私有实例变量
obj = Foo("xzj", 123)
print(obj._Foo_name) # 在外部访问私有实例变量的方法
- 类变量(静态字段)
- 在类的定义中创建的变量(普通变量或者函数变量)为类变量
- 类变量是该类所共享的,对象既可以访问实例变量,也可以访问类变量(先查找实例变量),但是类不可以访问实例变量
class Foo:
num = 1 # num为类变量,是该类的共享变量,在类的内外部均可访问
def __init__():
pass
- 类变量也分为公有和私有
- 公有类变量,同公有实例变量类似
- 私有类变量,同私有实例变量类似,例子如下
class Foo:
name = "xzj" # 公有类变量
__age = 21 # 私有类变量
# 在外部访问私有类变量的方法同访问私有实例变量一样
- 私有变量的继承问题
- 派生类可以访问父类的公有变量,但不能访问其私有变量
class Base(Object):
name = "xzj"
__age = 21
def f1(self):
print(self.__age)
class Son(Base):
def f2(self):
print(self._Base__age) # 在派生类内部也不可以直接访问父类的私有变量
obj = Son()
obj.f1() # 这是可以执行的,因为f1函数是在Base内部定义的
(2)方法
- 实例方法:即普通的定义
- 静态方法
- 若方法中没有调用到实例变量,则可以写成静态方法,即该方法与具体对象无关,是该类的公有方法
class Foo(Object):
@staticmethod # 定义静态方法要加上这个
def display(name):
print(name)
Foo.display() # 静态方法可以直接通过类来调用
Foo().display() # 也可以通过对象调用
- 类方法
2、嵌套
- 对象和对象之间是可以嵌套使用的
In [3]: class Stu(object):
...: def __init__(self, name, age):
...: self.name = name
...: self.age = age
...: self.school = None
In [4]: class School(object):
...: def __init__(self, name):
...: self.name = name
...:
In [5]: xx1 = Stu('abc', 20)
In [7]: yy1 = School('university')
In [8]: xx1.school = yy1
In [11]: xx1.school.name
Out[11]: 'university'
3、主动调用其它类的方法
- 调用某个类的方法时可以直接使用
类名.方法(对象)
的方式调用 - 这种用法在一个类中调用其它类的方法时有用
In [12]: class Obj1(object):
...: def __init__(self, name):
...: self.name = name
...: def f1(self):
...: print('f1: ', self.name)
...:
In [13]: xxx = Obj1('aaa')
In [14]: xxx.f1()
f1: aaa
In [15]: Obj1.f1(xxx)
f1: aaa
4、特殊成员
(1)__init__()方法
In [3]: class Foo(object):
...: def __init__(self, name):
...: self.name = name
...:
In [4]: obj = Foo('abc')
- 当实例化对象时自动执行
__init__()
方法
(2)__call__()方法
In [5]: class Foo(object):
...: def __init__(self, name):
...: self.name = name
...: def __call__(self, *args, **kwargs):
...: print('This is __call__()')
...: print(args)
...: print(kwargs)
...:
In [6]: obj = Foo('abc')
In [7]: obj()
This is __call__()
()
{}
In [8]: obj(1,2,3,4, k1='aaa', k2='bbb')
This is __call__()
(1, 2, 3, 4)
{'k1': 'aaa', 'k2': 'bbb'}
-
__call__()
方法在直接使用对象名作为函数时自动调用
(3)__getitem__()方法
- 该方法和列表的索引很像
In [13]: l = [1,2,3,4]
In [14]: l[0]
Out[14]: 1
In [16]: l.__getitem__(0)
Out[16]: 1
- 可以看到列表的索引实际上是调用了
__getitem__()
方法来实现的,所以其它的对象也是有相似语法的
- 例子如下:
In [9]: class Foo(object):
...: def __init__(self, name):
...: self.name = name
...: def __getitem__(self, item):
...: print('The item is: ', item)
...:
In [10]: obj = Foo('abc')
In [11]: obj[123]
The item is: 123
In [12]: obj['hhh']
The item is: hhh
- 当使用如上格式时,会自动调用
__getitem__()
方法
(4)__setitem__()方法
- 该方法和字典的赋值类似
In [17]: dic = {1:100, 2:200}
In [18]: dic[3] = 300
In [19]: dic
Out[19]: {1: 100, 2: 200, 3: 300}
In [20]: dic.__setitem__(4, 400)
In [21]: dic
Out[21]: {1: 100, 2: 200, 3: 300, 4: 400}
- 当我们通过上面的语法给字典赋值时,实际上是调用了
__setitem__()
方法的,同样其它对象也是有类似语法的
- 例子如下
In [22]: class Foo(object):
...: def __init__(self, name):
...: self.name = name
...: def __setitem__(self, key, value):
...: print('The key is: ', key)
...: print('The value is: ', value)
...:
In [23]: obj = Foo('aaa')
In [24]: obj[1] = 100
The key is: 1
The value is: 100
- 使用如上语法时,会自动调用对象的
__setitem__()
方法
(5)with obj_name as val_name语法
- 在文件操作中有一种
with file_obj as f
的语法,实际上是执行了__enter__()
方法和__exit__()
方法 - 这种语法对其它对象也是成立的,例子如下:
In [67]: class Foo(object):
...: def __enter__(self):
...: print('This is __enter__!!')
...: return [1,2,3]
...: def __exit__(self, ex_type, ex_val, tb):
...: print(ex_type)
...: print(ex_val)
...: print(tb)
...: print('This is __exit__!!!')
...:
...:
In [68]: obj = Foo()
In [69]: with obj as ret:
...: print('----\n', ret, '\n----')
...:
This is __enter__!!
----
[1, 2, 3]
----
None
None
None
This is __exit__!!!
with ··· as ···
是上下文管理器的语法with obj
触发__enter__()
方法,传递的参数就是obj
这个对象__enter__()
的返回值会赋给as ret
中的ret
- 当发生异常时会触发
__exit__()
方法
- 需要注意的是
__exit__()
方法的四个参数似乎都必须使用(这里没太懂,如果有知道的,望在评论区告知,万分感谢),一个错误例子如下
In [53]: class Foo(object):
...: def __enter__(self):
...: print('This is __enter__!!')
...: return [1,2,3]
...: def __exit__(self, exc_type, exc_val, exc_tb):
...: print('This is __exit__!!!')
...:
In [54]: with obj as ret:
...: print('------')
...: print(ret)
...: print('------')
...:
This is __enter__!!
------
[1, 2, 3]
------
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-54-e6c137c400ba> in <module>()
2 print('------')
3 print(ret)
----> 4 print('------')
5
TypeError: __exit__() takes 1 positional argument but 4 were given
(6)构造方法__new__()
- 创建对象(对象实例化)时,实际上是先执行了object(所有对象都是继承的object)的
__new__()
方法,这个方法会创建一个空的object
对象,然后再执行__init__()
方法,返回一个Foo
对象(假设我们创建的对象是Foo类的) - 一个例子如下:
In [70]: class Foo(object):
...: def __init__(self, name):
...: print('This is in __init__')
...: self.name = name
...: def __new__(cls, *args, **kwargs):
...: print('This is in __new__')
...: return object.__new__(cls)
...:
In [71]: obj = Foo('aaa')
This is in __new__
This is in __init__
return object.__new__(cls)
中的参数cls
是指Foo
这个类,__new__()
方法会创建一个空对象__new__()
方法返回的值是赋给__init__(self, name)
中的self
__init__(self, name)
方法实际上是初始化对象,而不是构造对象- 下例可以帮助更好理解
In [74]: class Foo(object):
...: def __init__(self, name):
...: print('This is in __init__')
...: self.name = name
...: def __new__(cls, *args, **kwargs):
...: print('This is in __new__')
...: emptyObj = object.__new__(cls)
...: print('emptyObj\'s address is: ', id(emptyObj))
...: return emptyObj
...:
In [75]: obj = Foo('aaa')
This is in __new__
emptyObj's address is: 4580299944
This is in __init__
In [76]: print(id(obj))
4580299944
- 可以看到创建的空对象和初始化后的对象内存地址是相同的
(7)其它的
- 这些特殊方法还有很多,实际上都是当语句满足某种语法时就会执行对象的特定的方法
- 比如说字符串可以相加,
str1 + str2
实际上是执行了__add__()
方法 - 以列表的特殊方法作为例子看一下
class list(object)
| list() -> new empty list
| list(iterable) -> new list initialized from iterable's items
|
| Methods defined here:
|
| __add__(self, value, /)
...
| __contains__(self, key, /)
...
| __delitem__(self, key, /)
...
| __eq__(self, value, /)
...
| __ge__(self, value, /)
...
| __getattribute__(self, name, /)
...
| __getitem__(...)
...
| __gt__(self, value, /)
...
| __iadd__(self, value, /)
...
| __imul__(self, value, /)
...
| __init__(self, /, *args, **kwargs)
...
| __iter__(self, /)
...
| __le__(self, value, /)
...
| __len__(self, /)
...
| __lt__(self, value, /)
...
| __mul__(self, value, /)
...
| __ne__(self, value, /)
...
| __new__(*args, **kwargs) from builtins.type
...
| __repr__(self, /)
...
| __reversed__(...)
...
| __rmul__(self, value, /)
...
| __setitem__(self, key, value, /)
...
| __sizeof__(...)
...
| append(...)
| L.append(object) -> None -- append object to end
... # 后面的略
- 比如说使用
+ - * / %
这些数学符号会触发特殊方法,在自己编写数学相关的类时非常有用