类的基本知识
self参数
类中的self参数在调用时会自动传进去,所传的值就是当前的对象:
# 定义一个类
class Bar(object):
def foo(self, num):
print(self, num)
b1 = Bar()
b2 = Bar()
print(b1)
b1.foo(11111)
print(b2)
b2.foo(22222)
#<__main__.Bar object at 0x0000018070B287F0>
#<__main__.Bar object at 0x0000018070B287F0> 11111
#<__main__.Bar object at 0x0000018070B28C50>
#<__main__.Bar object at 0x0000018070B28C50> 22222
构造方法
Python中类的构造方法为__init__(self)
,在实例化时执行:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print('name:', self.name, '\nage:', self.age)
meng = Person('Meng', 20)
meng.show()
# name: Meng
# age: 20
继承
在子类继承父类之后,调用子类的方法优先去子类中找,找不到才回去父类中找,所以可以在子类对父类的方法进行重写,如果要调用父类的同名方法,有两种办法:
class Father(object):
def f1(self):
print('Father.f1')
def f2(self):
print('Father.f2')
class Son(Father):
def s1(self):
print('Son.s1')
def f2(self):
print('Son.f2')
super(Son, self).f2() # 执行父类中的f2方法
Father.f2(self) # 执行父类中的f2方法
obj = Son()
obj.f2()
# Son.f2
# Father.f2
# Father.f2
字段
字段分为普通字段和静态字段,普通字段保存在对象中,静态字段保存在类中,所以静态字段是没有self的。普通字段只能通过对象访问,而静态字段既可以通过对象访问,又可以通过类访问。
class Province:
country = '中国' # 静态字段,属于类
def __init__(self, name):
self.name = name # 普通字段,属于对象
henan = Province('河南')
hebei = Province('河北')
print(Province.country) # 中国
print(hebei.name) # 河北
在上面的例子中,country为静态字段,在内存中只保存了一份。
静态方法、类方法
Python中的静态方法和类方法需要在方法定义前加上相应的装饰器,类方法和静态方法的功能是类似的,但是必须有一个特殊参数cls
。cls是class的缩写,调用时自动传进方法,self代表当前对象,而cls代表当前类。
class Foo:
def bar(self):
# self是对象
print('bar')
@staticmethod
def sta():
print('123')
@classmethod
def classmd(cls):
# cls 是类名
print('classmd')
Foo.sta() # 123
Foo.classmd() # classmd
类的属性
类的属性是在方法的定义前加上@property
的装饰器,不会改变方法的功能,但是在调用时不用加括号,使代码看起来更加清晰简洁:
class Foo:
# 用于执行 obj.per
@property
def per(self):
return 123
@per.setter
def per(self, val):
print(val)
@per.deleter
def per(self):
print(666)
obj = Foo()
print(obj.per) # 123
obj.per = 555 # 555
del obj.per # 666
通过per.setter
和per.deleter
给per增加了两个新的功能,需要注意的是,这两个新的功能和设置删除并没有直接关系,只是我们在用del obj.per
时,会调用相应的@per.deleter
下的方法,所以仅仅是一种一一对应的关系。
类的特殊成员
Python中的私有变量在字段前加两个下划线表示。
__call__()
方法用来表示对象后加括号自动调用的内容,类后加括号自动调用__init__()
方法,而对象后加括号自动调用__call__()
方法:
class Foo:
def __init__(self):
print('init')
def __call__(self, *args, **kwargs):
print('call')
obj = Foo() # 'init'
obj() # 'call'
# Foo()() 先调用init方法,再调用call方法
对象在强制转换时会调用相应的方法,在强制转换为int时调用__int__()
方法,在强制转换为str时调用__str__()
方法:
class Foo:
def __init__(self):
pass
def __int__(self):
return 1111
def __str__(self):
return 'MengHX'
obj = Foo()
print(int(obj)) # 1111
print(obj) # MengHX str类型在print的时候可以不用str()强制转换,会自动调用__str__()
两个对象相加时,会自动调用第一个对象的__add__()
方法,并且把第二个对象当成参数传入__add__()
中:
class Foo:
def __init__(self, name,age):
self.__name = name
self.__age = age
def __add__(self, other):
return self.__age + other.__age
obj1 = Foo('alex', 19)
obj2 = Foo('eirc', 20)
print(obj1 + obj2) # 39
Python中的析构方法用__del__()
来定义,对象被销毁的时候自动执行。
obj.__dict__
返回一个列表,里面包含了对象中的字段:
class Foo:
def __init__(self, name,age):
self.name = name
self.age = age
self.n = 123
self.__sex = 'male'
def show(self):
print(self.name, self.age)
obj = Foo('alex', 18)
d = obj.__dict__
print(d) # {'name': 'alex', 'age': 18, 'n': 123, '_Foo__sex': 'male'}
__getitem__, __setitem__, __delitem__
三个重要的方法,在对象后加方括号被当做序列时调用,需要注意,执行的方法仅仅是对应关系,和序列没有任何的逻辑联系:
class Foo:
def __init__(self, name,age):
self.name = name
self.age = age
def __getitem__(self, item):
return item+10
def __setitem__(self, key, value):
print(key,value)
def __delitem__(self, key):
print(key)
li = Foo('alex', 18)
r= li[8] # 自动执行li对象的类中的 __getitem__方法,8当作参数传递给item
print(r)
li[100] = "asdf" # 自动执行__setitem__
del li[999] # 自动执行__delitem__
在Python3中,切片取值和索引取值调用的方法都是__getitem__
,如果需要通过切片取值,可以在写__getitem__
方法的时候增加一个对传进来参数的判断,如果是基本类型那就是索引取值,如果传进来的是slice
对象,那么就是切片取值。
把对象变成可迭代对象,需要改写对象的__iter__
方法。for i in list:
的过程中,其实是执行了两步:1.执行list对象的__iter__
方法,并获取其返回值 2.循环上一步中返回的对象。for循环中,先执行类中__iter__
方法得到迭代器,再循环执行执行迭代器的next
方法。
metaclass 对象
在Python中一切事物皆是对象,比如我们写了一个类class Foo:
,又创建了一个对象obj = Foo()
,那么obj是对象,Foo类;Foo也是对象,type类。以下两种方法定义类是完全相同的:
# class Foo:
#
# def func(self):
# print(123)
def func(self):
print(123)
Foo = type('Foo', (object,), {'func': func})
Foo().func() # 123
当我们写了一个自定义类,默认用type创建,所以一般的类其实都是type的对象,那么在初始化类时,比如obj = Foo()
,对象后加括号,要执行Foo对象的__call__
方法。接下来可以通过自己写的metaclass 来看看解释器是如何初始化一个对象的:
class MyType(type):
def __init__(self,*args, **kwargs):
# self=Foo
print(123)
pass
def __call__(self, *args, **kwargs):
# self=Foo
r = self.__new__()
class Foo(object,metaclass=MyType):
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
return '对象'
def func(self):
print('hello wupeiqi')
obj = Foo()