异常,类与枚举

异常

        除了关键字不一样外,其余的与java完全相同。

        try-except-finally分别表示java中的try,catch,finally。java中的throw在python中用raise代替。

try:
	f = file('x.txt')
except Exception, e: # 捕获异常,并将异常信息用e变量存储
	print e
else: # 程序没有异常时执行
	print 'no except'
finally: # 与java中一样
	print 'finally'
        python中所有的异常都是Exception的子类。

        else与finally都存在时,如果程序出现异常,不执行else但执行finally;如果程序没有异常,则先执行else,再执行finally。

raise

        raise如果不带参数的话,会将当前的异常原样抛出。

logging

       日志模块。

        basicConfig():

        python中所有的数据都是对象,包括基本数据类型,而赋值就是将对象的地址赋值给对应的变量,使变量与对象关联起来。由于基本数据类型也是对象,因此a=1语句会执行两个操作:分配一块内存存储1,并使用变量a记录该内存的地址。

        类的定义与java一样,通过class关键字表示。

函数

        所有函数至少有一个参数,并且所有函数的第一个参数都是self(它代表当前对象自身,同java中的this一样),在使用函数时不需要为第一个参数传值。

        所有类的构造函数名都是__init__,而且第一个参数也必须是self。可以在构造函数中为类定义一些全局变量。

        类的实例化也与java类似,只不过不需要关键字new。如:

class Demo:
    def __init__(self,a): # 构造函数
        self.a = a # 定义一个全局变量a
    def function(self,b):
        return 'Demo%s-%s'%(self.a,b)
d = Demo(3) # 实例化对象,并且传入构造函数需要的参数
print d.function(5) # Demo3-5
        python允许对实例变量绑定任何数据,也就是说获取对象后,可以为对象动态添加属性,新添加的属性只为该实例所有,别的实例无法使用。如下:
d = Demo(3) 
d1 = Demo(3)
d.name = 'name'
print d.name # name
print d1.name # AttributeError
        其实这和__init__一样,在__init__中self指对象本身,而此时也没有任何属性,都是在__init__函数中新添加的属性,只不过__init__是构造函数,每一个对象都会执行,也就保证了每一个对象都会有在__init__中定义的属性。

继承

        定义类时,可以在类名后面跟(),并在()中写上父类。所有的类都继承于object。如

class Demo:
	def function(self):
		return 'Demo'
class Demo2(Demo):# Demo2继承于Demo
	a = None
d = Demo2()
print d.function() # Demo

        一个类可以多继承,只需要在()中用逗号将父类隔开即要。

class P1(object):
    def say(self):
        print("say")


class P2(object):

    def sing(self):
        print("sing")


class C(P1, P2):  # C继承于P1,P2
    pass

c = C()
c.say()
c.sing()

私有

        以双下划线开头的变量是私有的,外界无法直接访问。但要注意以双下划线开头,并且以双下划线结尾的是特殊变量,是可以直接访问的。

class Demo:
	def __init__(self,a): 
		self.__a = a # 私有属性__a
		self.a = a
	def function(self,b):
		return 'Demo%s-%s'%(self.__a,b) # 私有变量,类内部可以访问
	def __private(self,c): # 私有方法
		print "__private",c
d = Demo(3) 
print d.a # 3
print d.function(5) # Demo3-5
d.__private(10) # AttributeError: Demo instance has no attribute '__private'
print d.__a	# AttributeError: Demo instance has no attribute '__a'

protected

        以_开头的变量是protected的。本类及其子类才可访问。

属性

        分为类属性与实例属性。实例属性指的是为某一个实例绑定的属性,它只属于该实例。而类属性是类中定义的属性——所有实例共享的,也可以直接通过类名点调用的。

        当类属性与实例属性同名时,实例属性会重写类属性。

class Demo(object):
    name = 'name'  # 类属性

    def __init__(self):
        self.age = 15   # 实例属性

d = Demo()
d2 = Demo()
d.score = 84  # 实例属性,该属性只属于d,d2是没有的

