Python:面向对象(二)

  • 扩展:

 继承:

class A:
    def f(self):
        self.f1()

class B(A):
    def f1(self):
        print("B")

class C:
    def f1(self):
        print("C")

class D(C,B):
  pass

d1 = D()
d1.f()
#打印结果:C

#执行顺序:D-C-B-A-A-C

 执行顺序图:

练习:

注:一定记住从底层开始找

####实例:找源码的过程(self.xxx(),从底层开始找)####
import socketserver

r = socketserver.ThreadingTCPServer()
r.serve_forever()
找源码

执行父类的构造方式:

    类名加括号执行类的普通字段:__init__

    推荐:super(当前类,self).__init__()

    不推荐:父类.__init__(self)

class Animal:
    def __init__(self):
        print("A构造方法")
        self.ty = "动物"

class Cat(Animal):
    def __init__(self):
        print("B构造方法")
        self.n = ""
        super(Cat,self).__init__()

c = Cat()
print(c.n)
#打印结果:
B构造方法
A构造方法
猫

##########

c = Cat()
print(c.__dict__)
#打印结果:
B构造方法
A构造方法
{'ty': '动物', 'n': ''}
  • 面向对象的进阶

一、成员

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

 

 字段

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

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

  注:静态字段:调用

    普通字段:对象调用

class Foo:
    # 静态字段,在类里(没有self),由类调用
    country = "中国"

    # 普通字段,封装在对象中,由对象调用
    def __init__(self,name):
        self.name = name

    # 普通方法,在类里,由对象调用
    def show(self):
        print("show")


print(Foo.country)
obj = Foo("北京")
print(obj.name)
obj.show()
#打印结果:
中国
北京
show

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

 

 方法

 方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,但是调用方式有所不同。

注:

普通方法:对象调用,至少一个self参数,执行普通方法时,自动将调用该方法的对象赋值给self

静态方法:调用,没有默认参数,可以添加参数。关键字:@staticmethod

类方法:调用,至少一个cls参数,执行类方法时,自动将调用该方法的类名复制给cls。关键字:@classmethod

class Provice:
    # 静态字段
    country = "China"

    # 普通字段
    def __init__(self):
        self.name = "China"

    # 类方法
    @classmethod
    def f1(cls):
        print("F1")

    # 静态方法
    @staticmethod
    def f2():
        print("F2")

    # 普通方法
    def show(self):
        print("show")
 
obj = Provice()
obj.show() # 用对象调用普通方法
Provice.f1() # 用类调用类方法,默认参数为cls
Provice.f2() # 用类调用静态方法,默认无参数

#打印结果:
show
F1
F2

属性

  Python中的属性其实是普通方法的变种。

属性的基本使用:

定义及调用:

  定义:仅有一个self参数,加参数会报错。关键字:@property

  调用:用对象调用属性,调用时不加括号

class Foo:
def __init__(self): self.name = "num"

def start(self): print("start") #定义属性 @property def end(self): print("end") obj = Foo() obj.start() obj.end #打印结果: start end

设置字段:字段是能获取也能重新设置:

class Foo:
    def __init__(self,name):
        self.name = name

    @property
    def end(self):
        temp = "%s A" % self.name
        return temp

obj = Foo("num")
#获取字段
print(obj.name)
#设置字段
obj.name = "123"
print(obj.name)

#打印结果:
num
123

设置属性:属性是将方法伪造成字段(调用时不加括号):@方法名.setter

class Foo:
    def __init__(self,name):
        self.name = name

    @property
    def end(self):
        temp = "%s A" % self.name
        return temp
    @end.setter
    def end(self,value):
        print(value)

obj = Foo("num")
print(obj.end) #获取end值
obj.name = "123" #设置end值,执行@方法名.setter方法
print(obj.end) 
#打印结果:
num A
123 A

二、成员修饰符

  •  公有成员,在任何地方都能访问

  • 私有成员,只有在类的内部才能访问

 私有成员和公有成员的定义不同:私有成员命名时,前两个字符是下划线。(特殊成员除外:__init__、__call__、__dict__等)

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

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

  静态字段

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

私有静态字段:仅类内部可以访问

class C:

    name = "公有静态字段"

    def func(self):
        print C.name

class D(C):

    def show(self):
        print C.name


C.name         # 类访问

