1 新式类与旧式类

新式类拥有经典类的全部特性之外,还有一些新的特性,比如 __init__发生变化,新增了静态方法__new__,python3目前都采用新式类,新式类是广度优先,旧式类是深度优先

  1. #新式类
  2. class C(object):
  3. pass
  4. #经典类
  5. class B:
  6. pass
(1)内置的object对象

  1. 1. __new____init__方法
  2. 这两个方法是用来创建object的子类对象,静态方法__new__()用来创建类的实例,然后再调用
  3. __init__()来初始化实例。
  4. 2. __delattr__, __getattribute__, __setattr__方法
  5. 对象使用这些方法来处理属性的访问
  6. 3. __hash__, __repr__, __str__方法
  7. print(someobj)会调用someobj.__str__(), 如果__str__没有定义,则会调用someobj.__repr__(),
  8. __str__()和__repr__()的区别:
  9. 默认的实现是没有任何作用的
  10. __repr__的目标是对象信息唯一性
  11. __str__的目标是对象信息的可读性
  12. 容器对象的__str__一般使用的是对象元素的__repr__
  13. 如果重新定义了__repr__,而没有定义__str__,则默认调用__str__时,调用的是__repr__
  14. 也就是说好的编程习惯是每一个类都需要重写一个__repr__方法,用于提供对象的可读信息,
  15. 而重写__str__方法是可选的。实现__str__方法,一般是需要更加好看的打印效果,比如你要制作
  16. 一个报表的时候等。
(2)类的方法

静态方法

  1. 静态方法可以被类或者实例调用,它没有常规方法的行为(比如绑定,非绑定,默认的第一个self参数),当有一
  2. 堆函数仅仅是为了一个类写的时候,采用静态方法声明在类的内部,可以提供行为上的一致性。
  3. 使用装饰符@staticmethod进行创建

类方法

  1. 也是可以通过类和它的实例进行调用,不过它是有默认第一个参数,叫做是类对象,一般被
  2. 命名为cls,当然你也可以命名为其它名字,这样就你可以调用类对象的一些操作,
  3. 代码如下,使用装饰符@classmethod创建:

新式类(new-style-class)

__init__方法 : 类的初始化方法

__new__静态方法

新式类都有一个__new__的静态方法,它的原型是object.__new__(cls[, ...])

cls是一个类对象,当你调用C(*args, **kargs)来创建一个类C的实例时,python的内部调用是

C.__new__(C, *args, **kargs),然后返回值是类C的实例c,在确认

c是C的实例后,python再调用C.__init__(c, *args, **kargs)来初始化实例c。

所以调用一个实例c = C(2),实际执行的代码为:

  1. c = C.__new__(C, 2)
  2. if isinstance(c, C):
  3. C.__init__(c, 23)#__init__第一个参数要为实例对象
  4. class Singleton(object):
  5. _singletons = {}
  6. def __new__(cls):
  7. if not cls._singletons.has_key(cls): #若还没有任何实例
  8. cls._singletons[cls] = object.__new__(cls) #生成一个实例
  9. return cls._singletons[cls] #返回这个实例
  10. a = Singleton()
  11. b = Singleton()
  12. id(a) #35966666
  13. id(b) #35966666
  14. #注:单例模式 ,两个实例指向同一个内存地址
(3)新式类实例

新式类的实例也具有新的特性。比如它拥有Property功能,该功能会对属性的访问方式产生影响;还有__slots__新属性,该属性会对生成子类实例产生影响;还添加了一个新的方法__getattribute__,比原有的__getattr__更加通用。

__slots__属性

通常每一个实例x都会有一个__dict__属性,用来记录实例中所有的属性和方法,也是通过这个字典,

可以让实例绑定任意的属性。而__slots__属性作用就是,当类C有比较少的变量,而且拥有__slots__属性时,

类C的实例 就没有__dict__属性,而是把变量的值存在一个固定的地方。如果试图访问一个__slots__中没有