print(d.age, d.name, d.score)  # 15 name 84
print(d2.name, d2.age)  # name 15——d2是没有score属性的
d2.name = 'd2name'  # d2定义了实例属性,会覆盖掉Demo的类属性
print(d2.age, d2.name)  # 15 d2name
print(d.age, d.name, d.score)  # 15 name 84
print(Demo.name)  # name
del d2.name  # 删除d2的name属性
print(d2.name)  # name   d2的name属性就变成了继承于Demo的类属性
        从上面可以看出:1,实例属性只属于当前实例,跟别的实例没关系,跟类也没关系;2,类属性属于所有实例,也可直接通过类名点调用;3,实例属性可以覆盖掉类属性,所以实例属性不能与类属性重名

绑定方法

        直接通过实例点的方法可以为实例绑定属性,也可以为实例绑定某个方法,但需要借助types.MethodType。如下:

from types import MethodType


class Demo(object):
    name = 'name'  # 类属性

    def __init__(self):
        self.age = 15   # 实例属性


def say(self,age):
    print('ags = %d' % age)
d = Demo()
d.say = MethodType(say, d)  # 为d实例绑定方法
d.say(11)  # ags = 11

        要注意:类的方法的第一个参数一定是self,所以绑定到实例中的方法第一个参数也一定是self

        另外,为实例绑定的方法也与绑定的属性一样,只是属于当前这个实例,别的实例是没有办法调用的。如果想所有的实例都能调用,就将该方法写成类方法。

@property

        将一个类方法变成一个只读属性,调用时通过类名点——后不需要加(),也不能为该属性重新赋值——除非定义了setter方法。如:

class Demo(object):

	@property
	def test(self):
		print('-----')
		return 1

d = Demo()
print(d.test)  # 转变为属性,所以直接通过类名点方法调用
try:
	d.test = '2'  #将test方法转变为一个只读属性,所以不能赋值
except Exception as e:
	print(e)  # can't set attribute

        @property实质上生成了一个与方法名同名的属性——property是一个装饰器。同样,也可为该属性定义setter方法:

class Demo(object):
	@property
	def test(self):
		print('getter')
	@test.setter
	def test(self,value):
		print('value = %s'%value)
d = Demo()
d.test  # getter
d.test = 'aaaa'  # value = aaaa

        首先通过@properyt生成了一个名为test的属性,而@property本身又创建了另一个test.setter装饰器,可以通过@test.setter为test属性绑定了setter方法。

        简单点理解就是:@property相当于同名属性的getter方法,使用类名点的时候就会调用该getter方法;而@xxx.setter相当于为xxx属性定义了setter方法,每一次为该属性赋值时就会走该方法。

        注意:@property与@xxx.setter装饰的方法名必须一样,其中的xxx指的是就方法名。有@property时,可以没有@xxx.setter,但必须先定义了@property才能定义@xxx.setter

内置属性和方法

        __init__:构造函数。

        __len__:类的长度,定义该方法的类可以通过len()函数求长——len()函数的实质上也是调用__len__函数。

        __str__:java中toString(),定制直接print()实例时输出的语句。

        __repr__:直接输出对象时输出语句。__str__定义的是通过print(实例)输出的内容,__repr__是直接运行对象时输出的内容。一般情况下,两者一样。如下:

>>> class Demo(object):
...     def __repr__(self):
...             return 'hahahaha'
...
>>> Demo()
hahahaha

        __slots__限定可以绑定的实例属性(注:方法也是属性,且类属性不受__slots__限制)。一般情况下,可以为实例绑定任意的属性,但定义__slots__后,能绑定的属性就被限制死了。如:

class Demo(object):

    __slots__ = ('age', 'name', 'say')  # __slots__是一个类属性,它是一个元组

    def __init__(self):
        self.age = 15  # 实例属性,age定义在__slots__中,

    def yes(self):  # 类属性,不受__slots__限制
        print("yes")


def say(self,age):
    print('ags = %d' % age)
d = Demo()
d.say = MethodType(say, d)  # __slots__中定义了say属性,所以可以绑定
d.say(11)  # ags = 11
try:
    d.score = '1111'  # _slots__中没有定义score,所以该句会报错
