天才教育网合作机构 > 培训机构 >

全国python学习中心

欢迎您!
朋友圈

400-850-8622

全国统一学习专线 9:00-21:00

位置:培训资讯 > python元编程,不要轻易使用元编程

python元编程,不要轻易使用元编程

日期:2021-07-26 12:56:41     浏览:315    来源:全国python学习中心
核心提示:不管你是待业还是失业,在这个被互联网围绕的时代里,选择python元编程,就多了一项技能,还怕找不到工作?,还怕不好找工作?小编就来告诉你这个专业的优势到底体现在哪里:Python元编程:控制你想控制的一切,不要

不管你是待业还是失业,在这个被互联网围绕的时代里,选择python元编程,就多了一项技能,还怕找不到工作?,还怕不好找工作?小编就来告诉你这个专业的优势到底体现在哪里:Python元编程:控制你想控制的一切,不要轻易使用元编程,学习python编程需要安装哪些软件???。

1.Python元编程:控制你想控制的一切

很多人不理解“元编程”是个什么东西,关于它也没有一个十分准确的定义。这篇文章要说的是Python里的元编程,实际上也不一定就真的符合“元编程”的定义。只不过我无法找到一个更准确的名字来代表这篇文章的主题,所以就借了这么一个名号。副标题是控制你想控制的一切,实际上这篇文章讲的都是一个东西,利用Python提供给我们的特性,尽可能的使代码优雅简洁。具体而言,通过编程的方法,在更高的抽象层次上对一种层次的抽象的特性进行修改。首先说,Python中一切皆对象,老生常谈。还有,Python提供了许多特殊方法、元类等等这样的“元编程”机制。像给对象动态添加属性方法之类的,在Python中根本谈不上是“元编程”,但在某些静态语言中却是需要一定技巧的东西。我们来谈些Python程序员也容易被搞糊涂的东西。我们先来把对象分分层次,通常我们知道一个对象有它的类型,老早以前Python就将类型也实现为对象。这样我们就有了实例对象和类对象。这是两个层次。稍有基础的读者就会知道还有元类这个东西的存在,简言之,元类就是“类”的“类”,也就是比类更高层次的东西。这又有了一个层次。还有吗? vs RunTime如果我们换个角度,不用非得和之前的三个层次使用同样的标准。我们再来区分两个东西:和RunTime,它们之间也并非界限分明,顾名思义,就是两个时刻,导入时和运行时。当一个模块被导入时,会发生什么?在全局作用域的语句(非定义性语句)被执行。函数定义呢?一个函数对象被创建,但其中的代码不会被执行。类定义呢?一个类对象被创建,类定义域的代码被执行,类的方法中的代码自然也不会被执行。执行时呢?函数和方法中的代码会被执行。当然你要先调用它们。元类所以我们可以说元类和类是属于的,import一个模块之后,它们就会被创建。实例对象属于RunTime,单import是不会创建实例对象的。不过话不能说的太绝对,因为如果你要是在模块作用域实例化类,实例对象也是会被创建的。只不过我们通常把它们写在函数里面,所以这样划分。如果你想控制产生的实例对象的特性该怎么做?太简单了,在类定义中重写__init__方法。那么我们要控制类的一些性质呢?有这种需求吗?当然有!经典的单例模式,大家都知道有很多种实现方式。要求就是,一个类只能有一个实例。最简单的实现方法是这样的class _Spam: def __init__(self): print("Spam!!!") _spam_singleton =None def Spam(): global _spam_singleton if _spam_singleton is not None: return _spam_singleton else: _spam_singleton = _Spam() return _spam_singleton工厂模式,不太优雅。我们再来审视一下需求,要一个类只能有一个实例。我们在类中定义的方法都是实例对象的行为,那么要想改变类的行为,就需要更高层次的东西。元类在这个时候登场在合适不过了。前面说过,元类是类的类。也就是说,元类的__init__方法就是类的初始化方法。 我们知道还有__call__这个东西,它能让实例像函数那样被调用,那么元类的这个方法就是类在被实例化时调用的方法。代码就可以写出来了:class Singleton(type): def __init__(self, *args, **kwargs): self._instance = None super().__init__(*args, **kwargs) def __call__(self, *args, **kwargs): if self._instance is None: self._instance = super().__call__(*args, **kwargs) return self._instance else: return self._instance class Spam(metaclass=Singleton): def __init__(self): print("Spam!!!")主要有两个地方和一般的类定义不同,一是Singleton的基类是type,一是Spam定义的地方有一个metaclass=Singleton。type是什么?它是object的子类,object是它的实例。也就是说,type是所有类的类,也就是最基本的元类,它规定了一些所有类在产生时需要的一些操作。所以我们的自定义元类需要子类化type。同时type也是一个对象,所以它又是object的子类。有点不太好理解,大概知道就可以了。装饰器我们再来说说装饰器。大多数人认为装饰器是Python里面最难理解的概念之一。其实它不过就是一个语法糖,理解了函数也是对象之后。就可以很轻易的写出自己的装饰器了。from functools import wraps def print_result(func): @wraps(func) def wrappper(*args, **kwargs): result = func(*args, **kwargs) print(result) return result return wrappper @print_result def add(x, y): return x + y #相当于: #add = print_result(add) add(1, 3)这里我们还用到了一个装饰器@wraps,它是用来让我们返回的内部函数wrapper和原来的函数拥有相同的函数签名的,基本上我们在写装饰器时都要加上它。我在注释里写了,@decorator这样的形式等价于func=decorator(func),理解了这一点,我们就可以写出更多种类的装饰器。比如类装饰器,以及将装饰器写成一个类。def attr_upper(cls): for attrname,value in cls.__dict__.items(): if (value,str): if not value.('__'): setattr(cls,attrname,bytes.decode(str.encode(value).upper())) return cls @attr_upper class Person: sex = 'man' print(Person.sex) # MAN注意普通的装饰器和类装饰器实现的不同点。对数据的抽象--描述符如果我们想让某一些类拥有某些相同的特性,或者说可以实现在类定义对其的控制,我们可以自定义一个元类,然后让它成为这些类的元类。如果我们想让某一些函数拥有某些相同的功能,又不想把代码复制粘贴一遍,我们可以定义一个装饰器。那么,假如我们想让实例的属性拥有某些共同的特点呢?有人可能会说可以用property,当然可以。但是这些逻辑必须在每个类定义的时候都写一遍。如果我们想让这些类的实例的某些属性都有相同的特点的话,就可以自定义一个描述符类。关于描述符,这篇文章 : def __init__(self, _type): self._type = _type def __get__(self, instance, cls): if instance is None: return self else: return getattr(instance, self.name) def __set_name__(self, cls, name): self.name = name def __set__(self, instance, value): if not (value, self._type): raise TypeError('Expected' + str(self._type)) instance.__dict__[self.name] = value class Person: age = (int) name = (str) def __init__(self, age, name): self.age = age self.name = name jack = Person(15, 'Jack') jack.age = '15' # 会报错 在这里面有几个角色,是一个描述符类,Person的属性是描述符类的实例,看似描述符是作为Person,也就是类的属性而不是实例属性存在的。但实际上,一旦Person的实例访问了同名的属性,描述符就会起作用。需要注意的是,在Python3.5及之前的版本中,是没有__set_name__这个特殊方法的,这意味着如果你想要知道在类定义中描述符被起了一个什么样的名字,是需要在描述符实例化时显式传递给它的,也就是需要多一个参数。不过在Python3.6中,这个问题得到了解决,只需要在描述符类定义中重写__set_name__这个方法就好了。还需要注意的是__get__的写法,基本上对instance的判断是必需的,不然会报错。原因也不难理解,就不细说了。控制子类的创建——代替元类的方法在Python3.6中,我们可以通过实现__init_subclass__特殊方法,来自定义子类的创建,这样我们就可以在某些情况下摆脱元类这个讨厌的东西。class : = [] def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) cls..append(cls) class Plugin1(): pass class Plugin2(): pass小结诸如元类等元编程对于大多数人来说有些晦涩难懂,大多数时候也无需用到它们。但是大多数框架背后的实现都使用到了这些技巧,这样才能让使用者写出来的代码简洁易懂。如果你想更深入的了解这些技巧,可以参看一些书籍例如《Fluent Python》、《Python Cookbook》(这篇文章有的内容就是参考了它们),或者看官方文档中的某些章节例如上文说的描述符HowTo,还有Data Model一节等等。或者直接看Python的源码,包括用Python写的以及CPython的源码。记住,只有在充分理解了它们之后再去使用,也不要是个地方就想着使用这些技巧。