的属性,实例就会报错。这样操作有什么好处呢?__slots__属性虽然令实例失去了绑定任意属性的便利,

但是因为每一个实例没有__dict__属性,却能有效节省每一个实例的内存消耗,有利于生成小而精

干的实例。

定义__slots__属性

  1. class A(object):
  2. def __init__(self):
  3. self.x = 1
  4. self.y = 2
  5. __slots__ = ('x','y')
  6. a = A()
  7. a.z = 3
  8. a.u = 4 #都会报错,不能对实例新增属性,__dict__字典集没有任何改变
  9. class A(object):
  10. def __init__(self):
  11. self.x = 1
  12. self.y = 2
  13. a = A()
  14. a.x = 3 #不会报错,在__dict__字典字典集会新增'x'属性

使用时__slots__时需要注意的几点:

  1. 1. 当一个类的父类没有定义__slots__属性,父类中的__dict__属性总是可以访问到的,所以只在子
  2. 类中定义__slots__属性,而不在父类中定义是没有意义的。
  3. 2. 如果定义了__slots__属性,还是想在之后添加新的变量,就需要把'__dict__'字符串添加到__slots__
  4. 元组里。
  5. 3. 定义了__slots__属性,还会消失的一个属性是__weakref__,这样就不支持实例的weak reference
  6. 如果还是想用这个功能,同样,可以把'__weakref__'字符串添加到元组里。
  7. 4. __slots__功能是通过descriptor实现的,会为每一个变量创建一个descriptor
  8. 5. __slots__的功能只影响定义它的类,因此,子类需要重新定义__slots__才能有它的功能。
__getattribute__方法

对新式类的实例来说,所有属性和方法的访问操作都是通过__getattribute__完成,这是由object基类实现的。如果有特殊的要求,可以重载__getattribute__方法.

2 __init____new__区别

  1. __new__是一个静态方法,而__init__是一个实例方法.
  2. __new__方法会返回一个创建的实例,而__init__什么都不返回.
  3. 只有在__new__返回一个cls的实例时后面的__init__才能被调用.
  4. 当创建一个新实例时调用__new__,初始化一个实例时用__init__.

__metaclass__是创建类时起作用.所以我们可以分别使用__metaclass__,__new____init__来分别在类创建,实例创建和实例初始化的时候做一些操作

3 单例模式

​ 单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源,系统中存在多个该类的实例对象,而这样会严重浪费内存资源 如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

__new__()__init__()之前被调用,用于生成实例对象。利用这个方法和类的属性的特点可以实现设计模式的单例模式。单例模式是指创建唯一对象,单例模式设计的类只能实例一次

一般python中可以采用以下方法实现单例模式

  • 使用模块(import导入)
  • 使用 __new__
  • 使用装饰器(decorator)
  • 使用元类(metaclass)

(1)使用__new__方法

  1. class Singleton(object):
  2. def __new__(cls, *args, **kw):
  3. if not hasattr(cls, '_instance'): #如果该类是否含有实例
  4. orig = super(Singleton, cls)
  5. cls._instance = orig.__new__(cls, *args, **kw)
  6. return cls._instance
  7. class MyClass(Singleton):
  8. a = 1
  9. #如果 cls._instance 为 None 则创建实例,否则直接返回 cls._instance。

(2)共享属性(使用metaclass)

元类(metaclass)可以控制类的创建过程,它主要做三件事:

  • 拦截类的创建
  • 修改类的定义
  • 返回修改后的类

创建实例时把所有实例的__dict__指向同一个字典,这样它们具有相同的属性和方法.

  1. class Borg(object):
  2. _state = {}
  3. def __new__(cls, *args, **kw):
  4. ob = super(Borg, cls).__new__(cls, *args, **kw)
  5. ob.__dict__ = cls._state
  6. return ob
  7. class MyClass2(Borg):
  8. a = 1