obj = C()
obj.func()     # 类内部可以访问

obj_son = D()
obj_son.show() # 派生类中可以访问
公有静态字段
class C:

    __name = "公有静态字段"

    def func(self):
        print C.__name

class D(C):

    def show(self):
        print C.__name


C.__name       # 类访问            ==> 错误

obj = C()
obj.func()     # 类内部可以访问     ==> 正确

obj_son = D()
obj_son.show() # 派生类中可以访问   ==> 错误
私有静态字段
class Foo:
    xo = "xo"
    __xx = "xx"
    def __init__(self):
        pass
    def f(self):
        print(Foo.__xx)
    def d(self):
        print("d")

print(Foo.xo)
# print(Foo.__xx)#报错,有__只能内部执行
obj = Foo()
obj.f()
#打印结果:
xo
xx

  普通字段

公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问

私有普通字段:仅类内部可以访问

ps:如果想要强制访问私有字段,可以通过 【对象._类名__私有字段明 】访问(如:obj._C__foo),不建议强制访问私有成员。

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_son = D();
obj_son.show()  # 派生类中访问
公有普通字段
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_son = D();
obj_son.show()  # 派生类中访问  ==> 错误
私有普通字段
class Foo:
    xo = "xo"
    __xx = "xx"
    def __init__(self):
        self.__name = "name"
    def f(self):
        print(Foo.__xx)
    def d(self):
        print(self.__name)

obj = Foo()
obj.f()
obj.d()
#打印结果:
xx
name

三、面向对象中一些常用特殊方法

 1、__init__:构造方法,通过类创建对象时,自动触发执行。

class Foo:

    def __init__(self, name):
        self.name = name
        self.age = 18


obj = Foo('wupeiqi') # 自动执行类中的 __init__ 方法
__init__

2、__del__:析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

class Foo:

    def __del__(self):
        pass
__del__

3、__call__:对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Foo:

    def __init__(self):
        pass
    
    def __call__(self, *args, **kwargs):

        print '__call__'


obj = Foo() # 执行 __init__
obj()       # 执行 __call__
__call__

4、__getitem__、__setitem__、__delitem__:获取、设置、删除数据。用于索引操作,如字典。

class Foo(object):
 
    def __getitem__(self, key):
        print '__getitem__',key
 
    def __setitem__(self, key, value):
        print '__setitem__',key,value
 
    def __delitem__(self, key):
        print '__delitem__',key
 
 
obj = Foo()
 
result = obj['k1']      # 自动触发执行 __getitem__
obj['k2'] = '123'   # 自动触发执行 __setitem__
del obj['k1']           # 自动触发执行 __delitem__
__getitem__、__setitem__、__delitem__

5、__dict__:类或对象中的所有成员。

class Province:

    country = 'China'

    def __init__(self, name, count):
        self.name = name
        self.count = count

    def func(self, *args, **kwargs):
        print 'func'

# 获取类的成员,即:静态字段、方法、
print Province.__dict__
# 输出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None}

obj1 = Province('HeBei',10000)
print obj1.__dict__
# 获取 对象obj1 的成员
# 输出:{'count': 10000, 'name': 'HeBei'}

obj2 = Province('HeNan', 3888)
print obj2.__dict__
# 获取 对象obj1 的成员
# 输出:{'count': 3888, 'name': 'HeNan'}
__dict__

6、__iter__:用于迭代器,之所以列表、字典、元祖可以进行for循环,是因为类型内部定义了__iter__。

class Foo(object):

    def __init__(self, sq):
        self.sq = sq

    def __iter__(self):
        return iter(self.sq)

obj = Foo([11,22,33,44])

for i in obj:
    print i
__iter__

7、__str__:如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

class Foo:

    def __str__(self):
        return '123'


obj = Foo()
print obj
# 输出:123
__str__
  • 异常处理

1、异常基础

程序出现bug时,一般不会将错误信息显示给用户,而是实现一个提示的页面。

异常处理格式:

1 try:
2     pass
3 except Exception as e:
4     pass

练习:将用户输入的两个数字相加

while True:
    num1 = input("num1:")
    num2 = input("num2:")
    try:
        num1 = int(num1)
        num2 = int(num2)
        result = num1 + num2
    except Exception as e:
        print("出现异常,信息如下:")
        print(e)
View Code

2、异常种类

