[python] Pythonic语法笔记

Pythonic语法笔记

__new__

在类实例化之前执行的,也就是在init之前执行,可以为这个类写操作。接受的参数不是self而是cls。只有在new方法里返回类才会执行init操作,需要返回父类的new。

class A(object):
	def __new__(cls,name):
        print("cls name:{}".format(name))
        return super().__new__(cls)
    def __init__(self,name):
        print("self name:{}".format(name))
if __name__ == "__main__":
    a = A("ok")
    
'''
cls name:ok
self name:ok
'''

getattr和getattribute

在查找不到属性的时候会调用__getattr__

class A():
    def __init__(self,name):
        self.info = {
            "Name":name
        }
    def __getattr__(self,item):
        return self.info[item]
if __name__ == '__main__':
    a = A('aa')
    print(a['Name'])

__getattribute__管理的是整个类的属性访问,一般不重写,getattr实际上会在getattribute中被调用,重写了之后可能会导致整个类的崩溃,所以一般不重写。getattribute是无条件调用的,无论是否存在属性,都会被调用。

type

type是用来创建类的类,是元类的一种,所以我们也可以通过type函数来动态创建一个类。

type函数有三个参数,第一个是类名,第二个是基类名,第三个是属性

def say():
    print("something")
User = type('user',(),{'name':'xueaoru',"say":say})
user = User()
print(user.name)
user.say()

'''
xueaoru
something
'''


实际使用过程中一般不用type直接创建类,而是使用元类,定义metaclass去创建。

我们知道new方法是可以控制在类实例化的过程,而使用元类可以使这个过程分离,单独创建一个类去管理该类的实例化过程,这样代码分离性比较好,所以称之为metaclass。

class MetaClass(type):
    def __new__(cls,*args,**kwargs):
        return super().__new__(cls,*args,**kwargs)

class Base(metaclass=MetaClass):
    def __init__(self, *args, **kwargs):
        return super().__init__(*args, **kwargs)


class User(Base):
    def __init__(self, name,*args, **kwargs):
        self.name = name
        return super().__init__(*args, **kwargs)
    def __str__(self):
        return "user"

if __name__ == "__main__":
    user = User("aoru")
    print(user)

先定义了一个MetaClass,继承了type,这里其实和直接是type区别不大,因为直接返回super,也就是让实例化的过程交给父类来做,也就是type,然后定义base类,base类的metaclass是MetaClass,所以用MetaClass来做实例化的过程,User由于继承自base类,所以查找metaclass的时候自己没有,就调用基类的metaclass。

属性描述符

实际上是一个用来描述属性的类,需要定义其get方法或者是set方法,可以用来做类型的检查。

# 属性描述符类
class IntField():
    def __set__(self,instance,value):
        if not isinstance(value,int):
            raise ValueError("int value err")
class User():
    age = IntField()
if __name__ == "__main__":
    user = User()
    user.age = '2'
    
'''
Traceback (most recent call last):
  File "/media/xueaoru/其他/ML/推荐系统入门/my_attr_desc_demo.py", line 9, in <module>
    user.age = '2'
  File "/media/xueaoru/其他/ML/推荐系统入门/my_attr_desc_demo.py", line 4, in __set__
    raise ValueError("int value err")
ValueError: int value err
'''
    

数据查找过程,先查找类中的数据描述符对象,然后查找对象中的属性,然后查找类中或者基类中的属性,而在类中或者基类中查找的时候属性描述符优先。最后如果查找不到,就会调用类的getattr函数,没有就抛出异常。

迭代器

基于两个语法,next返回下一个迭代对象,__iter__返回被迭代的对象本身。

class Myobject():
    def __init__(self,step):
        self.step = step
    def next(self):
        if self.step == 0:
            raise StopIteration
        self.step-=1
        return self.step
    def __iter__(self):
        return self

则Myobject对象可被迭代。

与生成器的不同

生成器是使用了yield函数的,返回迭代器的函数,只能用于迭代操作。每次遇到yield时,函数会暂停病保存当前所有的运行信息,返回yield值,病在下一次执行next方法时从当前位置继续执行。调用一个生成器函数,返回的是一个迭代器对象。我们用的比较多的生成器是列表生成器,一个简单的生成器的例子:

def fib(n):
    a,b,cnt = 1,1,0
    while True:
        if cnt > n:
            return
        yield a
        a,b,cnt = b,a+b,cnt+1
f = fib(10)
for ff in f:
    print(ff)
    
'''
1
1
2
3
5
8
13
21
34
55
89
'''
posted @ 2019-06-27 12:01  aoru45  阅读(227)  评论(0编辑  收藏  举报