1、类的特殊成员方法
- _ modle _: 表示当前操作对象在哪个模块
_ class _: 表示当前操作的对象的类是什么
class C:
def __init__(self):
self.name = 'severen'
from lib.aa import C
obj = C()
print(obj.__module__) # 输出 lib.aa,即:输出模块
print(obj.__class__) # 输出 lib.aa.C,即:输出类
- _ doc _: 打印描述信息
- _ call _: 构造方法的执行是由创建对象触发的,即对象 = 类名();而对于__call___方法的执行是由对象后面加(),即对象()或类()()
- _ dict _: 查看类中或对象中所有的成员。通过类打印类里面的所有属性,不包括实例属性;通过实例调用,打印所有实例属性,不包括类属性
- _ str _: 打印对象时,默认输出该方法的返回值
# Author: Mr.Xue
# 2019.10.29
class Dog(object):
"""this is a class: Dog (描述信息)"""
def __init__(self, name):
self.name = name
def eat(self, food):
print("%s is eating %s" % (self.name, food))
def __call__(self, *avgv, **kwargv):
print("hello", avgv, kwargv)
def __str__(self):
return "helllo" + self.name
print(Dog.__dict__) # 查看类中所有的成员
print(Dog("bob").__dict__) # 查看对象中的所有成员
d = Dog("Bob")
print(d) #打印对象,输出__str__方法的返回值
print(d.__doc__) # 打印描述信息
d() # 执行__call__()方法
运行结果如下:
xue@xue-MacBookAir:~/python_learn$ python3 static_method.py
{'__init__': <function Dog.__init__ at 0x7f05cadd5730>, 'eat': <function Dog.eat at 0x7f05cadd57b8>, '__str__': <function Dog.__str__ at 0x7f05cadd58c8>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': 'this is a class: Dog (描述信息)', '__module__': '__main__', '__call__': <function Dog.__call__ at 0x7f05cadd5840>, '__dict__': <attribute '__dict__' of 'Dog' objects>}
{'name': 'bob'}
hellloBob
this is a class: Dog (描述信息)
hello () {}
- _ _ getitem _ _ 、_ _ setitem _ _ 、_ _ delitem _ _ : 用于索引操作
class Foo(object):
def __init__(self):
self.data = {}
def __getitem__(self, key):
print('__getitem__', key)
return self.data.get(key)
def __setitem__(self, key, value):
print('__setitem__', key, value)
self.data[key] = value
def __delitem__(self, key):
print('__delitem__', key)
obj = Foo()
obj['name'] = 'xue' # 调setitem
print(obj.data)
print(obj['name']) # 调getitem
del obj['name'] # 调delitem
- _ new _ 和 _ metaclass _
class Foo(object):
def __init__(self,name):
self.name = name
f = Foo("severen")
上述代码中,f 是通过 Foo 类实例化的对象,其实,不仅 f 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。
如果按照一切事物都是对象的理论:f对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建的。
print(type(f)) # 输出:<class '__main__.Foo'> 表示,obj 对象由Foo类创建
print(type(Foo)) # 输出:<type 'type'> 表示,Foo类对象由 type 类创建
所以,f对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。
在这里补充一下类的创建方式其实有两种,如下
# 第1种方式
class Foo(object):
def func(self):
print('hello severen')
# ----------------------------------
# 第2种方式
def func(self):
print("hello world")
def __init__(self, name):
self.name = name
print("---")
Foo = type("Foo", (object,), {"func": func, '__init__': __init__})
f = Foo('Bob')
f.func()
到这里,我们知道了类默认是由 type 类实例化产生,那么type类对象又是由谁来创建产生的呢?type类中如何实现的创建类?类又是如何创建对象?
答:类中有一个属性 _ metaclass_,其用来表示该类由 谁 来实例化创建,所以,我们可以为 _ metaclass_ 设置一个type类的派生类,从而查看 类 创建的过程。
# Author: Mr.XUe
# 2019.10.30
class MyType(type):
def __init__(self, what, base=None, dict=None):
print("--MyType init--")
super(MyType, self).__init__(what, base, dict)
def __call__(self, *argv, **kwargv):
print("--MyType call--")
obj = self.__new__(self, *argv, **kwargv)
# obj.data = {'name': 111}
self.__init__(obj)
class Foo(object):
__metaclass__ = MyType
def __init__(self, name):
self.name = name
def __new__(cls, *argv, *kwargv):
# 这一块可以添加自己的小功能
return object.__new__(cls, argv, kwargv) # 继承父类的__new__方法
obj = Foo("bob")
metaclass参考文章:https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python
2、动态导入模块
好处:简化导入自定义模块的导入步骤
举例:在A目录下有lib文件夹和dong态导入模块.py文件,在lib文件夹下又有__init__.py和aa.py两个文件,init.py文件没有内容,aa.py的代码如下:
# Author: Mr.Xue
# 2019.10.31
# aa.py
class C(object):
def __init__(self):
self.name = 'xue'
现在我们的需求是dong态导入模块.py文件需要去导入aa.py文件。
逻辑分析:按照正常的逻辑,我们首先需要去获取到dong态导入模块.py文件的父目录,在通过父目录我们可以找到lib,最后通过lib才可以找到aa.py,程序代码如下:
# Author: Mr.Xue
# 2019.10.31
# dong态导入模块.py
#!usr/bin/python3
import os,sys
# __file__: 当前文件
# os.path.abspath: 获取当前文件的绝对路径
# os.path.dirname: 获取上一级的路径
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # BASE_DIR现在A所在的绝对路径
sys.path.append(BASE_DIR) # 将该路径写入环境
from lib import aa # 导入aa.py文件
print(aa.C().name) # 打印C类的对象属性name
上面这一种导入的方式写起来就比较繁琐复杂,现在我们来看看动态导入模块的写法,代码如下:
# Author: Mr.Xue
# 2019.10.29
# dong态导入模块.py
# ------解释器自己内部使用的
#lib = __import__("lib.aa")
#print(lib)
#print(lib.aa.C().name)
# -------官方建议使用的
import importlib # 导入importlib库
aa = importlib.import_module("lib.aa") # 导入aa.py文件
#print(aa) # 打印aa的内存地址
print(aa.C().name) # 打印C类的对象属性name
是不是很简单,短短的三行代码就完成了,逻辑上也很简单。两种方式的运行结果都是一样的,如下所示:
xue@xue-MacBookAir:~/python_learn/A$ python3 dong态导入模块.py
xue
3、assert 断言
使用断言可以创建更稳定、品质更好且不易于出错的代码。当需要在一个值为FALSE时中断当前操作的话,可以使用断言
看一个简单的例子:
# Author: Mr.Xue
# 2019.10.31
class A(object):
def __init__(self, name):
self.name = name
a = A("xue")
# 判断name属性的值是不是str类型的,如果是,执行下一步,否则,阻断在这里
assert type(a.name) is str
print(a.name)
上面的条件成立,所以会打印name的值,“xue”;否则,阻塞