异常种类,不同种类处理不同异常

AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
常用异常
ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError
其他异常

实例:IndexError、KeyError、ValueError

########
li = []
try:
    li[3]
except IndexError as e:
    print(e)

########
dic = {"k1":"v1"}
try:
    dic["k2"]
except KeyError as e:
    print(e)

########
s = "hello"
try:
    int(s)
except ValueError as e:
    print(e)

#打印结果:
list index out of range
'k2'
invalid literal for int() with base 10: 'hello'

异常类只能用来处理制定的异常情况,如果非制定异常则无法处理

#未捕获到异常,程序直接报错
s = "hello"
try:
    int(s)
except ValueError as e:
    print(e)

为了避免有其他异常,可以这样写:

s = "hello"
try:
    int(s)
except IndexError as e:
    print(e)
except KeyError as e:
    print(e)
except ValueError as e:
    print(e)

万能异常:因为异常不止几种,有一个万能异常,就可以捕获任意异常

s = "hello"
try:
    int(s)
except Exception as e:
    print(e)

虽然有万能异常,但是也不能只用万能异常就可以来了,因为对于特殊处理或提醒的异常需要先定义,最后再定义Exception来确保程序正常运行。

s = "hello"
try:
    # li = []
    int(s)
except IndexError as e:
    print(e)
except ValueError as e:
    print(e)
except Exception as e:
    print("123")

3、异常其他结构

分两种情况:

a:try --> exceot KeyError as e --> finally

b: try --> else --> finally

try:
    # 主代码块
    pass
except KeyError as e:
    # 主代码异常时,执行该块
    pass
else:
    # 主代码块正常时,执行完,执行该块
    pass
finally:
    # 无论异常与否,最终执行该块
    pass

4、主动触发异常

try:
    print("123")
    raise Exception("出错了...")
except Exception as e:
    print(e)
#打印结果:
123
出错了...

5、断言

#assert 作为关键字

#条件成立就执行
assert 1 == 1

 #条件不成立就报错
assert 1 == 2

作业:选课(对象中可以封装对象) 

特性补充:

 方法一:装饰器+方法

class Foo:
    def func(self):
        print("func")

    @property
    def pp(self):
        return 123

    @pp.setter
    def pp(self,value):
        print(value)

    @pp.deleter
    def pp(self):
        print("del")
obj = Foo()
print(obj.pp) # 执行property
obj.pp = 999 # 执行setter
del obj.pp # 执行 deletser

 方法二:property+方法

class Foo:
    def f1(self):
        return "123"
    def f2(self,value):
        print(value)
    def f3(self):
        print("del")

    test = property(fget=f1,fset=f2,fdel=f3)
obj = Foo()
ret = obj.test
print(ret)
obj.test = "456"
del obj.test

Python2.7继承流程

 经典类(当未继承object时):

#深度优先
class Bar:
    def f1(self):
        print("BAR")

class A(Bar):
    def f(self):
        print("A")

class B(Bar):
    def f1(self):
        print("B")

class C(A):
    def f(self):
        print("C")

class D(B):
    def f1(self):
        print("D")

class E(C,D):
    def f(self):
        print("E")


obj = E()
obj.f1()
#E-C-A-Bar

流程图:

新式类(继承object时):

#广度优先
class Bar(object):
    def f1(self):
        print("BAR")

class A(Bar):
    def f(self):
        print("A")

class B(Bar):
    def f(self):
        print("B")

class C(A):
    def f(self):
        print("C")

class D(B):
    def f(self):
        print("D")

class E(C,D):
    def f(self):
        print("E")


obj = E()
obj.f1()
#执行流程:E-C-A-D-B-Bar

流程图:

抽象方法抽象类:约束

#####接口(python里面没有接口)#####
#####用抽象类加抽象方法实现接口
#####子类继承抽象类必须至少实现抽象方法的方法==子类中的方法必须等于大于基类中的方法
from abc import ABCMeta
from abc import abstractmethod
class Father(metaclass=ABCMeta):
    @abstractmethod
    def f1(self):pass
    @abstractmethod
    def f2(self):pass

#####继承抽象类和抽象方法
class Foo(Father):
    def f1(self):pass
    def f2(self):pass
    def f3(self):pass

obj = Foo()
原文地址:https://www.cnblogs.com/0820-zq/p/5554011.html