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))
View Code

    执行结果如下:

 

 

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))
View Code

  代码的执行结果为:

创建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()))
View Code

 

 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)
View Code

 

上面的示例:在类定义好后的测试代码中,凡执行出错的,就注释掉了,且在该行代码后面注明了原因。代码的执行结果如下:

 

 

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)
View Code

 

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 原生支持多态。

 

posted @ 2018-08-07 14:32  蒸水渔翁  阅读(165)  评论(0)    收藏  举报