Python进阶-面向对象

类的成员

类的成员可以分为三类:字段、方法、属性

一:字段:

普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同

  • 普通字段属于对象
  • 静态字段属于类

字段的定义和使用

class Province:
    # 静态字段
    country = '中国'
    def __init__(self,name):
        # 普通字段
        self.name = name
# 直接访问普通字段
obj = Province('北京')
print obj.name

# 直接访问静态字段
print Province.country

点睛:

1:谁来调用:

     从上面可以看出普通字段需要通过对象来访问,静态字段通过类来调用。

2:存储的位置

  1. 静态字段只存在把内存中一份,存在类的内存中
  2. 普通字段在每个对象中都要创建一份。

通过类创建对象的时候,如果每个对象都具有相同的字段,那么就使用静态字段

二:方法

普通方法、静态方法、类方法。三种方法在内存中都属于类,区别在于调用方式不同

  • 普通方法:由对象调用,至少一个self参数,执行普通方法时,自动将调用该方法的对象赋值给self
  • 类方法:由类调用,至少一个cls参数,执行类方法时,自动将调用该方法的类赋值给cls
  • 静态方法:由类调用,无默认参数

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

class Foo:     # 初始化类     def __init__(self):         pass     # 定义普通方法,至少有一个self参数     def p(self):         print '普通方法'     # 定义类方法,至少有一个cls参数     @classmethod     def q(cls):         print '类方法'     # 定义静态方法     @staticmethod     def w():         print '静态方法' # 调用普通方法 a = Foo() ret = a.p() # print ret # 调用类方法 Foo.q() # 调用静态方法 Foo.w()

点睛:

       相同点:对于所有的方法而言,均属于类中,所以在内存中也之保存一份

       不同点:方法调用者不同,调用方法时,自动传入的参数不同

三:属性

1:属性的基本使用

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

class Foo:     def func(self):         # print 'func'         return '方法调用的返回值'       # 定义属性     @property     def prop(self):         # print 'prop'         return '属性调用的返回值' # 调用方法 obj = Foo() ret = obj.func() print ret   # 调用属性 ret1 = obj.prop print ret1

点睛:

  1. 定义时,在普通方法的基础上在上面添加@property装饰器
  2. 属性仅有一个self参数
  3. 调用时,无需括号

        方法:

              obj = Foo()

              ret = obj.func()

        属性:

              obj = Foo()

              ret = obj.prop

属性存在的意义:访问属性时,可以制造出和访问字段完全相同的假象

实例:

对于主机列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第M条到第N条的所有数据,这个分页功能包括:

  1. 根据用户请求的当前和总数据条数计算出m和n
  2. 根据m和n去数据库请求数据

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

class Pager:     def __init__(self,current_page):         # 用户当前请求的页面         self.current_page = current_page         # 每页默认显示10条         self.per_items = 10     # 定义属性     @property     def start(self):         val = (self.current_page - 1) * self.per_items         return val     @property     def end(self):         val = self.current_page * self.per_items         return val # 调用属性 p = Pager(2) print  p.start print  p.end # 结果: # 10 # 20

2:属性的两种定义方式

装饰器、静态字段

装饰器:在方法上应用装饰器

静态字段:在类中定义值为property对象的静态字段

装饰器方式:

经典类,具有一种@property装饰器

# 定义类
class Foo:
    @property
    def fun(self):
        return 'caoxiaojian'
# 调用属性
obj = Foo()
ret = obj.fun
print ret
# 自动执行 @property修饰的fun方法,并获取方法的返回值

新式类,具有三种@property装饰器

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

class Goods(object):     @property     def price(self):         print '@property'     @price.setter     def price(self,value):         print '@price.setter',value     @price.deleter     def price(self):         print '@price.deleter'   # 调用 obj = Goods()   obj.price               # 自动执行@property修饰的price方法,并获取方法的返回值 obj.price = 123         # 自动执行@price.setter修饰的price方法,并将123赋值给方法的参数 del obj.price           # 自动执行@price.deleter修饰的price方法 执行结果: @property @price.setter 123 @price.deleter

注释:

经典类中的属性只用一种访问方式,其对应被@property修饰的方法

新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法

因为新式类有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为同一个属性:获取、修改、删除

实例讲解:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