(3) 装饰器版本

  1. def singleton(cls):
  2. instances = {}
  3. def getinstance(*args, **kw):
  4. if cls not in instances:
  5. instances[cls] = cls(*args, **kw)
  6. return instances[cls]
  7. return getinstance
  8. @singleton
  9. class MyClass:
  10. ...

(4) import 方法(使用模块)

作为python的模块是天然的单例模式

  1. # mysingleton.py
  2. class My_Singleton(object):
  3. def foo(self):
  4. pass
  5. my_singleton = My_Singleton()
  6. # to use
  7. from mysingleton import my_singleton #将类进行导入使用
  8. my_singleton.foo()

4 Python作用域

python的作用域分全局和局部,python变量的作用域分为以下四类:

L(local) 局部作用域

E(Enclosing) 闭包函数外的函数中

G(Global) 全局作用域

B(Built-in) 内建作用域

(1) 局部作用域

在了解局部作用域之前,先了解下块级作用域的概念

  1. #块级作用域
  2. if 1 == 1:
  3. name = "lol"
  4. print(name)
  5. for i in range(10):
  6. age = i
  7. print(age)
  8. #输出:
  9. C:/Users/L/PycharmProjects/s14/preview/Day8/作用域/test.py
  10. lol
  11. 9

可以发现python代码运行ok,为什么外部可以调用内部的变量呢? 因为在python中没有块级作用域的概念,代码块里的变量,外部可以调用,所以可运行成功, 也就是说,类似条件判断(if…..else)、循环语句(for x in data)、异常捕捉(try…catch)等的变量是可以全局使用的 .但是不区分作用域明显是不行的,因此python引入局部作用域

  1. #局部作用域
  2. def func():
  3. name = "lol"
  4. func() #调用函数
  5. print(name)
  6. #输出
  7. Traceback (most recent call last):
  8. File "C:/Users/L/PycharmProjects/s14/preview/Day8/作用域/test.py", line 23, in <module>
  9. print(name)
  10. NameError: name 'name' is not defined

即使执行了一下函数,name的作用域也只是在函数内部,外部依然无法进行调用 ,因此函数可以产生局部作用域,在python中模块(module),类(class)、函数(def、lambda)会产生新的作用域 .

(2) 作用域链

  1. #作用域链
  2. name = "张三"
  3. def func1():
  4. name = "李四"
  5. def func2():
  6. name = "王五"
  7. print(name)
  8. func2()
  9. func1()
  10. #输出
  11. "王五"

func1()调用函数执行变量赋值操作,当调用func2()时 , print(name)中name属性会先从局部作用域开始寻找,由内至外,最先找到的当然是 '王五'.Python中有作用域链,变量会由内到外找,先去自己作用域去找,自己没有再去上级去找,直到找不到报错 .

(3) 全局作用域与内建作用域

  1. x = int(2.9) # 内建作用域
  2. num = 0 # 全局作用域
  3. def outer():
  4. num2 = 1 # 闭包函数外的函数中
  5. def inner():
  6. num3 = 2 # 局部作用域

(4) global关键字

全局变量是指在函数外的变量,可以在程序全局使用,局部变量是指定义在函数内的变量,只能在函数内被声明使用若内部作用域的想要修改外部作用域的变量,就要使用global关键字

  1. a = 100
  2. def demo():
  3. global a
  4. a = 123
  5. print(a)
  6. demo()
  7. print(a)
  8. #运行结果是
  9. 123
  10. 123

本来运行结果应该是123,100,但是因为global声明a为全局作用域,因此在执行赋值后的a指向123,因此两次打印的都是123.

总结下:

​ Python 中,一个变量的作用域总是由在代码中被赋值的地方所决定的。当 Python 遇到一个变量的话他会按照这样的顺序进行搜索:本地作用域(Local)→当前作用域被嵌入的本地作用域(Enclosing locals)→全局/模块作用域(Global)→内置作用域(Built-in)

