学习记录~~~部分(学习ing~)
一、类的定义与创建:
定义:类(抽象的概念): 拥有着相同的特征(属性)和行为(方法)。
- 简单创建:
简单创建:
-
类名的命名规则:大驼峰写法(每个单词的首字母大写)
-
class关键字创建
类的简单创建,
class DogCat(object): # 类名的命名规则:大驼峰写法(每个单词的首字母大写)
pass
- 类属性:
类属性:
- 类属性的赋予
class Student(object):
# 类属性
class_name = "8班"
student_num = 30
这里创建了一个学生类后,又赋予了班级名和学生人数这个两个属性。而他们就是类属性。
- 类属性的访问
class Student(object):
# 类属性
class_name = "8班"
student_num = 30
# 方法一 # 直接通过: 类名.类属性
print(Student.student_num)
# 方法二 # 先实例化对象,通过:实例对象.属性 来查找
s = Student()
print(s.student_num)
在上面代码中的方式二:它先实例化对象,通过:实例对象.属性 来查找,但是实例化对象的空间里没有student_num 这个属性,它就会继续在类空间里去找(或者去它继承的类里找)。
- 类属性的修改
class Student(object):
# 类属性
class_name = "8班"
student_num = 30
name = "土狗"
# 类属性的修改 : 类名.属性名 ,如果没该属性就新建属性;如有,就修改它
Student.name = "憨猫" # 修改
Student.age = 100 # 新建
print(Student.name)
print(Student.age)
直观结果:
二、实例对象
定义的类只有进行实例化,也就是使用该类创建对象之后,才可以利用。
- 实例对象方法: 类名()
class Student(object):
# 类属性
class_name = "8班"
student_num = 30
s = Student() # 实例化对象
- 实例对象方法: _ _ init _ _ 方法
当我们需要多个实例对象的时候,第一种方法就会造成代码的冗余,因此就有了__init__方法的作用了。
来个例子看看:
class Student(object):
# 类属性
name = "华子"
# 方法
def __init__(self, name, age): # 形参,接收实参的传入
self.name = name # 对于这里的参数,前面的name是我们可以再自定义的,而后面的name是不可以变的,因为它要与我们的新参保持一致,就相当于函数里的传参
self.age = age
def eat(self):
print('华子在吃饭')
s1 = Student('土狗', '18') # 实参 ,参数的多少都可以自定义
s2 = Student('憨猫', '19')
s3 = Student('猪猪侠', '20')
print(s1.name)
print(s2.name)
print(s3.name)
print(s1.age)
看看运行结果:
这里注意的是,Student()实例化后才会赋值给 s1 等变量,而Student()实例化的时候它会自动的触发__init__方法,而我们又可以认为self就是s1,因为下图:
这里打印出了self和s1的id值,发现他们是相同的~~~所以,self就是s1,而self.属性名就是s1.属性名,self.属性名就是在向 s1 这个实例空间里创建实例属性。再就是这里的实参与形参的传入与接收,它是和函数的实参与形参相似的。
- 实例对象的属性赋予:实例对象.属性名
class Student(object):
# 类属性
class_name = "8班"
student_num = 30
name = "土狗"
s = Student()
s.name = '华仔'
s.age = 18
print(s.name) # 查找name属性时,发现类空间和实例空间都有name属性,
# 但实例对象会优先在自己空间去查找
运行结果:
所以会有:
- 实例对象.属性名 的查找先后顺序是:它先在自己的实例空间去找,如无;再到类空间去找,如无;再到该类所继承的类中去找;如都无,那就报错~~~~~~~
- 对象通过句点符调用属性和方法 : 对象.属性/方法
代码:
class Student(object):
# 类属性
name = "华子"
def eat(self):
print('华子在吃饭')
def sleep(self):
print('华子要睡觉')
s = Student()
print(s.name) # 对象调用属性
s.eat() # 调用方法
运行结果:
三、方法
- 实例方法
有self的方法就是实例方法,但是self这个名字并不是不变的,它可以是其他值,但规范习惯用self了,
self表示当前对象
- self并不是一个关键字,其实可以是任意的标识符,为了表达代表的是当前对象自己,习惯用self
- 调用实例函数的时候,self不需要手动传参,系统会自动传递当前的对象.
- 哪个对象调用了方法,方法里的self指的就是谁。
实例方法调用:
代码:
class Student(object):
# 类属性
class_num = 30
class_name = '8班'
# 方法
def __init__(self, name, course):
self.name = name
self.course = course
def listen(self):
print('%s在听%s课' % (self.name, self.course)) # self 中有name,course
def homework(self):
print('%s在写%s课作业' % (self.name, self.course))
s1 = Student('华仔', 'python') # 实参传入
s1.listen()
s2 = Student('我', 'python')
s2.homework()
在上面的代码中:s1.listen() ,这个调用方法,解释器会将 s1 这个对象作为实参传给该方法的第一个形参(self).
- 静态方法
代码:
class Sum(object):
@staticmethod
def add(x, y): # 这里是没有self这个参数的
return x + y
# 实例对象调用静态方法:
s = Sum()
print(s.add(2, 6))
# 类对象调用静态方法:
print(Sum.add(6, 6))
运行结果:
- 类方法
代码:
class Sum(object):
# 类属性
num = 30
@classmethod
def add_num(cls): # 这里加了 @classmethod 后,解释器会自动加上 cls 这个参数。
print(id(Sum), id(cls))
cls.num += 1
Sum.add_num()
print(Sum.num)
结果:
在上面发现:参数cls与Sum类的地址相同。所以cls就是当前的类对象。Sum这个类对象作为cls的接收者。
四、类的继承
- 继承:
继承:是子类复用父类的属性和方法的机制。在Python中,新建的类可以继承一个或多个父类。注意:object 是 Python 中所有类的根类。
单继承:子类之继承一个父类,被称为单继承。
多继承:子类可以拥有多个父类,并且具有所有父类的属性和方法。
- 父类: 又可称为基类或超类
- 新建的类: 称为派生类或子类
代码:
简单例子:
class Animal(object):
def eat(self):
print('吃')
def sleep(self):
print('睡')
class Dog(Animal): # 继承 Animal 父类
def bark(self):
print('狂吠')
class Cat(Animal):
def climetree(self):
print('爬树')
s1 = Dog()
s2 = Cat()
s1.eat()
s2.sleep()
结果:
子类没有的属性可以到他继承的父类里去找。
- 继承中的方法覆盖
代码:
class Animal(object):
def eat(self):
print('吃')
def sleep(self):
print('睡')
class Dog(Animal): # 继承 Animal 父类
def bark(self):
print('狂吠')
def sleep(self):
print('睡睡睡睡。。。。。') # 虽然继承了父类的sleep,但子类写了个sleep方法,就覆盖了,但对父类不影响
class Cat(Animal):
def climetree(self):
print('爬树')
s1 = Dog()
s1.sleep()
s2 = Cat()
s2.sleep()
运行结果:
- 引用父类方法
- 例子1 :
class Animal(object):
def __init__(self):
self.parent = '我是父类'
print(id(self))
print('父类')
def sleep(self):
print('我是父类的睡')
class Dog(Animal): # 继承 Animal 父类
def sleep(self):
super(Dog, self).sleep() # super 会首先找到 Dog 的父类(就是类 Animal),然后把类Dog的对象(s)转换为类Animal的对象(self),因为他们的id值相同
print('我是子类的睡睡睡睡。。。。。')
print(self.parent) # 找到父类的parent属性
d = Dog() # 别忘了,它会找__init__方法
d.sleep()
print(id(d))
运行结果:
注意:super 会首先找到 Dog 的父类(就是类 Animal),然后把类Dog的对象(s)转换为类Animal的对象(self),因为他们的id值相同
- 例子2 :
class Parent(object):
def __init__(self):
self.parent = '我是父类'
print(id(self))
print('父类')
def bar(self):
print("我是父类的bar")
class Child(Parent):
def __init__(self):
# super(Child,self) 首先找到 Child 的父类(就是类 Parent),然后把类Child的对象(s)转换为类Parent的对象(self),他们的id值相同。
super().__init__() # super(Child, self).__init__()
print('子类')
def bar(self):
super().bar() # super().bar(message)
print('我是子类的bar')
print(self.parent) # Child的对象(s)已经转换为类Parent的对象(self)
s = Child() # 实例化 Child 对象
s.bar() # 调用s的bar方法
print(id(s))
运行结果:
super().init() # 也可以写成: super(Child, self).init() 。
- 类的多重继承
代码:
class Animal(object):
def eat(self):
print('吃')
class Fly(object):
def fly(self):
print('飞')
class Dog(object):
pass
class BigBird(Animal, Dog, Fly):
pass
class LittleBird(Fly, Animal):
pass
b = BigBird()
b.fly()
c = LittleBird()
c.fly()
运行结果:
对于多个类的继承时,子类继承是有顺序的:从左向右继承
再就是:
- type()方法 : 除了判断字符串等类型,它还可以判断 实例对象是属于那个类。
print(type(b))
print(type(c))
结果
- isinstance()方法 : 判断某个对象是不是某个类的实例,是就True,否就False,但如果是true,那他继承的父类也是true.
代码:
print(isinstance(b, BigBird))
print(isinstance(b, Fly))
print(isinstance(b, LittleBird))
运行结果:
- dir(object)和object.dict
- dir(object) 和 object.dir() 是等价的。dir()方法可获取对象的所有属性和方法,并以列表形式返回。
print(dir(b))
print(c.__dir__())
结果
他们返回的顺序不同,但内容是一样的。~~~~
- object__dict__ 它可以获取对象自定义的属性,且以字典形式返回。
代码:
print(c.__dict__)
运行结果:
注意的是:在dir(object)中,它相当于只是拿出了key,在object__dict__ 中它将 key 和 value都拿出来了。