python中类中常见的特殊成员

# 类的特殊成员
class gg:
    '''
    这里都是特殊类成员方法,在触发后这些方法都根据这些方法自动传递的参数就行代码的编写
    '''
    #print(gg.__doc__)  # 查看类的描述信息
    def __init__(self,name):  #初始化对象  #类名() 创建对象的时候自动创建
        self.name = name
        self.data = {'key':'cisco'}#定义一个类中的字典

    def __call__(self, *args, **kwargs):  #触发执行,使用  对象() 就会自动执行该方法的内容
        print('call 触发后执行这里的代码')


    def __getitem__(self, item):# 使用对象['key'] 后自动调用, 会将'key' 的值传到item
        print('随你喜欢,你可以对传递过来的值任意蹂躏')
        return self.data[item]

    def __setitem__(self, key, value): #对象['key'] = 'value'  后会自动调用,像字典一样传值到对应的参数中
        print(key,value ,'进行自由的代码操作的,拿到这两个值之后可以随便操作')
        self.data[key] = value

    def __delitem__(self, key):# 像字典一样,使用del 对象['key']  会自动执行
        print('我是%s,如果喜欢可以按照字典的方式对类的key进行删除如下:'%key)
        del self.data[key]



    def __enter__(self): #使用with 对象 + as b 的时候 自动调用
        print('进来了,自动执行后的随意代码区,可以随便编写')

    def __exit__(self, exc_type, exc_val, exc_tb):#使用with 对象 + as b 的时候 自动调用
        print('出去了,自动执行后的随意代码区,可以随便编写')

    def __add__(self, other):  # 两个对象相加的的时候进行调用
        print('自动执行后的随意代码区,可以随便编写')

    def __str__(self): #在对应对象的时候调用并返回相应的return后面的 内容 通过打印调用 也可以使用str(对象)
        print('自动执行后的随意代码区,可以随便编写')
        return '打印对象的时候就将这里的内容进行返回'

    def __repr__(self): #转化为解析器读取的形式, 调用时repr(对象)
        pass

    def __hash__(self):#设置本对象的hash 的功能,如果直接在对象的后面添加__hash__ = None 的话,该对象不能被进行哈希
        return '可以给自己定义的对象设置可以hash的功能'

    def __new__(cls, *args, **kwargs):#构造方法__new__ 开辟内存,触发 __init__创建实例
        return object.__new__(cls)

    def __cmp__(self,x): #对象比较  调用方法  cmp(对象,x)
        pass

    def __del__(self): #析构方法:当对象在内存中被释放时,自动触发执行  del  对象
        pass

a = gg('panzhenwei') #  触发__new__ __init__
print(gg.__module__) # 查看当前操作的模块是哪个
print(gg.__class__)  #查看当前操作的类是哪个
print(gg.__dict__)  # 查看类或对象的成员,类只是打印类的成员不打印对象的成员
print(a.__dict__) #  查看类或对象的成员,对象只对应对象的成员,不打印类的成员
print(a ) #触发__str__
a()  # 触发__call__

a['name'] = 'cisco'# 触发__setitem__
a['name']           # 触发__getitem__
del a['name']    #  触发__delitem

with a as f:  # 自动触发__enter__ 和__exit__
    print('打印这里的时候已经触发了__enter__')
print('代码执行到这里,说明已经退出了上面的句柄,已经触发完__exit__')


# 来自菜鸟编程的示例
class Vector:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __str__(self):
        return 'Vector (%d, %d)' % (self.a, self.b)

    def __add__(self, other):
        return Vector(self.a + other.a, self.b + other.b)

v1 = Vector(2, 10)# 触发__new__ __init__
v2 = Vector(5, -2)# 触发__new__ __init__
print(v1 + v2) # 触发__add__, 触发__new__ __init__   触发__str__

#结果 Vector(7,8)  #这个是字符串

 

 

init
构造方法,每个对象被实例化出来的时候都将首先去执行init方法

class A:
    def __init__(self):
        print("在创建对象的时候会首先自动执行__init__")

del
析构方法,每个对象在被垃圾回收机制回收之前执行的方法

class A:
    def __del__(self):
        print("在对象销毁之前会执行__del__")

doc
类的描述信息

class A:
    """我是A类的描述信息"""
    pass

module
表示当前操作的对象在哪个模块

