Python的类
1、如何创建类
1.1 类
class 类名:
pass
1.2 方法
1.2.1 构造方法:创建实例时自动调用
def __init__(self,arg):
pass
1.2.2 普通方法:
def 方法名(self, 参数......):
pass
1.2.3 特殊方法:像Python的str对象,里面有许多 __xxx__ 方法,都是在特定情况下 去执行的。
对象() 或 类()() 执行:
def __call__(self, *argv,**kwargv):
pass
str(对象) 时执行:
def __str__(self):
return "str"
int(对象) 时执行
def __int__(self):
return 1111
def __del__(self): 析构函数
obj.__dict__ : 将 类/对象所封装的所有内容以字典方式打印出来
1 class Foo: 2 def __init__(self,name): 3 self.name = name 4 5 def __call__(self, *args, **kwargs): 6 print("执行 __call__ 方法") 7 8 def __str__(self): 9 print("str(对象) 时执行: ",end="") 10 return self.name 11 12 def __int__(self): 13 print("int(对象) 时执行: ", end="") 14 return 1111 15 16 17 foo = Foo("张三") 18 foo() 19 print(foo) 20 print(int(foo))
执行结果如下:

1.3 属性
在 __init__ 函数外定义的变量,为 静态属性。静态属性 一个类 只有一份,大家共享。类与对象(类实例化,就是对象)皆可访问。
在 __init__ 里定义的、带 self. 的变量为 普通属性:普通属性 只有对象可以访问。
在 __init__ 里 访问 静态变量,要加 类名做前缀!(不能加self)
1 class Foo: 2 cnt=0 3 def __init__(self, name): 4 Foo.cnt += 1 5 self.name = name 6 7 foo1 = Foo("Zhangsan") 8 foo2 = Foo("Lisi") 9 print("创建foo1、foo2后,foo1.name=%s, foo2.name=%s " % (foo1.name,foo2.name)) 10 print("\t\t静态变量cnt的内存地址:",id(foo1.cnt),id(foo2.cnt)) 11 foo1.cnt = 100 12 print("外围对foo1.cnt=100后,静态变量cnt的内存地址:",id(foo1.cnt),id(foo2.cnt)) 13 foo2.name = "Wangwu" 14 print("外围只修改foo2.name后,foo1.name=%s, foo2.name=%s " % (foo1.name,foo2.name))
代码的执行结果为:
创建foo1、foo2后,foo1.name=Zhangsan, foo2.name=Lisi
静态变量cnt的内存地址: 1796264416 1796264416
外围对foo1.cnt=100后,静态变量cnt的内存地址: 1796265984 1796264416
外围只修改foo2.name后,foo1.name=Zhangsan, foo2.name=Wangwu
Process finished with exit code 0
从上面的结果得出:
1、创建2个对象后,2个对象cnt的地址相同,故:静态变量存在类里,在该类与它的所有实例里只有一份。
2、修改 foo2.name后,foo1.name不变,故:普通属性存在 对象里,各个对象皆有一份。
3、外围对foo1.cnt=100后,2个对象的静态变量cnt的内存地址不一致了,这是因为:
Python在使用变量前不需要定义其类型,当 解释器看到 foo1.cnt = 100 时,一查,foo1里没有cnt,就创建一个新的int对象foo1.cnt,并将100赋给它。【因为赋值,才创建】
当 查 foo1.cnt和foo2.cnt的内存地址时,解释器会分别去找它们;找到了就显示其内存地址,否则报错!
下面的代码可以清晰地体现出来:
1 class test(object): 2 pass 3 4 t = test() 5 print(t.count) # 会出错,因为count不存在 6 t.count = 1 7 print(t.count) # 不会出错,因为新创建了一个count
4、对 类成员(静态变量,或静态属性)进行包装
1 class Foo(object): 2 __count = 0 # 私有变量,无法在外部访问,Foo.__count会出错 3 4 # 类方法和静态方法都不能使用 @property 进行包装,负责报错:TypeError: 'staticmethod' object is not callable 5 @classmethod 6 def get_count(cls): 7 return cls.__count 8 9 @classmethod 10 def set_count(cls, num): 11 cls.__count = num 12 13 foo1 = Foo() 14 foo2 = Foo() 15 foo1.set_count(foo1.get_count()+3) 16 foo2.set_count(foo2.get_count()+5) 17 print("foo1.count=%d,\tfoo2.count=%d" % (foo1.get_count(),foo2.get_count()))
1.4 示例:包含静态属性、普通属性、静态方法、普通方法的类
1 #!/usr/bin/env python 2 # encoding: utf-8 3 """ 4 @author: Fisher 5 @file: pyclass.py 6 """ 7 class Foo: 8 # 静态属性 9 country = "China" 10 # 在名称前加 __ 表示私有,外面不能访问 11 __forwhat = "day dream" 12 13 # 构造方法 14 def __init__(self, name, cixu): 15 # 定义几个普通属性 name、cixu、degree 16 self.name = name 17 self.cixu = cixu 18 self.degree = 0 19 # 私有属性 __per_money, 只能在 类内部访问 20 self.__per_money = 5000 21 22 # 静态方法里不能引用 普通属性。因为静态方法由类调用,此时 还没有实例化对象,普通属性还没有生成。 23 # 静态方法: 方法前加 @staticmethod,保存在类中,由类直接调用。不必加 self 参数 24 @staticmethod 25 def staticfunc(): 26 print("static function") 27 28 # 类方法里也不能引用 普通属性。理由同 静态方法 29 # 类方法: 方法前加 @classmethod,保存在类中,由类直接调用。加 cls 参数 表示 当前类 30 @classmethod 31 def classfunc(cls): 32 print("%s class function" % cls) 33 34 # 下面是普通方法 35 # 外部只能通过 get_per_money 这个方法访问 __per_money! 36 def get_per_money(self): 37 return self.__per_money 38 39 # 外部只能通过 get_forwhat 这个方法访问 __forwhat! 40 def get_forwhat(self): 41 return Foo.__forwhat 42 43 def show(self): 44 print(self.name, self.cixu) 45 46 def set_degree(self, d): 47 self.degree = d 48 49 def get_degree(self): 50 return self.degree 51 52 def del_degree(self): 53 pass 54 55 # 定义属性方法(分别设定 get/set/del方法: 定义了用 dg 来h获取/设置属性 degree ) 56 dg = property(fget=get_degree, fset=set_degree, fdel=del_degree) 57 58 ''' 46-56 定义了用 dg 来取/设置属性 degree 的 “快捷方式”: 59 对象实例化后(假定为foo),可以 用 x = foo.dg 取得 对象的degree属性的值;foo.dg = 5 即可对 degree赋值。 60 61 没有 56行,可以在 49行上加 @property,就能像访问属性一样使用 get_degree函数:x = foo.get_degree 62 如果 在 46行上 加上 @dg2.setter , 则 执行 foo.dg2 = 60 相当于: foo.set_dgree(60) 63 ''' 64 65 66 print('不实例化类,直接以类的方式运行') 67 print(Foo.country) 68 #print(Foo.__forwhat) # 不能直接访问私有的静态属性 69 Foo.staticfunc() 70 Foo.classfunc() 71 #print(Foo.name) # 类没有实例化(变成对象)之前,不能访问 对象属性 72 73 print('\n实例化类,用对象去调用') 74 foo = Foo("Hunan", 20) 75 print(foo.country) 76 foo.classfunc() 77 foo.staticfunc() 78 79 print("\n调用其他") 80 foo.show() 81 print(foo.name, foo.cixu) 82 83 #print(foo.__per_money) # 不能直接访问对象的私有属性 84 print(foo.get_per_money()) 85 86 foo.dg += 100 # 通过 property 的映射,取 foo.dg 的值 = foo.get_degree(),给 foo.dg 赋值 = foo.set_degree(值) 87 print(foo.dg)
上面的示例:在类定义好后的测试代码中,凡执行出错的,就注释掉了,且在该行代码后面注明了原因。代码的执行结果如下:

