提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
类中的特殊函数——魔法函数
(以“__ ” 开头,同时以 “ __ ”结尾)一览表:
1. __ new __:
现在可以不用知道怎么用,只要知道它和 __ init __差不多就行了。
2. __ repr __:
当执行print一个实例对象时,会默认执行这个函数。这个方法默认输出的是“类名+object at+内存地址”。如:
class CLanguage:
pass
clangs = CLanguage()
print(clangs)
结果为:
<__main__.CLanguage object at 0x000001A7275221D0>
和 __ init __(self) 的性质一样,Python 中的每个类都包含 repr() 方法,因为 object 类包含 __ reper __() 方法,而 Python 中所有的类都直接或间接继承自 object 类。
可以对改方法重写,输出想要的信息:
class CLanguage:
def __init__(self):
self.name = "C语言中文网"
self.add = "http://c.biancheng.net"
def __repr__(self):
return "CLanguage[name="+ self.name +",add=" + self.add +"]"
clangs = CLanguage()
print(clangs) #或者 print(clangs.__repr__())也是一样的
输出为:
CLanguage[name=C语言中文网,add=http://c.biancheng.net]
3. __ del __() :
功能正好和 __ init __() 相反,其用来销毁实例化对象,当执行“del 对象名”时默认执行该函数。
注意:当程序中有其它变量引用该实例对象时,即便手动为该实例调用 __ del __() 方法,该方法也不会立即执行。这是因为:每个 Python 对象都会配置一个计数器,初始 Python 实例对象的计数器值都为 0,如果有变量引用该实例对象,其计数器的值会加 1,依次类推;反之,每当一个变量取消对该实例对象的引用,计数器会减 1。如果一个 Python 对象的的计数器值为 0,则表明没有变量引用该 Python 对象,即证明程序不再需要它,此时 Python 就会自动调用 __ del __() 方法将其回收。
例:
class CLanguage:
def __init__(self):
print("调用 __init__() 方法构造对象")
def __del__(self):
print("调用__del__() 销毁对象,释放其空间")
clangs = CLanguage()
#添加一个引用clangs对象的实例对象
cl = clangs
del clangs #因为cl引用了clangs,即使对clangs调用了del,也不会执行__del__,只有当该类引用计数为0 # 时才会调用
print("***********")
结果为:
调用 __init__() 方法构造对象
***********
调用__del__() 销毁对象,释放其空间
如果在上述程序结尾增加:
del cl
print("-----------")
则输出:
调用 __init__() 方法构造对象
***********
调用__del__() 销毁对象,释放其空间
-----------
还需注意一点:如果我们重写子类的 __ del __() 方法(父类为非 object 的类),则必须显式调用父类的 __ del __() 方法
,这样才能保证在回收子类对象时,其占用的资源(可能包含继承自父类的部分资源)能被彻底释放。为了说明这一点,这里举一个反例:
class CLanguage:
def __del__(self):
print("调用父类 __del__() 方法")
class cl(CLanguage):
def __del__(self):
print("调用子类 __del__() 方法")
c = cl()
del c
执行结果为:
调用子类 __del__() 方法
正确做法应为:
class CLanguage:
def __del__(self):
print("调用父类 __del__() 方法")
class cl(CLanguage):
def __del__(self):
CLanguage.__del__(self)
print("调用子类 __del__() 方法")
c = cl()
del c
结果为:
调用父类 __del__() 方法
调用子类 __del__() 方法
4. __ dir __:
当对某一对象调用dir() 函数时,默认执行__dir__方法,该方法会默认返回一个包含所有属性名和方法名的列表。
同时dir()函数会对该方法返回的属性名和方法名做排序然后输出。注意:它不仅仅输出本类中新添加的属性名和方法,还会输出从父类继承得到的属性名和方法名。
class CLanguage:
global_name = "python"
global_add = "abc"
def __init__ (self,):
self.name = "C语言中文网"
self.add = "http://c.biancheng.net"
def say(self):
pass
clangs = CLanguage()
print(clangs.__dir__()) #或者执行dir(clangs)
输出为:
['name', 'add', 'global_name', 'global_add', '__module__', '__init__', 'say', '__dict__', '__weakref__', '__doc__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
其中,name、add、say都是该类自带的属性和方法,其他的为继承自object类的。
5. __ dict __:
和 __ dir __() 一样,都可以返回类的属性(属性=变量)和方法,但 __ dict __返回的是字典,它以属性名为key,以其值为value。(注意:调用__dict__时,不要像__dir__()一样加括号
)
class CLanguage:
a = 1
b = 2
def __init__ (self):
self.name = "C语言中文网"
self.add = "http://c.biancheng.net"
#通过类名调用__dict__
print(CLanguage.__dict__)
#通过类实例对象调用 __dict__
clangs = CLanguage()
print(clangs.__dict__)
输出为:
{'__module__': '__main__', 'a': 1, 'b': 2, '__init__': <function CLanguage.__init__ at 0x0000022C69833E18>, '__dict__': <attribute '__dict__' of 'CLanguage' objects>, '__weakref__': <attribute '__weakref__' of 'CLanguage' objects>, '__doc__': None}
{'name': 'C语言中文网', 'add': 'http://c.biancheng.net'}
可以发现:该属性可以用类名或者类的实例对象来调用,用类名直接调用 __ dict __,会输出该由类中所有类属性组成的字典;而使用类的实例对象调用 __ dict __,会输出由类中所有实例属性组成的字典。这一点和__dir__()也不同,__dir__()既可以用类名访问,也可以用实例对象访问,但最终输出的都是包含类属性和实例属性
6. __ call __ :
类似于给对象重载了"()"。
class CLanguage:
# 定义__call__方法
def __call__(self,name,add):
print("调用__call__()方法",name,add)
clangs = CLanguage()
clangs("C语言中文网","http://c.biancheng.net")# 也可以调用clangs.__call__("C语言中文网","http://c.biancheng.net")
执行结果为:
调用__call__()方法 C语言中文网 http://c.biancheng.net
7. 三个常用函数:setattr()、getattr()、hasattr()
hasattr() 函数用来判断某个类实例对象
是否包含指定名称的属性或方法。该函数的语法格式如下:
hasattr(obj, name)
例如:
class CLanguage:
global_name = "python"
def __init__ (self):
self.name = "C语言中文网"
self.add = "http://c.biancheng.net"
def say(self):
print("我正在学Python")
clangs = CLanguage()
print(hasattr(clangs,'global_name'))
print(hasattr(clangs,"name"))
print(hasattr(clangs,"add"))
print(hasattr(clangs,"say"))
结果为:
True
True
True
True
getattr() 函数获取某个类实例对象中指定属性的值。没错,和 hasattr() 函数不同,该函数只会从类对象
包含的所有属性中进行查找。
语法格式如下:
getattr(obj, name[, default])
其中,obj 表示指定的类实例对象,name 表示指定的属性名,而 default 是可选参数,用于设定该函数的默认返回值,即当函数查找失败时,如果不指定 default 参数,则程序将直接报 AttributeError 错误,反之该函数将返回 default 指定的值。
class CLanguage:
global_name = "python"
def __init__ (self):
self.name = "C语言中文网"
self.add = "http://c.biancheng.net"
def say(self):
print("我正在学Python")
clangs = CLanguage()
print(getattr(clangs,"global_name"))
print(getattr(clangs,"name"))
print(getattr(clangs,"add"))
print(getattr(clangs,"say"))
print(getattr(clangs,"display",'nodisplay'))
输出:
python
C语言中文网
http://c.biancheng.net
<bound method CLanguage.say of <__main__.CLanguage object at 0x00000225386D6550>>
nodisplay
setattr() 函数的功能相对比较复杂,它最基础的功能是修改类实例对象中的属性值。其次,它还可以实现为实例对象动态添加属性或者方法。
setattr() 函数的语法格式如下:
setattr(obj, name, value)
例如:
def say(self): #必须要有self
print("我正在学Python")
class CLanguage:
def __init__ (self):
self.name = "C语言中文网"
self.add = "http://c.biancheng.net"
clangs = CLanguage()
print(clangs.name)
print(clangs.add)
setattr(clangs,"name",say)
setattr(clangs,"add", "abc")
setattr(clangs,"other","C语言中文网")
clangs.name(clangs)
print(clangs.add)
print(clangs.other)
输出:
C语言中文网
http://c.biancheng.net
我正在学Python
abc
C语言中文网
可以发现:利用 setattr() 函数,可以将类属性修改为一个类方法,同样也可以将类方法修改成一个类属性;同时,当没有某个属性或方法时,它给该实例对象动态添加一个指定名称的属性或方法。
8. issubclass和isinstance函数:检查类型
- issubclass(cls, class_or_tuple):检查 cls 是否为后一个类或元组包含的多个类中任意类的子类。
- isinstance(obj, class_or_tuple):检查 obj 是否为后一个类或元组包含的多个类中任意类的对象。
例如:
hello = "Hello";
# "Hello"是str类的实例,输出True
print('"Hello"是否是str类的实例: ', isinstance(hello, str))
# "Hello"是object类的子类的实例,输出True
print('"Hello"是否是object类的实例: ', isinstance(hello, object))
# str是object类的子类,输出True
print('str是否是object类的子类: ', issubclass(str, object))
# "Hello"不是tuple类及其子类的实例,输出False
print('"Hello"是否是tuple类的实例: ', isinstance(hello, tuple))
# str不是tuple类的子类,输出False
print('str是否是tuple类的子类: ', issubclass(str, tuple))
# 定义一个列表
my_list = [2, 4]
# [2, 4]是list类的实例,输出True
print('[2, 4]是否是list类的实例: ', isinstance(my_list, list))
# [2, 4]是object类的子类的实例,输出True
print('[2, 4]是否是object类及其子类的实例: ', isinstance(my_list, object))
# list是object类的子类,输出True
print('list是否是object类的子类: ', issubclass(list, object))
# [2, 4]不是tuple类及其子类的实例,输出False
print('[2, 4]是否是tuple类及其子类的实例: ', isinstance([2, 4], tuple))
# list不是tuple类的子类,输出False
print('list是否是tuple类的子类: ', issubclass(list, tuple))
issubclass() 和 isinstance() 两个函数的第二个参数都可使用元组。例如如下代码:
data = (20, 'fkit')
print('data是否为列表或元组: ', isinstance(data, (list, tuple))) # True
# str不是list或者tuple的子类,输出False
print('str是否为list或tuple的子类: ', issubclass(str, (list, tuple)))
# str是list或tuple或object的子类,输出True
print('str是否为list或tuple或object的子类 ', issubclass(str, (list, tuple, object)))
9. 重载运算符相关的实例
class MyClass: #自定义一个类
def __init__(self, name , age): #定义该类的初始化函数
self.name = name #将传入的参数值赋值给成员交量
self.age = age
def __str__(self): #用于将值转化为字符串形式,等同于 str(obj)
return "name:"+self.name+";age:"+str(self.age)
__repr__ = __str__ #转化为供解释器读取的形式
def __lt__(self, record): #重载 self<record 运算符
if self.age < record.age:
return True
else:
return False
def __add__(self, record): #重载 + 号运算符
return MyClass(self.name, self.age+record.age)
myc = MyClass("Anna", 42) #实例化一个对象 Anna,并为其初始化
mycl = MyClass("Gary", 23) #实例化一个对象 Gary,并为其初始化
print(repr(myc)) #格式化对象 myc,
print(myc) #解释器读取对象 myc,调用 repr
print (str (myc)) #格式化对象 myc ,输出"name:Anna;age:42"
print(myc < mycl) #比较 myc<mycl 的结果,输出 False
print (myc+mycl) #进行两个 MyClass 对象的相加运算,输出 "name:Anna;age:65"
输出为:
name:Anna;age:42
name:Anna;age:42
name:Anna;age:42
False
name:Anna;age:65