class A:
    """我是A类的描述信息"""
    pass
from lib import A
a = A()
print(a.__module__)

class
表示当前操作的对象的类是什么

class A:
    pass

a = A()
print(a.__class__)

call
类名后面加括号表示创建一个对象;如果在对象后面加括号,就需要使用call方法了,如果不定义这个方法,在执行对象()的时候就会报错

class A:

    def __call__(self, *args, **kwargs):
        print("call")

a = A()
a()

------------
call

创建对象的时候首先执行init,在对象被调用的时候执行call

也可以在一行执行

a = A()()

str
print对象的时候显示的内容

class A:
    pass

a = A()
print(a)

------------
<__main__.A object at 0x101b77128>

在没有定义str的情况下,输出的是a对象的内存地址信息

class A:
    def __str__(self):
        return "A~"

a = A()
print(a)

------------
A~

str的应用实例

class B:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

b = B("ps")
print(b)

------------
ps

str类型转换

class B:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

b = B("ps")
ret = str(b)
print(ret)

str(b)和print()都会自动去调用b对象中的str方法

dict
对象的dict
在对象中默认已经有dict,不需要自定义。该方法用来获取对象中所有封装的对象

class B:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return self.name

b = B("ps", 26)
print(b.__dict__)

------------
{'age': 26, 'name': 'ps'}

类的dict
列出类中所有可以调用的方法

class B:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return self.name

b = B("ps", 26)
print(B.__dict__)

------------
{'__weakref__': <attribute '__weakref__' of 'B' objects>, '__module__': '__main__', '__str__': <function B.__str__ at 0x10137b730>, '__init__': <function B.__init__ at 0x10137b6a8>, '__doc__': None, '__dict__': <attribute '__dict__' of 'B' objects>}

add
当执行一个对象 + 一个对象的时候,就会自动去执行这个方法

注意,执行的是第一个对象的add方法

class A:
    def __init__(self, num):
        self.num = num

    def __add__(self, other):
        return self.num + other.num

class B:
    def __init__(self, num):
        self.num = num        
a = A(5)
b = B(9)
c = a + b
print(c)

getitem setitem delitem
用于索引操作,如字典。以上分别表示获取、设置、删除数据

d = {"k": "v"}
print(d["k"])
d["k"] = "vv"
del d["k"]

上面的代码展示了一个字典对象的取值、赋值和删除的操作。在自定义的类中,也可以实现类似于字典这样的操作
对象后面加小括号是执行call方法,那么对象后面加中括号又是怎样处理的呢?

使用key进行的操作
取值

class B:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return self.name

    def __getitem__(self, item):
        print("执行了getitem方法", item)

b = B("ps", 26)
b["name"]

------------
执行了getitem方法 name

赋值

class B:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return self.name

    def __getitem__(self, item):
        print("执行了getitem方法", item)

    def __setitem__(self, key, value):
        print("你要为%s重新赋值为%s" % (key, value))

b = B("ps", 26)
print(b.name)
b["name"] = "lr"

------------
ps

你要为name重新赋值为lr
删除

class B:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return self.name

    def __getitem__(self, item):
        print("执行了getitem方法", item)

    def __setitem__(self, key, value):
        print("你要为%s重新赋值为%s" % (key, value))

    def __delitem__(self, key):
        print("你要删除%s" % key)

b = B("ps", 26)
del b["age"]

------------
你要删除age

在web开发中,自定义session框架的时候会用到

使用下标进行的操作
使用下标和使用key的形式类似,使用key, item接收的是一个字符串,使用下标, item接收的是一个int类型的数字,可以在方法体内通过判断传递过来数据的数据类型来进行对应的操作

使用切片的操作

l = [1,2,3,4,5,6,7,8,9]
l[1:5:2]

在Python2.x中使用getslice setslice delslice来实现切片的操作,但是Python3.x中被遗弃,所有切片的功能都集中在了getitem setitem delitem

class B:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return self.name

    def __getitem__(self, item):
        # print("执行了getitem方法", item)
        print(type(item))

    def __setitem__(self, key, value):
        print("你要为%s重新赋值为%s" % (key, value))

    def __delitem__(self, key):
        print("你要删除%s" % key)

b = B("ps", 26)
b["name"]
b[1]
b[1:5:2]

------------
<class 'str'>
<class 'int'>
<class 'slice'>

