Python 的类内置了一些通用的属性和方法,方便我们进行操作和对类的管理。我们可以使用dir(ClassName)来查看这些属性和方法,其中前后双下划线的如__dir__就是内置的。
类的专有方法
- 特殊方法,也称为魔术方法
- 特殊方法都是使用__开头和结尾的
- 特殊方法一般不需要我们手动调用,需要在一些特殊情况下自动执行
__doc
__doc__ 可以返回类的介绍,这个介绍是我们之前在定义类时写的注释,帮助我们记住类的作用和使用方法,也可以写一些使用例子,我们接触三方库时,可以通过它查看它的介绍。
tom = Student('tome')
tom.__doc__
# '这是一个学生类'
__new
new 和 init 在类在实例化过程中都会被调用的方法,会先调用 new 函数再调用 init 函数。 __new__ 会创建对象,相当于构造器,起创建一个类实例的作用,__init__ 作为初始化器,负责对象的初始化。
new 的第一个参数是 cls 是类自身,init 是 self,是实例。一般情况下,我们很少需要自己编写 new,只需要关注 init 实例初始化。
new 是静态函数,init 是实例函数。如果,new 函数不返回实例对象,那么 init 函数就不会被调用:
class A(object):
def __new__(cls):
print("A.__new__ called")
# return super().__new__(cls)
def __init__(self):
print("A.__init__ called")
s = A()
print(s)
# A.__new__ called
# None
另外 init 函数只能返回 None,否则会引起 TypeError。
__init__
- 类有一个名为 __init__() 的特殊方法(构造方法),该方法在类实例化时会自动调用,我们一般在这里进行属性的初始化操作:
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
- __init__() 第一个参数永远是self,表示创建的实例本身(self 不是 python 关键字,我们把他换成 runoob 也是可以正常执行的)
- 当然, __init__() 方法可以有参数,参数通过 __init__() 传递到类的实例化操作上。例如:
#!/usr/bin/python3
class Complex:
def __init__(self, realpart, imagpart):
self.r = realpart
self.i = imagpart
x = Complex(3.0, -4.5)
print(x.r, x.i) # 输出结果:3.0 -4.5
类的方法与普通的函数只有一个特别的区别——第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。
class Test:
def prt(self):
print(self)
print(self.__class__)
t = Test()
t.prt()
以上实例执行结果为:
<__main__.Test instance at 0x100771878>
__main__.Test
从执行结果可以很明显的看出,self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类。
__call
__call__ 可以让实例对象像函数那样可被执行,callable(lily) 默认是不能被执行的,我们重写 call 。
class Student(object):
def __init__(self, a, b):
self.name = a
self.age = b
super(Student, self).__init__()
def __call__(self):
self.age += 1
print('我能执行了')
# 实例化
lily = Student('lily', 18)
callable(lily)
# True
lily()
# 我能执行了
lily.age
# 19
__str__
我们先定义一个Student类,打印一个实例:
>>> class Student(object):
... def __init__(self, name):
... self.name = name
...
>>> print(Student('Michael'))
<__main__.Student object at 0x109afb190>
打印出一堆<main.Student object at 0x109afb190>,不好看。
怎么才能打印得好看呢?只需要定义好__str__()方法,返回一个好看的字符串就可以了:
>>> class Student(object):
... def __init__(self, name):
... self.name = name
... def __str__(self):
... return 'Student object (name: %s)' % self.name
...
>>> print(Student('Michael'))
Student object (name: Michael)
__repr__
但是直接敲变量不用print,打印出来的实例还是不好看:
>>> s = Student('Michael')
>>> s
<__main__.Student object at 0x109afb310>
这是因为直接显示变量调用的不是__str__(),而是__repr__(),两者的区别是__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。
解决办法是再定义一个__repr__()。但是通常__str__()和__repr__()代码都是一样的,所以,有个偷懒的写法:
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name=%s)' % self.name
__repr__ = __str__
__iter__
如果一个类想被用于for … in循环,类似list或tuple那样,就必须实现一个 __iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的 __next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
我们以斐波那契数列为例,写一个Fib类,可以作用于for循环:
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1 # 初始化两个计数器a,b
def __iter__(self):
return self # 实例本身就是迭代对象,故返回自己
def __next__(self):
self.a, self.b = self.b, self.a + self.b # 计算下一个值
if self.a > 100000: # 退出循环的条件
raise StopIteration()
return self.a # 返回下一个值
调用:
>>> for n in Fib():
... print(n)
__getitem__
__getattr__
__del__
# 在Python中有自动的垃圾回收机制,它会自动将这些没有被引用的对象删除,
# 所以我们不用手动处理垃圾回收
class A:
def __init__(self):
self.name = 'A类'
# del是一个特殊方法,它会在对象被垃圾回收前调用
def __del__(self):
print('A()对象被删除了~~~',self)
a = A()
b = a # 又使用一个变量b,来引用a对应的对象
print(a.name)
# a = None # 将a设置为了None,此时没有任何的变量对A()对象进行引用,它就是变成了垃圾
# b = None
# del a
# del b
input('回车键退出...')
运算符重载
# object.__add__(self, other)
# object.__sub__(self, other)
# object.__mul__(self, other)
# object.__matmul__(self, other)
# object.__truediv__(self, other)
# object.__floordiv__(self, other)
# object.__mod__(self, other)
# object.__divmod__(self, other)
# object.__pow__(self, other[, modulo])
# object.__lshift__(self, other)
# object.__rshift__(self, other)
# object.__and__(self, other)
# object.__xor__(self, other)
# object.__or__(self, other)
# object.__lt__(self, other) 小于 <
# object.__le__(self, other) 小于等于 <=
# object.__eq__(self, other) 等于 ==
# object.__ne__(self, other) 不等于 !=
# object.__gt__(self, other) 大于 >
# object.__ge__(self, other) 大于等于 >=
__lt__
# inside class Card :
# 在 Card 类 内 部:
def __lt__ ( self , other ) :
# check the suits
# 判 断 花 色
if self.suit < other.suit : return True
if self.suit > other.suit : return False
# suits are the same ... check ranks
# 花 色 相 同 ... 判 断 等 级
return self.rank < other.rank
# __gt__会在对象做大于比较的时候调用,该方法的返回值将会作为比较的结果
# 他需要两个参数,一个self表示当前对象,other表示和当前对象比较的对象
# self > other
def __gt__(self , other):
return self.age > other.age
# print(p1 > p2)
# print(p2 > p1)
__bool__
# object.__bool__(self)
# 可以通过bool来指定对象转换为布尔值的情况
def __bool__(self):
return self.age > 17
其他
类还有以下方法:
# 类名称的字符
Student.__name__
# 'Student'
类的普通方法
- 在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例。
- 方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据
- 通过在实例上调用方法,我们就直接操作了对象内部的数据,但无需知道方法内部的实现细节。
# 定义一个类
class A(object):
# 类属性
# 实例属性
# 类方法
# 实例方法
# 静态方法
# 类属性,直接在类中定义的属性是类属性
# 类属性可以通过类或类的实例访问到
# 但是类属性只能通过类对象来修改,无法通过实例对象修改
count = 0
def __init__(self):
# 实例属性,通过实例对象添加的属性属于实例属性
# 实例属性只能通过实例对象来访问和修改,类对象无法访问修改
self.name = '孙悟空'
# 实例方法
# 在类中定义,以self为第一个参数的方法都是实例方法
# 实例方法在调用时,Python会将调用对象作为self传入
# 实例方法可以通过实例和类去调用
# 当通过实例调用时,会自动将当前调用对象作为self传入
# 当通过类调用时,不会自动传递self,此时我们必须手动传递self
def test(self):
print('这是test方法~~~ ' , self)
# 类方法
# 在类内部使用 @classmethod 来修饰的方法属于类方法
# 类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象
# 类方法和实例方法的区别,实例方法的第一个参数是self,而类方法的第一个参数是cls
# 类方法可以通过类去调用,也可以通过实例调用,没有区别
@classmethod
def test_2(cls):
print('这是test_2方法,他是一个类方法~~~ ',cls)
print(cls.count)
# 静态方法
# 在类中使用 @staticmethod 来修饰的方法属于静态方法
# 静态方法不需要指定任何的默认参数,静态方法可以通过类和实例去调用
# 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
# 静态方法一般都是一些工具方法,和当前类无关
@staticmethod
def test_3():
print('test_3执行了~~~')
a = A()
# 实例属性,通过实例对象添加的属性属于实例属性
# a.count = 10
# A.count = 100
# print('A ,',A.count)
# print('a ,',a.count)
# print('A ,',A.name)
# print('a ,',a.name)
# a.test() 等价于 A.test(a)
# A.test_2() 等价于 a.test_2()
A.test_3()
a.test_3()