Python类中的特殊成员

Python类中的特殊成员

Python Version: 3.5+

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()

原文地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容