item为slice时表示调用了切片的操作

class B:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return self.name

    def __getitem__(self, item):
        print("起点索引", item.start)
        print("终点索引", item.stop)
        print("步长", item.step)
        return "haha"

    def __setitem__(self, key, value):
        print("你要为%s重新赋值为%s" % (key, value))

    def __delitem__(self, key):
        print("你要删除%s" % key)

b = B("ps", 26)
ret = b[1:5:2]
print(ret)

------------
起点索引 1
终点索引 5
步长 2
haha

相对应的,取值可以通过判断item的类型做相应的操作,赋值和删除也可以通过判断key的类型来进行想对应的切片操作

class B:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return self.name

    def __getitem__(self, item):
        print("起点索引", item.start)
        print("终点索引", item.stop)
        print("步长", item.step)
        return "haha"

    def __setitem__(self, key, value):
        print("起点索引", key.start)
        print("终点索引", key.stop)
        print("步长", key.step)
        print("新值为", value)

    def __delitem__(self, key):
        print("起点索引", key.start)
        print("终点索引", key.stop)
        print("步长", key.step)

b = B("ps", 26)
print("切片取值")
ret = b[1:5:2]

print("切片赋值")
b[1:5:2] = "hehe"

print("切片删除")
print(ret)
del b[1:5:2]

------------
切片取值
起点索引 1
终点索引 5
步长 2
切片赋值
起点索引 1
终点索引 5
步长 2
新值为 hehe
切片删除
haha
起点索引 1
终点索引 5
步长 2

iter
一个自定义类实例化的对象,默认是不可迭代的,在类中使用iter方法后,对象就变成了可迭代对象。当对象被迭代时,会自动调用iter方法

class A:
    pass

a = A()
for i in a:
    print(i)
    
------------
Traceback (most recent call last):
  File "/Users/lvrui/PycharmProjects/untitled/8/c8.py", line 5, in <module>
    for i in a:
TypeError: 'A' object is not iterable
class A:
    def __iter__(self):
        return iter([1, 2])  # return了一个可迭代对象

a = A()
for i in a:
    print(i)
    
------------
1
2

class A:
    def __iter__(self):  # 返回了一个生成器
        yield 1
        yield 2

a = A()
for i in a:
    print(i)
    
------------
1
2

先去a对象中找到iter方法执行,并拿到返回值进行迭代

new metaclass

class A(object):
 
    def __init__(self):
        pass     

a = A()   # a是通过A类实例化的对象

上述代码中,a 是通过 A 类实例化的对象,其实,不仅 a 是一个对象,A类本身也是一个对象,因为在Python中一切事物都是对象。

如果按照一切事物都是对象的理论:a对象是通过执行A类的构造方法创建,那么A类对象应该也是通过执行某个类的构造方法创建。

print type(a) # 输出:<class '__main__.A'>     表示,a对象由A类创建
print type(A) # 输出:<type 'type'>              表示,A类对象由type类创建

所以,a对象是A类的一个实例,A类对象是type类的一个实例,即:A类对象是通过type类的构造方法创建

那么,创建类就可以有两种方式:

  • 普通方式
class A(object):
 
    def func(self):
        print("ps")
  • 特殊方式(type类的构造函数)
def func(self):
    print("ps")
 
A = type('A',(object,), {'func': func})
#type第一个参数:类名
#type第二个参数:当前类的基类
#type第三个参数:类的成员

–> 类是由type类实例化产生

那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?

答:类中有一个属性metaclass 其用来表示该类由谁来实例化创建,所以,我们可以为metaclass设置一个type类的派生类,从而查看类创建的过程:

 
类创建的过程

 

class MyType(type):

    def __init__(self, what, bases=None, dict=None):
        super(MyType, self).__init__(what, bases, dict)

    def __call__(self, *args, **kwargs):
        obj = self.__new__(self, *args, **kwargs)

        self.__init__(obj)

class A(object):

    __metaclass__ = MyType

    def __init__(self, name):
        self.name = name

    def __new__(cls, *args, **kwargs):
        return object.__new__(cls, *args, **kwargs)

# 第一阶段:解释器从上到下执行代码创建A类
# 第二阶段:通过A类创建a对象
a = A()





 

posted @ 2018-12-19 20:33  言吾  阅读(690)  评论(0编辑  收藏  举报