相信前端的小伙伴都熟悉ES6中的类,在ES6中类只不过是构造函数一个语法糖而已。而在Python中的类与其类似,类就是一个模板,里边定义了许多变量、方法,传入不同的数据,会产生不同的结果(像是一个生产工厂一样,通过生产加工,会产生不同的产品)。使用关键字class来定义一个类。下边我们还是以代码说下:
class Person ():
pass
p = Person('lxc')
上边代码,创建了一个类:我们用class定义了一个名子为Person的类,类名通常首字母大写,通过类名加括号的形式来创建一个类的实例,在ES6中,创建类要用 new + 类名 +括号。
补充:(这里要说明下类中的所有函数,统一称为方法)
因为下边多次提到一些名词,初学者肯定会很蒙,所以我这里先说下:
你需要知道在python的类中可定义:
1、构造函数:在类中有一个内置的构造函数__init__,在实例初始化时自动执行此方法;
2、实例方法:第一个参数永远都是self(类似js对象中的this),self指向调用实例方法的实例;在实例中的变量叫实例变量,
有两种方法定义实例变量:
(1)在构造函数 或者 实例方法中用 self . xxx 定义实例变量;
(2)在外部用实例去定义一个变量
class Person():
def __init__(self,name):
self.name = name # 定义实例变量name
p = Person('lxc')
p.age = 20 # 定义实例变量age
3、类方法:第一个参数永远都是cls,注意:cls也可以换成别的名,只是python中统一这么写。(cls与self类似,但是它指向类本身)且在类方法上边需要定义 一个装饰器 @classmethod 这时的方法才是类方法;(补充:在类方法中用到类变量的时候,才定义类方法)
class Person():
@classmethod # @ 表示装饰器的意思,在一个函数上边增加 @classmethod就可以让下边函数成为类方法
def class_fn(cls): # 类方法
pass
p = Person('lxc',20)
4、静态方法:静态方法参数没有指定实例或者类,但是在定义静态方法的同时,也要定义一个装饰器 @staticmethod,这时的方法才是静态方法;(补充:在静态方法中没用到实例方法、实例变量,也没用到类方法、类变量的时候,才定义静态方法)
class Person():
@staticmethod
def static_fn():
pass
p = Person()
5、类变量:在类中定义的变量就是类变量,与普通变量定义无差别
class Person():
name = '呆呆君' # 类变量
p = Person()
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1、类中可定义:变量、方法(注意这里所说的方法就是其实就是函数,只不过更加好理解,因为ES6类中定义的就是一个个方法);
2、self:在下边代码中,实例方法(函数)的参数中我们定义了一个self,它就相当于js对象中的this,如果你在类方法或实例方法中调用实例变量需要用到self。使用self或实例对象---->调用实例方法时,传递参数,无需关心self,实参只需要填写传递的参数,self后边填写与实参相对应的变量即可。
同样self也可以赋值给另外一个变量,使用另外的变量去调用实例变量;调用问题:其实self指向创建的实例本身,谁调用的类中的方法,self就是谁:
class Person ():
def __init__(self,name):
self.name = name
def fn (self):
# 这里的self指向实例 P
s = self
print(s.name) # 'lxc'
def fn1 (self):
# 这里的self指向实例 P1
s = self
p = Person('lxc')
p1 = Person('xxl')
p.fn()
p1.fn1()
上边代码,出现了__init__方法,下边我们会聊到,别慌!
3、在类中创建的实例方法与普通函数的差别在于:类中的实例方法第一个参数永远是self,其它无差别,实例方法的参数也可以使用可变参数、关键字参数等等。
4、所谓的实例,就是由类创建的对象(object)而已(上边代码实例是p和p1);
5、在外界调用类中实例方法:直接用实例(self)调用即可;
class Person ():
name = 'lxc'
age = 20
def fn (self):
print(self) # <__main__.Person object at 0x0000000001E04390>
print(self.name) # 20
p = Person()
print(p.name) # 'lxc'
p.fn()
上边代码,在调用类中实例方法时,我们先输出self看看它到底是啥,其实self就是Person这个类创建出来的实例,后边那一长串是实例在内存中的地址,每个实例在内存中的地址都不一样,下边有例子。
6、同一个类构造出来的不同实例,是不相等的,因为他们的内存地址不同:
class Person(object):
def __init__(self):
pass
def fn (self):
pass
p1 = Person()
p2 = Person()
p3 = Person()
# id 函数可以输出实例在内存中的地址,证明三个实例不相等
print(id(person1)) # 31148912
print(id(person2)) # 31175848
print(id(person3)) # 3117478
7、实例方法中调用类变量:
在这说这个问题,有点早,不妨先了解下:
方法一:
class Person():
name = '呆呆君'
age = 100
def __init__(self,name,age):
self.name = name
self.age = age
def fn(self):
print(Person.name) # '呆呆君'
p = Person('lxc',20)
p.fn()
上边代码,使用类名Person可以在实例方法中调用类变量,原因是类中包含类变量,下边有详细说道!同理,如果我们在__init__构造函数里边不带self去访问一个在类和方法中都有的变量,会打印什么呢:
class Person():
name = '呆呆君'
def __init__(self,name):
self.name = name
print(name) # 'lxc'
def fn(self):
pass
p = Person('lxc')
上边代码,打印的是‘lxc’,真是这样的吗?我们把形参改下:
class Person():
name = '呆呆君'
def __init__(self,name1):
self.name = name1
print(name) # name 'name' is not defined
def fn(self):
pass
p = Person('lxc')
上边代码,我们把形参改为name1,在输出name的时候结果报错了;不带self打印的变量是形参中的变量,这点要知道,不过平时最好还是带上self来输出实例变量为宜。
方法二:(通过self.__class__去访问类变量,self.___class__指向类本身!!!)
class Person():
name = 'lxc'
def fn(self):
print(self.__class__.name) # 'lxc'
p = Person()
p.fn()
8、在外界如何调用类变量,其实与在实例方法中调用类变量一样,也是用类名去调用类变量:
class Person():
name = '呆呆君'
def __init__(self):
pass
def fn(self):
pass
p = Person()
print(Person.name) # '呆呆君'
类中定义的__init__方法,是一个内置方法,在python中叫构造函数,此函数有几个特点:
1、类在实例化的时候,__init__构造函数会自动执行;
2、此构造函数默认返回None,如果显示的return数据类型,会报错!!!
class Person():
def __init__(self):
return 123
p = Person() #TypeError: __init__() should return None, not 'int'
3、一般在__init__方法(函数)中,初始化一些实例变量;
class Person():
name = '呆呆君'
def __init__ (self,name,age):
self.name = name
self.age = age
def fn(self):
pass
p = Person('lxc',20)
print(p.name) # 'lxc'
上边代码,用实例p调用name变量,为什么输出的是 'lxc' 呢(输出的是实例变量),而不是 '呆呆君' ,(类变量) 在类中定义的变量在python中叫做类变量,在实例中定义的变量叫实例变量,变量p就是类构造出来的实例,所以说用实例去调用内部的变量必然是实例变量 'lxc'。
4、如果我们在外界和实例方法调用一个实例中没有的变量,但是类中定义了此变量,它会输出什么呢???
class Person():
name = '呆呆君'
def __init__ (self):
pass
def fn(self):
print(self.name) # 呆呆君
p = Person()
print(p.name) # 呆呆君
p.fn()
结果打印的都是 ' 呆呆君 ' ,结果是不是很震惊!!!即使是实例中没有此变量,应该返回None才对啊!!!这里是Python的一个内部机制,输出一个变量的时候,python内部它会先去实例对象中去找此变量,如果没有,它会尝试去类中寻找此变量,类中有此变量,所以输出了;如果类中还是没有,它会去父类中寻找此变量,这里涉及到继承问题,我们下一篇文章详细来聊下!!!
说了这么多,来放松下脑子,下边我们来看下类和实例中分别都存了哪一些值:
class Person():
name = '呆呆君'
def __init__ (self,name,age):
self.name = name
self.age = age
def fn(self):
pass
p = Person('lxc',20)
# 实例中的变量
print(p.__dict__) # {'name': 'lxc', 'age': 20}
# 类中的变量和方法
print(Person.__dict__)
# { '__module__': '__main__',
# 'sum': 0,
# 'name': '呆呆君',
# '__init__': ,
# 'fn': ,
# '__dict__': ,
# '__weakref__': ,
# '__doc__': None
# }
上边代码,调用__dict__方法可以输出一个对象内部所有的成员组成的字典。。。可以看出他们都是以字典dict形式存放的,很显然,类中存放的是类变量、构造函数 __init__、实例方法(特点参数有一个self)、静态方法、内置方法等等,而实例中存放的是实例变量;了解了这些,你会更加清晰明白在外界 或 方法中 类变量和实例变量 是如何调用!
上边有提到过类方法,但是大部分是在说变量和实例方法,下边我们着重来看下类方法的定义及调用:
定义类方法:(1)要定义一个装饰器 classmethod ; (2)第一个参数永远都是cls,与self类似,但是它指向的是类本身,满足这两点,才能称为类方法,类方法关注的类本身。
class Person():
# ··· ···
@classmethod # @ 表示装饰器的意思,在一个函数上边增加 @classmethod就可以让下边函数成为类方法
def class_fn(cls): # 类方法
print(cls) #
p = Person()
p.class_fn()
外部调用类方法:(用实例对象也可以调用类方法,但是不推荐!!!)
class Person():
@classmethod
def class_fn(cls): # 类方法
print("类方法")
p = Person()
Person.class_fn() # "类方法"
实例方法中调用类方法:
class Person():
def fn (self): # 实例方法
Person.class_fn()
@classmethod
def class_fn(cls):
print("类方法") # 类方法
p = Person()
p.fn()
类方法中调用类变量(两个方法):
class Person():
name = 'lxc'
@classmethod
def class_fn(cls):
# 方法一
print(cls.name) #'lxc'
# 方法二
print(Person.name) #'lxc'
p = Person()
Person.class_fn()
静态方法定义及调用:
静态方法不像实例方法或类方法一样要指定第一个参数为xxx,静态方法里边没有指代参数,但是需在方法上边加上装饰器:
@staticmethod。
外界调用静态方法(两种方法,实例对象调用,类调用)
class Person():
@staticmethod
def fn():
print('静态方法')
p = Person()
p.fn() # '静态方法'
Person.fn() # '静态方法'
静态方法里边访问类变量
class Person():
name = 'lxc'
@staticmethod
def fn():
print(Person.name) # 'lxc'
p = Person()
p.fn()
————————————通过实例对象访问实例变量,(使用self访问实例变量会报错,大家自己试下,这里就不举例了!)
class Person():
def __init__(self,name,age):
self.name = name
self.age = age
@classmethod
def class_fn(cls):
print(p.name) # '呆呆君'
@staticmethod
def static_fn():
print(p.age) # 100
p = Person('呆呆君',100)
Person.class_fn()
Person.static_fn()
最后我们在类中、__init__方法(构造函数)中、普通方法中分别输出一个值,我们看下执行顺序:
class Person():
name = '呆呆君'
print("1")
def fn(self):
print('fn')
print('2')
def __init__ (self,name,age):
self.name = name
self.age = age
print('__init__')
print('3')
def fn1 (self):
print('fn1')
p = Person('lxc',20)
p.fn()
p.fn1()
# 执行顺序如下:
# 1
# 2
# 3
# __init__
# fn
# fn1
上边代码,类中的print从上至下先执行 ---------> 然后在执行__init__方法中的print --------> 最后执行调用方法里的print,执行顺序大家要明白!!!
1、类调用实例方法时,参数必须要传该类的实例对象,否则将报错,且实例self不会被绑定:
class Person():
def __init__(self,name):
self.name = name
def fn(self):
print(self.name) # 'lxc'
p = Person('lxc')
Person.fn(p)
上边代码,Person调用实例方法,参数需要手动的传类的实例对象p,self才能绑定到实例对象上边。
1、在动态添加类实例方法时,self不会自动绑定实例对象,(也就是说self不会自动指向调用它的实例),需要手动的添加:
def fn1(self):
print(self.name) # 'lxc'
class Person():
def __init__(self,name):
self.name = name
p = Person('lxc')
p.foo = fn1
p.foo(p)
上边代码,为Person类动态添加实例方法 fn1 ,执行fn1方法,self不会自动绑定实例对象,参数需要传一个实例对象。
def son(self):
print(self.name) # 'lxc'
class Cat:
def __init__(self,name):
self.name = name
c = Cat('lxc')
Cat.son_fun = son
c.son_fun()
总结:我们用一张脑图总结下,以上主要介绍了类的定义及创建一个类、类中变量和方法及构造函数的定义及调用,在实际开发中经常会在一个方法中去操作变量,或者调用方法。还是那句话,多写、多练,自然而然你会明白。就这么多,有不足之处,望指正,有不懂地方欢迎留言!