当先锋百科网

首页 1 2 3 4 5 6 7

类的基本知识

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