python之类与对象进阶(二)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


类中的特殊函数——魔法函数

(以“__ ” 开头,同时以 “ __ ”结尾)一览表:

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值