python学习——基础(七)

在Python中,一个.py文件就称之为一个模块(Module)。

使用模块有什么好处?

最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。

模块别名:

try:
    import cStringIO as StringIO
except ImportError: # 导入失败会捕获到ImportError
    import StringIO

面向对象的访问限制:

在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑。

如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问

class Student(object):
    def __init__(self, name):
        self.__name = name

    def getName(self):
        return '实例变量:'+self.__name

stu1 = Student('syc')
print stu1.getName() # 实例变量:syc
print stu1.__name # AttributeError: type object 'Student' has no attribute '__name'


需要注意的是,在Python中,变量名类似__xxx__ 的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__ __score__ 这样的变量名。

有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。

继承:

在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。

class Animal(object):
    def run(self):
        print 'animail is running'

    def eat(self):
        print 'animail is eating'

class Horse(Animal):

    def run(self):
        print 'horse is running'
        Animal.eat(self) # 子类中调用父类的方法

hs = Horse()
hs.run()
print type(hs)

结果:
horse is running
animail is eating
<class '__main__.Horse'>


如果要获得一个对象的所有属性和方法,可以使用dir()函数:

['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'eat', 'run']


仅仅把属性和方法列出来是不够的,配合getattr() setattr() 以及hasattr() ,我们可以直接操作一个对象的状态

class Horse(object):
    name = 'horse'
    def run(self):
        print 'horse is running'
        Animal.eat(self) # 子类中调用父类的方法

hs = Horse()
print hasattr(hs, 'name') # 判断hs对象是否含有name属性,同样也可以进行方法的判断
setattr(hs, 'age', '18') # 增加的是实例变量,不能为对象设置新的方法
print getattr(hs, 'age') # 得到hs的age值,同时可以得到方法的变量


使用__slots__

正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性

class Student(object):
    name = 'syc'

    def drink(self):
        print 'student is drunking'

stu = Student()
stu.age = 18 #给实例增加属性
print stu.age
Student.age =19 # 给类添加属性
print Student.age

def eat(self):
    print 'student is eating'

from types import MethodType
stu.eat = MethodType(eat, stu, Student) # 给Student的实例stu添加方法
stu.eat()

stu2 = Student()
# print stu2.eat() # AttributeError: 'Student' object has no attribute 'eat'

Student.eat = MethodType(eat, None, Student) # 给类Student添加方法
stu2.eat()


   但是,如果我们想要限制class的属性怎么办? 为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__ 变量,来限制该class能添加的属性和方法
class Student(object):
    __slots__ = ('name', 'age', 'eat')
    name = 'syc'

    def drink(self):
        print 'student is drunking'
stu = Student()
stu.address = 'fuzhou'

结果:AttributeError: 'Student' object has no attribute 'address'

方法也是同样的;

使用__slots__要注意,__slots__定义的属性仅对当前类起作用,对继承的子类是不起作用的

class Student(object):
    __slots__ = ('name', 'age', 'eat')
    name = 'syc'

    def drink(self):
        print 'student is drunking'

class SubStudent(Student):
    pass

substu = SubStudent()
substu.address = 'fuzhou'
print substu.address  # fuzhou


使用@property

@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。

class Student(object):

    @property
    def aname(self):  # 第一处
        return self.__name

    @aname.setter # 第二处
    def name(self, name): # 第三处
        # if name == 'syc':
        #     raise TypeError('name不能为syc')
        self.__name = name


stu = Student()
stu.name = 'syc' # 第四处
print stu.name # 第五处


第一处和第二处的name必须相同,第三处、第四处、第五处必须相同

新增的属性为name,不是__name

多重继承:

Mixin:在设计类的继承关系时,通常,主线都是单一继承下来的,如果需要“混入”额外的功能,通过多重继承就可以实现,这种设计通常称之为Mixin;python中的多重继承类似于java中的类组合;

在多重继承中,最大的问题就是当继承的父类中有同名的方法,这时的优先级问题:

class Grandfa(object):
    def hair(self):
        print 'no hair'

class Father(Grandfa):
    pass

class Mom(object):
    def hair(self):
        print 'hair'

class Tom(Father,Mom):
    pass

tom = Tom()
tom.hair()  # no hair 深度优先


从例子可以看出,遵从的是深度优先的准则;


定制类:

通过特殊变量,可以为我们定制类,如:__slots__,__len__,__str__等

__str__:

class Student(object):
    pass
    # def __str__(self):
    #     return 'a student instance'

stu = Student()
print stu # <__main__.Student object at 0x02634B90>

class Student(object):
    # pass
    def __str__(self):
        return 'a student instance'

stu = Student()
print stu # a student instance


还有一个类似的__repr__; 两者的区别是__str__() 返回用户看到的字符串,而__repr__() 返回程序开发者看到的字符串,也就是说,__repr__() 是为调试服务的。


__iter__:

判断对象是否可以进行迭代:

class Student(object):
    pass

from collections import Iterable
print isinstance(stu,Iterable) # False


如果需要使对象能够迭代,可以在类中定义__iter__方法:


class Student(object):

    def __iter__(self):
        return self

    def next(self):
        self.a, self.b = self.b, self.a + self.b
        if self.b >100:
            raise StopIteration()
        return self.b

stu = Student()

from collections import Iterable
print isinstance(stu,Iterable) # True
stu.a, stu.b = 1,2
print [x for x in stu] # [3, 5, 8, 13, 21, 34, 55, 89]


Python的for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。


__getitem__

虽然能作用于for循环

class Student(object):

    def __getitem__(self, n):
        for x in range(n):
            self.a, self.b = self.b, self.a + self.b
        return self.b

stu = Student()

from collections import Iterable
print isinstance(stu,Iterable) # False
stu.a, stu.b = 1,2
print stu[1] # [3, 5, 8, 13, 21, 34, 55, 89]



,但是不能像list按照下标取出元素,需要实现__getitem__方法:

__getattr__

通过__getattr__动态的定义类的属性和方法;

class Student(object):
    def __init__(self, name):
        self.name = name

    def __getattr__(self, item):
        if item == 'score': # 自动添加属性
            return 99

        if item =='getSocre': # 自动添加方法
            return lambda :self.score * self.score

stu = Student('syc')
print stu.socre # None ==>当类定义了__getattr__时,即使没有定义socre,也不会报错:AttributeError: 'Student' object has no attribute 'socre'
print stu.score # 99
print stu.getSocre() # 9801



class Student(object):

    def __init__(self, path=''):
        self.__path = path
    def __getattr__(self, item):
        if item == "users":
            return lambda user: Student("%s/users/:%s" % (self.__path, user))
        else:
            return Student("%s/%s" % (self.__path, item))

    def __str__(self):
        return self.__path


print Student().users('syc').repos # /users/:syc/repos



或者:

class Student(object):

    def __init__(self, path=''):
        self.__path = path
    def __getattr__(self, item):
        return Student("%s/%s" % (self.__path, item))

    def __str__(self):
        return self.__path

    def __call__(self, name):
        return Student("%s/:%s" % (self.__path, name))


print Student().users('syc').repos # /users/:syc/repos




__call__

一个对象实例可以有自己的属性和方法,

当我们调用实例方法时,我们用instance.method()来调用。能不能直接在实例本身上调用呢?类似instance()?在Python中,答案是肯定的。

任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用。请看示例:

class Student(object):
    def __init__(self, name):
        self.name = name

    def __call__(self):
        print('My name is %s.' % self.name)

s = Student('syc')
s() # My name is syc.



__call__() 还可以定义参数。对实例进行直接调用就好比对一个函数进行调用一样,所以你完全可以把对象看成函数,把函数看成对象,因为这两者之间本来就没啥根本的区别。

那么,怎么判断一个变量是对象还是函数呢?其实,更多的时候,我们需要判断一个对象是否能被调用,能被调用的对象就是一个Callable对象,比如函数和我们上面定义的带有__call()__的类实例:

class Student(object):
    def __init__(self, name):
        self.name = name

    def __call__(self):
        print('My name is %s.' % self.name)

s = Student('syc')
print callable(s) # True
print callable([1, 2, 3]) # False
print callable('ABC') # False
print callable(None) # False



通过callable() 函数,我们就可以判断一个对象是否是“可调用”对象。

使用元类:

创建类有两种方法:自定义:class XXX,type(ClassName, parentClass, dict{fun,property})

def fn(self, name):
    print 'Hello %s'% name
Hello = type('Hello', (object,), dict(hello=fn))
Hello().hello('world') # Hello world



要创建一个class对象,type()函数依次传入3个参数:

  1. class的名称;
  2. 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
  3. class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。
通过type() 函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type() 函数创建出class。

转载于:https://my.oschina.net/u/257801/blog/521092

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值