class Goods(object):     def __init__(self):         # 原价         self.original_price = 100         # 折扣         self.discount = 0.8       @property     def price(self):         # 实际价格 = 原价 * 折扣         new_price = self.original_price * self.discount         return new_price       @price.setter     def price(self,value):         # 设置原始价格         self.original_price = value     @price.deleter     def price(self,value):         # 删除原始价格         del self.original_price # 调用 obj = Goods() # 获取商品价格 obj.price # 设置原始价格 obj.price = 3000 # 删除原始价格 del obj.price

静态字段方式:

创建值为property对象的静态字段

当使用静态字段的方式创建属性时,经典类和新式类无区别

1 2 3 4 5 6 7 8 9

class Foo:     def get_bar(self):         return 'caoxiaojian'     BAR = property(get_bar)   obj = Foo() # 自动调用get_bar方法,并获取方法的返回值。 ret = obj.BAR print ret

property的构造方法中有个四个参数

  • 第一个参数是方法名,调用对象.属性时自动触发执行方法
  • 第二个参数是方法名,调用对象.属性 = xxx时自动触发执行方法
  • 第三个参数是方法名,调用del 对象.属性时自动触发执行方法
  • 第四个参数是字符串,调用对象.属性.__doc__此参数是该属性的描述信息

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

class Foo:     def get_bar(self):         return 'caoxiaojian'     # 必须有两个参数     def set_bar(self):         return 'set value' + value     def del_bar(self):         return 'caoxiaojian===2'     BAR = property(get_bar, set_bar, del_bar,'description......')   obj = Foo() print obj.BAR           # 自动调用第一个参数中定义的方法:get_bar obj.BAR = "caogaotian"  # 自动调用第二个参数中定义的方法:set_bar方法,将"caogaotian" 当作参数传入 print obj.BAR del  obj.BAR            # 自动调用第三个参数中定义的方法:del_bar print obj.del_bar()     obj.BAR.__doc__         # 自动调用第三个参数中设置的值:'description......' ''' 结果输出: caoxiaojian caogaotian caoxiaojian===2 '''

类成员的修饰符

两种形式:

  1. 私有成员:只有在类的内部才能访问的方法
  2. 公有成员:在任何地方都能访问

定义的不同:

私有成员命名时,前面两个字符是下划线。(特殊成员除外,例如:__init__等)

class C:
    def __init__(self):
        self.name = '公有字段'
        self.__name = '私有字段'

私有成员和公有成员的访问限制不同

静态字段

  • 公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
  • 私有静态字段:仅类内部可以访问

公有静态字段

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

class C:     name = '公有静态字段'     def func(self):         print C.name class D(C):     def func_1(self):         print C.name # 直接使用类访问 C.name # 类内部访问 obj = C() obj.func() # 派生类内部访问 obj_1 = D() obj_1.func_1() ''' 结果打印: 公有字段 公有字段 '''

私有静态字段

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

class C:     __name = '公有静态字段'     def func(self):         print C.__name class D(C):     def func_1(self):         print C.__name # 类中访问 # C.__name    # 错误 # 类内部访问 obj = C() obj.func() # 派生类中访问 # obj_1 = D()    # 错误 # obj_1.func_1()

普通字段

  • 公有普通字段:对象、类、派生类都可以访问
  • 私有普通字段:只能在类内部访问

公有普通字段

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

class C:     def __init__(self):         self.foo = '公有字段'     def func(self):         # 在类内部调用访问         print self.foo class D(C):     def show(self):         # 在派生类中调用访问         print self.foo obj = C() # 通过对象访问 print type(obj.foo) print  obj.foo print '===========' # 类的内部访问 obj.func() print '===========' obj_1 = D() # 在派生类中访问 obj_1.show() ''' 结果打印: <type 'str'> 公有字段 =========== 公有字段 =========== 公有字段 '''

私有普通字段

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

class C:     def __init__(self):         self.__foo = '私有普通字段'     def func(self):         # 类的内部调用访问         print self.__foo class D(C):     def show(self):         # 在派生类中调用访问         print self.__foo obj = C() # obj.__foo      # 通过对象访问:报错 obj.func()       # 通过类内部访问   obj_1 = D() #obj_1.show()    # 通过派生类调用访问: 报错

类的特殊成员

1:__doc__

表示类的描述信息

class C:
    """
    这是描述信息,你看什么看??
    """
    def func(self):
        pass
print C.__doc__
# 输出:这是描述信息,你看什么看??

2:__module__和__class__

__module__:表示当前操作的对象在哪个模块

__class__: 表示当前操作的对象的类是哪一个

在tmp模块下面有test.py和test1.py

test.py

class C:
    def __init__(self):
        self.name = 'caoxiaojian'

test1.py