Python新式类 单例模式与作用域(四)的更多相关文章

  1. Python新式类和经典类的区别

    @Python新式类和经典类的区别 class ClassicClass(): pass class NewStyleClass(object): pass x1 = ClassicClass() x ...

  2. Python新式类与经典类的区别

    1.新式类与经典类 在Python 2及以前的版本中,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位置),都属于“新式类”,都会获得所有“新式类”的特性:反之,即不由任意内置类型派生出的类 ...

  3. Python新式类继承的C3算法

    在Python的新式类中,方法解析顺序并非是广度优先的算法,而是采用C3算法,只是在某些情况下,C3算法的结果恰巧符合广度优先算法的结果. 可以通过代码来验证下: class NewStyleClas ...

  4. python新式类与旧式类

    python2.X是经典类[旧式类]: 是以深度优先[] 但是在Python2.x中,默认都是经典类,只有显式继承了object才是新式类,即:class Person(object):pass 新式 ...

  5. Python 新式类与经典类

    新式类,经典类 查询匹配 广度查询 横着对每个类进行查询 深度查询 无视平级类,直接寻找下级类 #python 3.0 #新式类 广度查询 #经典类 广度查询 #python 2.0 #新式类 广度查 ...

  6. 【Python】Python 新式类介绍

    本文转载自:kaka_ace's blog 我们使用 Python 开发时, 会遇到 class A 和 class A(object) 的写法, 这在 Python2 里是有概念上和功能上的区别, ...

  7. Python新式类与经典类(旧式类)的区别

    看写poc的时候看到的,思考了半天,现在解决了 转载自http://blog.csdn.net/zimou5581/article/details/53053775 Python中类分两种:旧式类和新 ...

  8. Python新式类和旧式类的区别

    新式类是为了统一**而在2.2中开始引入的. 代码讲解 上面的例子比较明白的说明了问题. B是定义的新式类.那么输入b的时候,不论是type(b),还是b.__class__都是输出的<clas ...

  9. python 新式类的 __getattribute__

    这个方法定义在object中,所以所有的新式类都继承有该方法,所有的新式类的实例在获取属性value的时候都会调用该方法,为了验证这一结论,我们重写一下该方法: class C(object): a ...

随机推荐

  1. C# .Net正则表达式去除HTML标记和空格

    C# .Net正则表达式去除HTML标记和空格 http://www.cnblogs.com/deerchao/archive/2006/08/24/zhengzhe30fengzhongjiaoch ...

  2. linux 配置环境变量

    配置全局 环境变量 查看环境变量 #这个变量赋值操作,只是临时生效,需要写入到文件,永久生效 echo $PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/u ...

  3. Pseudoprime numbers---费马小定理

    Pseudoprime numbers Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13406   Accepted: 5 ...

  4. Trie - 20181113

    442. Implement Trie (Prefix Tree) class TrieNode { public boolean isWord; public TrieNode[] children ...

  5. superobject 设定排序方式

    (* * Super Object Toolkit * * Usage allowed under the restrictions of the Lesser GNU General Public ...

  6. UML-2-迭代、进化和敏捷

    1.UP UP:Unified Process,统一过程.RUP:Rational Unified Process,Rational 公司制定的UP,是对UP的精细化. UP的过程: 初始 不是需求, ...

  7. 7.使用jenkins+marathon+docker完成自动化部署

    1.前置条件 1)Docker开启TCP端口,CloudBees Docker Build and Publish plugin插件会向目标主机docker生成docker镜像 开启docker ap ...

  8. 正则提取字符串IP地址,返回IP列表

    public class Main { public static void main(String args[]) { String str = "10.11.90.1 asedfa 1. ...

  9. like模糊查询%注入问题

    android like 全局模糊查找文件命名 通过条件通过 like %search% 如果查找的关键字是% 那么就成了 like %%% 就会查找出所有的文件 解决办法是先把正则里面的匹配符 替换 ...

  10. javascript中for in与in的用法

    1.For...In 声明用于对数组或者对象的属性进行循环/迭代操作. 对于数组 ,迭代出来的是数组元 素,对于对象 ,迭代出来的是对象的属性: var x var mycars = new Arra ...