except AttributeError as msg:
    print(msg)  # 'Demo' object has no attribute 'score'

        还要注意的是:

        1,__slots__中不能含有类属性。因为实例属性不能与类属性重名。

        2,__slots__只对当前类起作用,对其子类不起作用,除非子类也定义了__slots__。如果子类定义了__slots__,那么子类的__slots__就是自身的__slots__加上父类的__slots__。

        __iter__:返回一个iterator。将一个对象用于for循环时,循环的其实就是__iter__的返回值。如:

class P1(object):
    name = ('a', 'b', 'c', 'yield ')

    def __init__(self):
        self.n = 0

    def __iter__(self):
        return (x*x for x in range(11))

for x in P1():  # __iter__返回的是一个iterator,此时的循环已经跟P1()这个对象没关系了
    print(x)  # 输出0到10的平方

        一般来说,它返回的都是self,表示该类本身就是一个iterator,那么这个时候该类就需要重写下面的__next__方法。

        __next__:每一个iterator通过反复调用迭代器的__next__()方法来返回后继值。也就是说,每一个iterator都需要重写该方法,并且在它的__next__中返回后继值。如:

class P1(object):
    name = ('a', 'b', 'c', 'yield ')

    def __init__(self):
        self.n = 0

    def __iter__(self):
        return self  # 该对象本身就是iterator

    def __next__(self):
        if self.n >= len(self.name):
            return 'end-----'
        result = self.name[self.n]
        self.n += 1
        return result

for x in P1():  # <span style="font-family: Arial, Helvetica, sans-serif;">该对象本身就是iterator,所以可以用于for循环
</span>    print(x)

        每一次循环时都会从__next__中取值。在本例中的循环是一个死循环。

        __getitem__:使对象可以通过下标获取数据。如:

class P1(object):
    name = ('a', 'b', 'c', 'yield ')

    def say(self):
        print("say")

    def __getitem__(self, item):
        return self.name[item]

p = P1()
print(p[2])  # c  其执行的是__getitem__方法,并将2传入item
        对于切片来说,执行切片时走的也是__getitem__方法,处理方式如下:
    def __getitem__(self, item):
        if isinstance(item, int):  # 是下标时处理
            return self.name[item]
        if isinstance(item, slice):  # 判断是否是切片
            start = item.start
            end = item.stop
            #  通过start,end等属性截取相应的元组返回即可

        与之类似的还有__setitem__与__delitem__,一个是设置一个是删除。

        __getattr__:当调用不存在的属性时,python会调用对象的__getattr__去动态地获取属性值——包括通过实例点以及getattr()方法获取。如果调用的是已经存在的属性,就不会执行__getattr__。如:

class Demo(object):
	def __getattr__(self,attr):
		if attr == 'age':
			return 20

d = Demo()
print(d.age)  # 20  age属性不存在,所以调用__getattr__方法获取,并将attr赋值为age字符串
print(d.name)  # None

        对于d对象来说,age即不是对象属性也不是类属性,所以d.age时会执行__getattr__方法,同时将age传入__getattr__的attr参数中。

        对于d.name,由于__getattr__在attr为name时并没有返回值,所以默认的返回None。

        对于一个函数来说,它可以返回一个函数。所以__getattr__也可以返回一个函数或者一个lambda表达式。如下:

class Demo(object):
	def __getattr__(self,attr):
		if attr == 'say':
			return say

def say():
	print('hello')

d = Demo()
print(type(d.say))  # <type 'function'><type function="">
d.say()  # 在attr为say时,返回的是一个函数,使用()执行该函数</type>

        在d.say时,会调用__getattr__,同时将attr赋值为say,此时__getattr__返回的是一个函数,所以d.say指向的是一个函数,也就是倒数第二句输出的类型为function。再通过()执行该函数,就相当于直接执行say函数。

        __call__:直接将实例当方法调用时,会走该方法。如:

class Demo(object):

    def __call__(self, *args, **kwargs):
        return '__call__调用'

print(Demo()())  # __call__调用

        Demo()返回一个Demo实例,后面的()实例当方法调用,就相当于调用实例的__call__方法,故Demo()()返回的是__call__的返回值。

        结合__getattr__可以写出很有意思的效果:

class P1(object):

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

    def __getattr__(self, item):
        if item == 'age' or item == 'sex':
            return P1("%s/%s" % (self.name,item))
        if item == 'say':
            return self

    def __call__(self, *args, **kwargs):
        return P1("%s/%s" % (self.name, args[0]))

    def __str__(self):
        return self.name
    __repr__ = __str__

print(P1().sex.say('xxxxx').age)  # /sex/xxxxx/age

        首先P1(),会创建一个P1对象,该对象的name属性为''“,__init__方法中指定的。

        其次,获取sex属性,因为没有定义sex属性所以执行__getattr__方法,返回的就是另一个P1对象,它的name值是'/sex'

        再获取say,直接返回上一个P1对象,然后执行该对象,所以执行该对象的__call__方法,该方法返回的是P1对象,其name为/sex/xxxxx

        最后获取age属性,返回一个name为/sex/xxxxx/age的P1对象。

        使用print()方法输出对象,会调用对象的__str__方法,所以输出的就是对象的name属性。即:/sex/xxxxx/age。

枚举

方法一

        继承enum模块中的Enum即可。如下:

import enum


@enum.unique  # 保证各个枚举变量值不相同
class Demo(enum.Enum):
    MAN = 0  # MAN值被设置为1
    WOMEN = 3
    MIDDLE = 'renyao'

print(Demo.MAN)  # Demo.MAN
print(Demo['MAN'])  # Demo.MAN
print(Demo(3))  # Demo.WOMEN  这里的3是变量的值,不是下标
try:
    print(Demo(2))  # 这句会报错
except Exception as e:
    print(e)  # 2 is not a valid Demo
print(Demo('renyao'))  # Demo.MIDDLE  因为有变量值为renyao,所以可以取出来。

        取值方式一共有三种:类名点,按字典形式取,以及通过变量值取

        取对应变量的值,是在变量点value。如:Demo.MAN.value返回的是0。

方法二

        通过enum模块中Enum类创建一个枚举类。如:

d = enum.Enum('D', ('month', 'year', 'day'))
print(d(3))  # D.day
print(d.month)  # D.month
print(d['year'])  # D.year

        第一个参数相当于枚举类的类名,后面元组中是各个常量。d为枚举类的对象。

        与java不同的地方在于:枚举类的值从1开始。如:

import enum


d = enum.Enum('D', ('month', 'year', 'day'))
for name, member in d.__members__.items():
    print(name, member, member.value)  # month D.month 1
        循环时,取value值是从1开始的。






异常枚举是一种将异常型以枚举的形式进行定义的方法。在Java中,异常是通过抛出异常对象来进行处理的。而使用异常枚举可以将异常型进行分,使得代码更加清晰明了。 以下是一个简单的异常枚举的例子: ```java public enum MyExceptionType { NULL_POINTER_EXCEPTION, INDEX_OUT_OF_BOUNDS_EXCEPTION, ARITHMETIC_EXCEPTION } ``` 在上面的例子中,我们定义了三种异常型:空指针异常、数组下标越界异常、算术异常。接下来,我们可以在代码中使用这些异常型来抛出具体的异常对象: ```java public class MyExceptionExample { public static void main(String[] args) { int[] array = {1, 2, 3}; try { int num = array[4]; } catch (IndexOutOfBoundsException e) { throw new MyException(MyExceptionType.INDEX_OUT_OF_BOUNDS_EXCEPTION); } } } class MyException extends Exception { private MyExceptionType exceptionType; public MyException(MyExceptionType exceptionType) { this.exceptionType = exceptionType; } public MyExceptionType getExceptionType() { return exceptionType; } } ``` 在上面的代码中,我们尝试访问数组中的第5个元素,这会抛出一个IndexOutOfBoundsException异常。然后,我们将这个异常转化为我们自己定义的MyException异常,并且将具体的异常型设置为INDEX_OUT_OF_BOUNDS_EXCEPTION。 通过使用异常枚举,我们可以更加清晰地组织我们的异常型,并且在代码中使用这些异常型来抛出具体的异常对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值