2.不要轻易使用元编程

本文转载自: Common Lisp 里的 loop 宏就。一方面,它体现了宏的强大;另一方面,它展现了宏能给我们带来的复杂。熟悉 C/Java 语言都知道循环是语言本身提供的关键字,一般是 for。但 Lisp 语言特别精简,它认为循环只是递归的一个特殊形式,语言本身也不包含任何的循环关键字。于是有人用宏实现了 loop ,它让我们能以近乎英语的方式在 Lisp 里写循环语句,这里从 这里 摘抄一个例子:(loop for x in '(a b c d e) for y from 1 if (> y 1) do (format t ", ~A" x) else do (format t "~A" x) )你不需要了解这段代码的含义,重要的是了解像 for .. in .., if ... do ... else ... do 这样的语法并不是 Lisp 提供的,而是 loop 宏实现的,这些语法离开了 loop 也就不再合法。我们看到 loop 宏让我们能在 Lisp 语言不支持的情况下享受到近乎现代语言中才包含的 for ... in ... 语法。要知道在 Java 中有两种 for 语句:for (int i=0; i < array.length; i++) { System.out.println("Element: " + array[i]); } for (String element : array) { System.out.println("Element: " + element); }而第二种直到 JDK 1.5 才加入。在这之前,广大的 Java 程序员即使已经认识到了第二种写法的优越性,却也只能无奈等到语言支持才行。而 Lisp 程序员很快就能通过宏来实现自己理想中的语法。然而光明与黑暗共生,宏给我们带来极大自由的同时,也意味着分裂。每个程序员心中理想的语法各不相同,这就意味着一千个程序员会有一千种语法。在 Lisp 中宏是非常容易编写的(不代表容易正确编写),意味着真的会存在一千种语法,大家谁也不服谁,因此造成分裂;但在 C/Java 中,没有宏的支持,虽然有一千种想法,但大家都写不出编译器,于是只能集中讨论,统一语法了,再靠大牛们实现了。而现实就是如此,Common Lisp 尝试标准化 Lisp,但依旧有人不认同这种理念,例如 Scheme,Common Lisp 标准化的 loop 宏在 Scheme 中就被抛弃了。照进现实前车之鉴,后事之师。Lisp 强大的功能,反面导致了语言的分裂,最终使 Lisp 也慢慢退出历史舞台(主流地位),这也被称为 The Lisp Curse。而现实中我们也常常会被元编程的强大和便捷诱惑,我认为使用元编程之前*考虑会不会造成更多的分裂。最基本的就是不应该自己造语法(DSL)。当然,我的出发点是多人团队,较大的项目,考虑的是整体的发展。如果是个人学习,或者小团队等,元编程或许能成为你出众的秘密武器。但大的项目讲求的是合作,DSL 造成的分裂实在是得不偿失,尤其是作者离开后,维护的工作经常后继无人。近两年接触到的 rust 也是提供了宏的支持,虽然不像 Lisp 宏一样容易编写,但从功能的角度上依旧特别强大,而且模板宏写起来也很容易,于是有人想写一个类似 Python 的 dict 语法:let x = dict!( "hello" => "world" ,"hello2" => "world2" );但我个人并不喜欢这种语法,我认为 Clojure 似的语法更简洁 dict!("hello": "world")。那在团队里引入这两个宏就会引起代码的分裂,后来人在看代码时就会很困惑。不利于团队的建设。*分享在 知乎 上看到的引用:Hygienic Macros and Compile-Time : A first-class macro system, or support for compile-time code execution in general, is something we may consider in future releases. We don’t want the existence of a macro system to be a that reduces the incentive for making the core language great. 表示不希望用宏来解决语言本身的缺陷。而我的理解是当我们希望用宏(或其它元编程手段)时,很可能是我们使用的语言缺少了某些特性,例如 Java 的 lombok 提供的 @Getter/@Setter 等注解,就是因为 Java 没有相应的语言层面的支持,看看 Kotlin 的支持你就会明白的。但即便有了宏(或元编程)的支持,你有信心能做出让整个团队都信服的设计吗?如果没有,*还是慎重为之。写在*虽然是吐糟,但这篇之间重写了三次。想表达的内容很多,最终还是把其它的东西删去, Lisp curse 还是我想真正表达的东西吧,其它的基础知识,有缘人自然会从其它地方学会。年轻人容易崇拜力量,我们也别忘了阳光还有影子。

3.学习python编程需要安装哪些软件?

你好,需要安装Python平台和一个顺手的代码编辑器,Python平台2.6、2.7、3.0+的版本皆可,如果你在windows下代码编辑器可以使用、PythonWin、自带的IDLE也行,但智能感不够强,在Linux下,可以考虑Vim,如果需要,请追问或私信留下邮箱,我将所需的工具和一些教材发给你。

就拿大数据说话,优势一目了然,从事IT行业,打开IT行业的新大门,找到适合自己的培训机构,进行专业和系统的学习。

本文由 全国python学习中心 整理发布。更多培训课程,学习资讯,课程优惠,课程开班,学校地址等学校信息,可以留下你的联系方式,让课程老师跟你详细解答:
咨询电话:400-850-8622

如果本页不是您要找的课程,您也可以百度查找一下: