类的学习、__init__学习和super方法学习
1.python中类的属性、方法学习
- 类的私有属性:以两个下划线开头的,如 __private_attrs,声明该属性为私有,不能被类的外部使用或直接访问。在类的内部方法使用时用:self.__private__attrs
- 类的方法:与一般函数定义不同,类的方法定义的第一个参数必须为self;
- 类的专有方法:
方法名 | 作用 |
---|---|
init | 构造函数,在生成对象时调用,即初始化该方法的属性 |
del | 析构函数,释放对象的时候使用 |
… | … |
class person(object):
tall=180
hobbies=[]
def __init__(self,name,age,weight):
self.name=name
self.age=age
self.weight=weight
def information(self):
print("%s age is %d ,and weigth is %s"%(self.name,self.age,self.weight))
person.hobbies.extend(["football","woman"]) #类数据属性属于类本身,可以通过类名进行修改和访问,此次添加两个值
print("person hobbies list is:%s"%person.hobbies)
person.hobbies2=["reading","swimming","running"] #类在定义后,依然可以添加类的属性,新增的类属性也可以被类和所以实例共有
print("person hobbies2 list is:%s"%person.hobbies2)
print(dir(person)) #通过内建函数dir()或访问类的字典属性__dict__这两种方式来查看类有那些属性
jhon=person("jhon",24,66) #实例数据属性只能通过实例化访问
jhon.gender="man" #类实例化后可以动态添加属性,但是只能被实例化的jhon使用
print("%s gender is %s"%(jhon.name,jhon.gender))
print(dir(jhon))
jhon.hobbies.append("python") #修改实例化列表属性,在原基础上添加
infoma=jhon.information()
print(infoma)
print(jhon.hobbies)
jhon2=person("jhon2",25,68) #jhon2将没有属性gender
print(jhon2.__dir__())
- 特殊的类属性:对于所有的类
属性名 | 含义 |
---|---|
name | 类的名字 |
doc | 类的文档字符串 |
bases | 类的所有父类组成的元组 |
dict | 类的属性组成的字典 |
module | 类所属的模块 |
class | 类对象的类型 |
- 类的隐藏属性(不可变类型的类属性)
- 对于不可变类型的类属性person.tall,可以通过实例jhon进行访问;person.tall的值就是jhon.tall的值 。
- 当通过实例赋值或修改属性时,将为实例jhon新建一个tall实例属性,person.tall 不等于 jhon.tall 。
- 当通过del jhon.tall语句删除实例tall的属性后,再次成为:person.tall为jhon.tall
对于可变类型的类属性(列表等),隐藏属性总结为:
- 同样对于可变类型的类属性person.hobbies,可以通过实例Bruce进行访问,并且"person.hobbies is Bruce. hobbies"
- 当通过实例赋值hobbies 属性的时候,都将为实例Bruce新建一个hobbies实例属性,这时,“person.hobbies is not Bruce. hobbies”
- 当通过"del Bruce. hobbies"语句删除实例的hobbies属性后,再次成为"person. hobbies is Bruce.hobbies"
- 当通过实例修改hobbies属性的时候,将修改Bruce. hobbies指向的内存地址(即person.hobbies),此“person.hobbies is not Bruce. hobbies”
虽然可以通过实例化来访问类的属性,但是不建议这样做,最好通过类名访问类的属性,从而避免属性隐藏带来的不必要的麻烦
2. 类的实例方法、类方法、静态方法
- 实例方法
实例方法的第一个参数必须为self,实例方法只能通过类实例化进行调用,这时的self代表这个类本身。通过self可以直接访问实例的属性:
class person(object):
tall=180
hobbies=[]
def __init__(self,name,age,weight): #__init__类的私有方法,构造方法,实例类的时候调用
self.name=name
self.age=age
self.weight=weight
def infoma(self): #实例方法,只能通过实例进行调用
print('%s is age %s weights %s'%(self.name,self.age,self.weight))
jhon=person("jhon",24,175)
jhon.infoma()
输出:
jhon is age 24 weights 175
- 类方法
- 类方法以cls作为第一个参数,cls表示类本身,定义时使用@classmethod装饰器。通过cls可以访问类的相关属性
class person(object):
tall = 180
hobbies = []
def __init__(self, name, age,weight):
self.name = name
self.age = age
self.weight = weight
@classmethod #类的装饰器
def infoma(cls): #cls表示类本身,使用类参数cls
print(cls.__name__)
print(dir(cls))
#cls表示类本身
person.infoma() #直接调用类的装饰器函数,通过cls可以访问类的相关属性
jhon=person("jhon",24,170) #也可以通过两个步骤来实现,第一步实例化person
jhon.infoma() #调用装饰器
- 类的静态方法
- 类的静态方法没有参数限制,即不需要实例参数,也不需要类参数,定义的时候使用@staticmethod装饰器
同类方法一样,静态方法可以通过类名访问,也可以通过实例访问;
class person(object):
tall = 180
hobbies = []
def __init__(self, name, age,weight):
self.name = name
self.age = age
self.weight = weight
@staticmethod #静态方法装饰器
def infoma(): #没有参数限制,既不要实例参数,也不用类参数
print(person.tall)
print(person.hobbies)
#person.infoma() #静态法可以通过类名访问
Bruce = person("Bruce", 25,180) #通过实例访问
Bruce.infoma()
3.类class的访问控制:单划线_与双划线__
- 在python中,通过单下划线来实现模块级别的私有化,除变量外。一般约定以单划线开头的函数为模块私有的,也就是说:from modulename import *将不会导入以单划线开头的函数
_tall=180 #导入该包时会导入
def _call_for(): #导入该包时不会导入
print('_tall',——tall)
- 对于python中的类属性,可以通过双下划线__来实现一定程度的私有化。由于双下划线开头的属性在运行时会被"混淆"
class person(object):
tall = 180
hobbies = []
def __init__(self, name, age,weight):
self.name = name
self.age = age
self.weight = weight
self.__Id = 430 #实现__id一定程度的私有化
@staticmethod
def infoma():
print(person.tall)
print(person.hobbies)
#person.infoma()
jhon = person("jhon", 25,180)
#print(Bruce.__Id)#出错
#jhon.infoma()
#通过内建函数dir()发现__Id属性在运行时,属性名被改成_person__Id
print(dir(jhon))
print(jhon._person__Id)
- 双划线的另一个用途:避免子类对父类同名属性的冲突
class A(object):
def __init__(self):
self.__private()#将执行时会变成self._A__private()
self.public()
def __private(self): #只能被本身类访问,连子类也不行
print('A.__private()')
def public(self):
print('A.public()')
class B(A):
def __private(self): #
print('B.__private()')
def public(self):
print('B.public()')
b=B() #当B实例化后,由于没有定义__init__函数,将会调用父类的__init__,但是由于双下划线的'混淆'效果,"self.__private()"将变成self._A__private()
输出:
A.__private()
B.public()
class A(object):
def __init__(self):
self.private()
self.public()
def private(self):
print('A.private()')
def public(self):
print('A.public()')
class B(A):
def private(self): #
print('B.private()')
def public(self):
print('B.public()')
b=B()
输出:
B.private()
B.public()
4.继承中的__init__
在Python中出现继承时需要注意点是:初始化函数__init__的行为:
- 如果子类没有定义自己的初始化函数,父类的初始化会被默认调用,但是如果要实例化子类的对象,则只能传入父类的初始化函数对应的参数,要不然会出错。
#首先定义父类parent
class Parent(object):
def __init__(self,name):
self.name=name
print("create an instance of:",self.__class__.name__) #self.__class__.__name__用于显示执行该语句的类名
print("name attribute is:",self.name)
#define subChild class ,继承父类:
class Child(Parent):
pass
#子类实例化是,由于子类没有初始化,此时父类的初始化函数会被默认调用,且必须传入父类的参数那么
c=Child("init Child")
输出:
create an instance of: Child
name attribute is: init Child
- 子类定义了自己的初始化函数,而在子类中没有显示调用父类的初始化函数,则父类的属性不会被初始化
class Parent(object):
def __init__(self,name):
self.name=name
print("create an instance of: ",self.__class__.__name__)
print("name attribute is:",self.name)
#子类继承父类
class Child(Parent):
#子类中没有显示调用父类的初始化函数
def __init__(self):
print("call__init__ form Child class")
#实例化子类
c=Child()
print(c.name) #将会出错,原因父类没有被初始化
- 如果子类定义了自己的初始化函数,显示调用父类,子类和父类的属性都会被初始化
class Parent(object):
def __init__(self, name):
self.name = name
print("create an instance of:", self.__class__.__name__)
print("name attribute is:", self.name)
class Child(Parent):
def __init__(self):
print("call__init__form Child class")
super(Child,self).__init__("data from Child") #要将子类child和self传递进去
d=Parent('jhon')
c=Child()
print(c.name)
输出结果:
create an instance of: Parent
name attribute is: jhon
call__init__form Child class
create an instance of: Child
name attribute is: data from Child
data from Child
5.super的详细使用
- super主要是用来调用父类方法来显示调用父类的,在子类中一般会定义与父类相同的属性、方法、等,从而实现子类特有的行为。也就是所,子类会继承父类的所以属性和方法,子类也可以覆盖父类同名的属性和方法:
class Parent(object):
Value="from parent value"
def fun(self):
print("function is from Parent")
#定义子类,继承父类
class Child(Parent):
Value ="from child value"
def fun(self):
print("funtion is from child")
Parent.fun(self) #调用父类的fun函数方法,将self显示的传递进入
c=Child()
c.fun()
print(Child.Value)
上面继承父类的缺点:需要经过父类名硬编码到子类中,然而super方法可以解决这一问题:
class Parent(object):
Value="from parent value"
def fun(self):
print("function is from Parent")
#定义子类,继承父类
class Child(Parent):
Value ="from child value"
def fun(self):
print("funtion is from child")
#Parent.fun(self) #调用父类的fun函数方法,将self显示的传递进入
super(Child,self).fun() #和上一句相同用于调用父类方法
c=Child()
c.fun()
print(Child.Value)
输出:
funtion is from child
function is from Parent
from child value