文章目录
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 ... # 后面的略
-
比如说使用
+ - * / %
这些数学符号会触发特殊方法,在自己编写数学相关的类时非常有用