实例变量 & 类变量
class Role(object):
# <类变量> = var
n = 100
n_list = []
name = 'hahaha'
def __init__(self, var):
# self.<实例变量> = var
self.name = var
>>>r1 = Role(var='lalala')
>>>r1.name
lalala
>>>Role.name
hahaha
>>>r2 = Role('lex')
>>>r2.n
100
>>>r1.n = 200
>>>r1.n
200
>>>r2.n
100
# 其实在r1的内存里创建了变量 n=200,类变量没动
# r1,r2,Role 都公用一个内存变量 n_list
>>>r1.n_list.append("from r1")
>>>r2.n_list.append("from r2")
>>>r2.n_list
["from r1","from r2"]
>>>Role.n_list
["from r1","from r2"]
析构函数
在实例释放、销毁的时候自动执行
del var 启动 __del__(self)方法
摘掉门牌号,自动回收机制删除内存
私有方法、私有属性
加俩下划线:self.life_value ---> self.__life_value
外界无法直接访问,可以内部定义一个方法访问
类的封装
封装数据的函数是和Student类本身是关联起来的,我们称之为类的方法。
简单的说,将外部函数内部化为类的方法,就是封装。
新式类 & 经典类
""" Author: Dr.Ch """
# class People: ## 经典类写法
class People(object): # 新式类 ## object是个基类
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print("%s is eating..." % self.name)
def talk(self):
print("%s is talking..." % self.name)
def sleep(self):
print("%s is sleeping..." % self.name)
class Relation(object): # 给人加上社交属性
def make_friends(self, obj): # obj 是 其他人,尚未实例化的
print("%s is making friends with %s" % (self.name, obj.name))
class Man(People, Relation): # 注释1
# 为了增加子类属性,需要重构 __init__()
def __init__(self, name, age, money): # 增加属性:男人出生就有钱
# 把父类的属性拿过来
People.__init__(self, name, age) # 经典类写法
self.money = money
print("%s 一出生就有 %s money" % (self.name, self.money))
def whoring(self): # 定义子类新方法
print("%s is whoring..." % self.name)
def sleep(self):
print("man is sleeping...") # 更改父类方法
def talk(self):
People.talk(self) # 直接调用父类方法
def eat(self):
People.eat(self)
print("man is eating...") # 在父类方法上增加新功能
class Woman(People, Relation):
def __init__(self, name, age, height, big_breast=True):
# 另一种高级的方法继承父类,代替 line32 的语法
super(Woman, self).__init__(name, age) # 新式类写法 ## 注释2
self.height = height
self.big_breast = big_breast
def get_birth(self):
print("%s is born a baby..." % self.name)
print("\n--------- 多继承 -----------")
m3 = Man("Jon", 25, 2000)
w3 = Woman("Maria", 22, 170, False)
m3.make_friends(w3)
print("\n--------- women -----------")
w1 = Woman("alex", 22, 162)
w1.get_birth()
print("\n--------- men -----------")
m1 = Man("lex", 23, 20)
m1.whoring()
m1.sleep()
m1.talk()
m1.eat()
print("\n--------- men 继承 -----------")
m2 = Man("clark", 24, 100)
print("\n--------- women 继承 -----------")
w2 = Woman("lana", 21, 165)
"""
注释1:Man的实现 先在Man里面执行__init__()生成 name ,再继承Relation的方法,所以name已经有了
不是在People里面执行__init__(),所以 Man(People,Relation)继承顺序无影响。
如果没有自己的构造方法,应该去执行父类的__init__(),然而依然没有报错(Relation,People),
因为make_friends()还没有执行。
……总之按照从左到右顺序继承。(见视频30分钟处)
对象生成,先实例化,多继承的时候,从左到右: SubClass(Class1,Class2,...,ClassN):
先执行 SubClass 的 构造函数__init__(),如果没有构造函数,则
执行 Class1 的 构造函数,如果 Class1 也没有 构造函数,则
执行 Class2 的 构造函数,…… 以此类推。重点是,只继承一个就结束。
—— 关于广度优先、深度优先见视频6.9 10分钟左右——(面试必备)
A,B(A),C(A),D(B,C)
py2 是深度优先:D先继承B,再继承A,最后继承C
py3 经典类和新式类都是统一按照广度优先来继承的:D先继承B,再继承C,最后继承A
注释2:与 People.__init__(self, name, age) 相比优点在于,
super(Woman,self).__init__(name, age) 不用写父类名 People,
如果有一天 People 名字改了,只需要改一次 line50 处
另外,有利于多继承。
经典类 和 新式类 区别主要体现在 多继承 上。
"""
--------- 多继承 -----------
Jon 一出生就有 2000 money
Jon is making friends with Maria
--------- women -----------
alex is born a baby...
--------- men -----------
lex 一出生就有 20 money
lex is whoring...
man is sleeping...
lex is talking...
lex is eating...
man is eating...
--------- men 继承 -----------
clark 一出生就有 100 money
--------- women 继承 -----------
Process finished with exit code 0
静态方法
@staticmethod 静态方法 跟 类 的关系切断了,变成了普通的函数
唯一与类的关联就是,如果要调用,必须通过类名(实例名)调用
普通的 类的方法 需要传入self参数。
(如果非要传self参数,需要再把实例传进去,这就失去静态方法的意义了)
用处:把类变成一个工具包组合。
类方法
@classmethod 类方法只能访问类变量,不能访问实例变量(似乎没怎么用过)
场景:强制使用类属性,实例变量改了没用,比如禁止改国籍。
属性方法
@property 导致方法不可调用
效果:把一个方法变成一个静态属性,不再可以加()调用,不能传参数了
作用:隐藏实现细节,只给用户输出结果。
查看类方法的说明文档
import pandas as pd
df = pd.DataFrame(data)
# 查看DataFrame类在哪个模块里:
>>>df.info()
>>>
...
# 查看info()方法说明文档:
print(pd.DataFrame.info.__doc__)
df 的各种操作
df.sum() # 按字段求和