from test import C
# 根据导入的C类创建对象
obj = C()
# 获取对象中的模块名
print obj.__module__   # test
# 获取对象中的类名
print obj.__class__    # test.C

3:__init__

构造方法,通过类创建对象时,自动触发执行

class C:
    def __init__(self,name):
        self.name = name
        self.age = 18
obj = C('caoxiaojian') # 自动执行类中的__init__方法
print obj.name

4:__call__

对象后面加括号,触发执行

点睛:

构造方法的执行是由创建对象触发的。即:对象名 = 类名()

__call__方法的执行由对象后面加括号触发的。即:对象()或者类名()()

class C:
    def __init__(self):
        pass
    def __call__(self, *args, **kwargs):
        print '__call__'

obj = C()      # 触发__init__
obj()          # 触发__call__

5:__dict__

类或对象中的所有成员

点睛:

类的普通字段属于对象,类中的静态字段和方法等属于类

class Province:
    country = 'china'
    def __init__(self,name,count):
        self.name = name
        self.count = count
 
    def func(self, *args, **kwargs):
        print 'func===func'
 
# 获取类中的成员:静态字段和方法
print Province.__dict__
# {'country': 'china', '__module__': '__main__', 'func': <function func at 0x021DA7F0>, '__init__': <function __init__ at 0x021DA870>, '__doc__': None}
 
# 调用类创建obj对象
obj = Province('shandong',100000)
print obj.__dict__
# {'count': 100000, 'name': 'shandong'}
 
# 调用类创建foo对象
foo = Province('beijing',20000)
print foo.__dict__
# {'count': 20000, 'name': 'beijing'}

类的分类:

经典类和新式类

# 经典类
class func:
    def Foo(self):
        pass
# 新式类
class func_new(object):
    def Foo_new(self):
        pass

点睛:

     区别:就是在类的后面加个object

类的继承

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

# 新式类 class D(object): # 经典类 #class D:     def bar(self):         print 'D.bar' class C(D):     def bar(self):         print 'C.bar' class B(D):     pass class A(B,C):     pass a = A() a.bar()   ''' 经典类:深度优先  D.bar 新式类:广度优先  C.bar '''

点睛:

经典类:深度优化

新式类:广度优化

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏企鹅号快讯

Python这些问题你都会吗?

距离Python圣诞学习狂欢夜 还有4天 点击进入详细了解 final作用域的代码一定会被执行吗? 正常的情况下,finally作用域的代码一定会被执行的,不管...

24850
来自专栏从流域到海域

《笨办法学Python》 第32课手记

《笨办法学Python》 第32课手记 本节课讲for循环和list,list里类似于c中的数组,但有区别很大。C语言中的数组是数据类型相同的值的集合,list...

22190
来自专栏Linux驱动

29.C++- 异常处理

C++内置了异常处理的语法元素 try catch try语句处理正常代码逻辑 当try语句发现异常时,则通过throw语句抛出异常,并退出try语句 catc...

30960
来自专栏java学习

Java每日一练(2017/8/21)

每日一句 学的到东西的事情是锻炼,学不到的是磨练。 查看以前的所有练习题目以及答案:https://mp.weixin.qq.com/mp/homepage?_...

374160
来自专栏吾爱乐享

java学习之数组元素排序,冒泡排序和选择排序

12940
来自专栏从零开始学 Web 前端

01 - JavaSE之基础及面向对象

byte(-128 ~ 127) short(-32768 ~ 32767) int(-2147483648 ~ 2147483647)

19140
来自专栏C/C++基础

CC++变参函数

C语言中,有时需要变参函数来完成特殊的功能,比如C标准库函数printf()和scanf()。C中提供了省略符“…”能够帮主programmer完成变参函数的书...

11410
来自专栏CaiRui

Python列表删除的三种方法

1、使用del语句删除元素 >>> i1 = ["a",'b','c','d'] >>> del i1[0] >>> print(i1) ['b', 'c',...

30880
来自专栏小二的折腾日记

《effective C++》from line 1 to line 12

包含着最初的以c语言为基础的C,面向对象的C++,C++的泛型编程,以及STL。在我们使用的过程中,可能会穿插,但是我们需要根据不同的情况使用不同的策略。

10830
来自专栏全沾开发(huā)

搞懂JavaScript中的连续赋值

搞懂JavaScript中的连续赋值 前段时间老是被一道题刷屏,一个关于连续赋值的坑。 遂留下一个笔记,以后再碰到有人问这个题,直接...

45160

扫码关注云+社区

领取腾讯云代金券