2、面向对象三大特性之一:封装
1 class Bar: 2 def __init__(self, n,a): 3 self.name = n 4 self.age = a 5 self.xue = 'o' 6 7 b1 = Bar('alex', 123) 8 b2 = Bar('eric', 456)
3、面向对象三大特性之二:继承
3.1 继承
class 父类:
pass
class 子类(父类):
pass
3.2 重写
在子类中编写同名方法覆盖父类的方法,则父类中的方法不再执行。
3.3 self永远是执行该方法的调用者
3.4 显式调用父类中的方法
super(子类, self).父类中的方法(...)
父类名.父类中的方法(self,...)
3.5 Python中支持多继承
a. 左侧优先
class obj(obj2,obj1,obj3):
pass;
o = obj()
o.func()
以上示例代码,obj 继承自 obj2、obj1、obj3。现有一个obj的示例o,执行一个方法 func。obj本身没有,则 依次到 obj2/obj1/obj3去找,找到即返回且执行该函数。若全部找了,也找不到func,则报错。
b. 一条道走到黑
类 obj 继承自 left3,right2。left3继承left2,left2继承left1;right2继承right1。若 obj的实例化对象,执行一个obj本身没有的方法,则:
先从左边找,left3->left2->left1;找完左侧,没找到,再找 right2->right1。中间,在任何一个地方找到,即返回且执行。全部找完,没找到,则报错。
c. 同一个根时,根最后执行
假设 b. 中,left1与right1有一个共同的父亲root,则:root 最后找。即
左: left3->left2->left1;转 右:right2->right1;最后:root。
4、面向对象三大特性之三:多态
Python 原生支持多态。

浙公网安备 33010602011771号