赞
踩
目录
1、Python的函数参数传递:看两个如下例子,分析运行结果
5、python是用C语言写成的,根据名字空间特性,以下代码经过python编译器编译后,一共得到()个PyCodeObject对象。
21、python函数式编程,例如filter、map、reduce
- # 代码1
- a=1
- def fun(a):
- a=2
- fun(a)
- print(a) #1
-
- # 代码2
- a=[]
- def fun(a):
- a.append(1)
- fun(a)
- print(a). #[1]
分析:
在Python中,分为两种对象,一个是可更改的(例如:列表、字典),一个是不可更改的(例如:字符串、数字、元组)。
第一个例子:当一个引用传递给函数的时候,函数自动复制一份引用,这个函数里的引用和外边的引用就没有关系了。而且指向的是一个不可变对象。
第二个例子:函数内的引用指向的是可变对象,对它的操作就和定位了指针地址一样,在内存里进行修改。
Python参数传递机制包括值传递(int、float数据类型)、引用传递(列表、字典等数据类型)、关键字传递(def f(a=1,b=2))形参制定实参调用,包裹形式传递(*agr,**agrs元组和字典)
python的函数传参方式使用引用传递的方式:就是把实参的地址传递给形参,执行期间实参和形参其实是共同使用一个存储单元的,被调用的函数对形参的任何操作都等同于对实参的操作,所以实参会随着形参的变化而改变。
借鉴:python中元类的使用,该怎么理解呢? - 楚阳的回答 - 知乎 https://www.zhihu.com/question/325646241/answer/721870925
所谓元类,就是类的类。对象是类实例生成的,类是元类生成的。
先说一下说Python的__new__()方法:
-
- class Person(object):
-
- def __new__(cls, name, age):
- print('I am __new__')
- res = super(Person, cls).__new__(cls)
-
- return res
-
- def __init__(self, name, age):
- self.name = name
- self.age = age
- print('__init__',name,age)
-
- def print_name(self):
- print('__init__ 获取class中的变量', self.name,self.age)
-
-
- p = Person('aaaaa',12)
- p.name = 'eric'
- p.age = 25
- p.print_name()
首先执行使用name和age参数来执行Person类的__new__方法。这个__new__方法返回Person类的一个实例。也就是说在类被实例化之前提供给你一个自定义这些类的实例化过程的途径,返回一个实例化对象。
python中的type()函数,它有两种方法:
测试对象的类型
- >>> print(type(1))
- <class 'int'>
- >>> print(type('1'))
- <class 'str'>
动态创建类——type(类名,父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
理解python metaclass_风-四方的博客-CSDN博客_metaclass
- >>> mc = type('MyClass',(),{})
- >>> print(mc)
- <class '__main__.MyClass'>
- >>> print(mc())
- <__main__.MyClass object at 0x0000000002EA8358>
-
__metaclass__就是python中的元类。元类的作用就是生成类,举个例子:
- class ListMetaclass(type):
- def __new__(cls, name, bases, attrs):
- attrs['add'] = lambda self, value: self.append(value) # 在MyList中添加了一个add方法
- return type.__new__(cls, 'name', bases, attrs)
-
-
- class MyList(list):
- __metaclass__ = ListMetaclass # 指示使用ListMetaclass来定制类
-
-
- a = MyList([1,2,3,4])
- print(type(a))
当我们定义MyClass
时,Python做了如下的操作:
在MyClass
中查找是否有__metaclas__
这个属性?如果有,Python会在内存中通过__metaclass__
后自定义的类或者函数(本文中用的是ListMetaclass
)创建一个名字为MyClass
的类对象(我说的是类对象,请紧跟我的思路)。
如果Python没有找到__metaclass__
,它会继续在父类中寻找__metaclass__
属性,并尝试做和前面同样的操作。如果Python在任何父类中都找不到__metaclass__
,它就会在模块层次中去寻找__metaclass__
,并尝试做同样的操作。如果还是找不到__metaclass__
Python就会用内置的type来创建这个类对象。
现在的问题就是,你可以在__metaclass__
中放置些什么代码呢?
答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者type的子类都可以。
什么是僵尸进程?
子进程结束后而父进程并没有结束,这时候子进程占有的资源(打开的文件、占用的内存)会被CPU回收,但子进程的信息(jinchengPID,运行时间,退出状态等)会被保留,子进程编程僵尸进程。
僵尸进程的危害:
当僵尸进程大量积累的时候会占用大量的PID号,但是进程号是有限的,大量积累的PID号会影响新的子进程生成。
如何结束这个僵尸进程?
- import time, os
- from multiprocessing import Process
-
-
- def run():
- print(f"子:{os.getpid()}")
-
-
- if __name__ == '__main__':
- p = Process(target=run)
- p.start()
- # p.join() 如果执行回收 就不会有这个僵尸
- print(f"主:{os.getpid()}")
- time.sleep(10000)
-
- """
- # 返回:
- 主:3545
- 子:3546
- 终端:
- pa aux | grep "3690"
- win 3690 0.0 0.0 0 0 ?? Z 10:49上午 0:00.00 (python3.7)
- win 3706 0.0 0.0 4277296 844 s000 S+ 10:49上午 0:00.00 grep 3690
- """
D
Python编译器在对Python的源码进行编译的时候,对代码中的 一个Code Block,会创建 一个PyCodeObject对象与这段代码对应。
Python中确定Code Block的规则:当进入一个新的名字空间或作用域时,就算进入了 一个新的CodeBlock
- class A:
- pass
- def Fun():
- pass
- a = A()
- Fun()
A.A()<br>Fun() B.1 C.2 D.3 E.4
- class Person:
- def __init__(self):
- pass
-
- def GetAge(self):
- print(__name__)
-
-
- p = Person()
- p.GetAge()
【答案】:__main__
print(self.__class__.__name__)。输出Person
print(__name__). 输出__main
Requests.Kenneth Reitz写的最富盛名的http库。每个Python程序员都应该有它。
Scrapy.如果你从事爬虫相关的工作,那么这个库也是必不可少的。用过它之后你就不会再想用别的同类库了。
wxPython.Python的一个GUI(图形用户界面)工具。我主要用它替代tkinter。你一定会爱上它的。
Pillow.它是PIL(Python图形库)的一个友好分支。对于用户比PIL更加友好,对于任何在图形领域工作的人是必备的库。
SQLAlchemy.一个数据库的库。对它的评价褒贬参半。是否使用的决定权在你手里。
BeautifulSoup.我知道它很慢,但这个xml和html的解析库对于新手非常有用。
Twisted.对于网络应用开发者最重要的工具。它有非常优美的api,被很多Python开发大牛使用。
NumPy.我们怎么能缺少这么重要的库?它为Python提供了很多高级的数学方法。
SciPy.既然我们提了NumPy,那就不得不提一下SciPy。这是一个Python的算法和数学工具库,它的功能把很多科学家从Ruby吸引到了Python。
matplotlib.一个绘制数据图的库。对于数据科学家或分析师非常有用。
Pygame.哪个程序员不喜欢玩游戏和写游戏?这个库会让你在开发2D游戏的时候如虎添翼。
Pyglet.3D动画和游戏开发引擎。非常有名的Python版本Minecraft就是用这个引擎做的。
pyQT.Python的GUI工具。这是我在给Python脚本开发用户界面时次于wxPython的选择。
pyGtk.也是Python GUI库。很有名的Bittorrent客户端就是用它做的。
Scapy.用Python写的数据包探测和分析库。
pywin32.一个提供和windows交互的方法和类的Python库。
nltk.自然语言工具包。我知道大多数人不会用它,但它通用性非常高。如果你需要处理字符串的话,它是非常好的库。但它的功能远远不止如此,自己摸索一下吧。
nose.Python的测试框架。被成千上万的Python程序员使用。如果你做测试导向的开发,那么它是必不可少的。
SymPy.SymPy可以做代数评测、差异化、扩展、复数等等。它封装在一个纯Python发行版本里。
IPython.怎么称赞这个工具的功能都不为过。它把Python的提示信息做到了极致。包括完成信息、历史信息、shell功能,以及其他很多很多方面。一定要研究一下它。
(这里的虚拟机是指处理虚拟机,而不是系统虚拟机(例如Qemu和Virtualbox)。进程虚拟机只是提供一般编程环境的程序,程序可以编程。)两者都解释字节码(一个是解释Java、一个是解释Pyhton))
Python解释器 由编译器和虚拟机组成,编译器负责把.py格式的源码文件编译成字节码,pycodeobject并存放在内存中,然后虚拟机逐行执行字节代码,转换成机器语言,虚拟机于操作系统交互。运行结束后,解释器将pycodeObject写入硬盘的pyc文件中,下次运行直接读取pyc问价。
Java虚拟机在操作系统做了一层封装,不直接于硬件关联,所有具有跨平台性。主要运行java字节码文件,可以不是java源码编译的,编译/解释成对应平台(linux/windows)的机器指令执行,Java虚拟机特点:一次编译、处处运行、自动内存管理、垃圾自动回收。
浅拷贝copy有两种情况:
深拷贝deepcopy:完全复制独立,包括内层列表和字典:
- import copy
- testList = [1,2,[3,4]]
- a = copy.copy(testList)
- b = copy.deepcopy(testList)
- # 外层列表是[1,2,[3,4]]
- # 内层列表是[3,4]
- # 复杂子对象 [3,4]
- # 简单子对象[1,2]
- print('原来对象的值和id',testList,id(testList))
- print('a的值和id',a,id(a))
- print('b的值和id',b,id(b))
- # 测试修改外层列表中的简单子对象,也就是修改1或2
- # 结果表明修改了原始list之后,a和b并没有随之改变,符合我们的正常逻辑,因为是3个不同的对象
- testList[0]='test'
- print('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@')
- print('将1改为test,原来对象的值和id',testList,id(testList))
- print('将1改为test,a的值和id',a,id(a))
- print('将1改为test,b的值和id',b,id(b))
- # 测试内层列表的值的修改,也就是测试复杂子对象的值的修改
- # 结果表明copy浅拷贝并没有真正将内层列表独立拷贝出来,导致修改了list内层列表(字典)后a的内层列表(字典)值也变了。
- # 结果表明deepcopy神拷贝可以将内层列表和字典独立拷贝出来,所以b的内层列表值不变
- testList[2][0]=5
- print('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@')
- print('将3改为5,原来对象的值和id',testList,id(testList))
- print('将3改为5,a的值和id',a,id(a))
- print('将3改为5,b的值和id',b,id(b))
-
- # 输出结果为:
- 原来对象的值和id [1, 2, [3, 4]] 4480733576
- a的值和id [1, 2, [3, 4]] 4480766664
- b的值和id [1, 2, [3, 4]] 4480389640
- @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- 将1改为test,原来对象的值和id ['test', 2, [3, 4]] 4480733576
- 将1改为test,a的值和id [1, 2, [3, 4]] 4480766664
- 将1改为test,b的值和id [1, 2, [3, 4]] 4480389640
- @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- 将3改为5,原来对象的值和id ['test', 2, [5, 4]] 4480733576
- 将3改为5,a的值和id [1, 2, [5, 4]] 4480766664
- 将3改为5,b的值和id [1, 2, [3, 4]] 4480389640
A、print(2.3-1.1) #输出结果为 1.1999999999999997
B、print(Decimal("2.3")- Decimal("1.1"))# 输出结果为1.2
C、print(Decimal(2.3)- Decimal(1.1)) #输出结果为1.199999999999999733546474090
D、print(round(2.3-1.1,2))# 输出结果为:1.2
decimal模块,使用的时候 :from decimal import *,这个模块提供了十进制浮点运算支持。
可以传递给Decimal整型或字符串参数,但不能是浮点数据,因为浮点数据根本不准确。
这个也是Python彪悍的特性,自省就是面向对象语言缩写的程序在运行时,所能知知道对象的类型,简单一句就是:运行时能够获得对象的类型,比如type()、dir()、hasattr()、isinstance()。
- 迭代:当创建的对象可以被一个接一个读取里面的值,叫做迭代
- 迭代器协议:对象需要提供next()方法,通过它返回迭代中的下一项,直到返回终止抛出Stopiteration。
- 可迭代对象:实现了迭代器协议对象。list、tuple、dict都是可迭代对象,但不是迭代器对象。
区别:
生成器的好处是延迟计算,一次返回一个结果。也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用。
什么是函数的重载?
- 简单的理解,支持多个同名函数的定义,只是参数的个数或者类型不同,在调用的时候,解释器会根据参数的个数或者类型,调用相应的函数。
- 重载这个特性在很多语言中都有实现,比如 C++、Java 等,而 Python 并不支持。
参数个数不同的情形
参数类型不同的类型
Python 中__new__()和__init__()的区别_鱼跃龙的博客-CSDN博客___new__和__init__区别
PS:__metaclass__是创建类时起作用,所以我们可以分别使用__metaclass__、__new__和__init__来分别在类创建,实例创建和实例初始化的时候做一些小手脚。
python中单例模式是什么_阿常呓语的博客-CSDN博客_python单例是什么
什么是单例模式?
一种常用的软件设计模式。单例模式的主要目的是确保某一个类只有一个实例存在。当开发者希望在整个系统中某个类只能出现一个实例时,单例模式就能派上用场。
使用场景:
- from functools import update_wrapper
- import redis
- from config.DB import REDIS_CONFIG
-
-
- def single(fn):
- """
- 这个函数 只会计算一次.并且对函数的参数不敏感.
- single is not sensitive to
- argument values, and will always return the ame value if
- called with different arguments.
- :param fn:
- :return:
- """
- name = fn.__name__
-
- def wrapper(*args, **kw):
- if name not in single.__dict__:
- ret = fn(*args, **kw)
- single.__dict__[name] = ret
- return ret
- else:
- return single.__dict__[name]
-
- return update_wrapper(wrapper, fn)
-
-
-
-
- pool = redis.ConnectionPool(**REDIS_CONFIG, decode_responses=True)
-
-
-
- @single
- def get_redis_client():
- client = redis.Redis(connection_pool=pool)
- return client
-
- if __name__ == '__main__':
- r = get_redis_client()
- r2 = get_redis_client()
- r3 = get_redis_client()
-
- print(id(r), id(r2), id(r3))
-
- print(r == r2 == r3) # True
- pass
-
直接用类装饰器来做
-
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- @Time : 2019/6/1 18:48
- @File : mysingle3.py
- @Author : frank.chang@shoufuyou.com
- """
-
- from functools import update_wrapper
-
-
- def singleton(cls):
- """
- 类装饰器 的使用,
- 这样简单的可以生成一个对象
- :param cls:
- :return:
- """
- dic = dict()
-
- def wrapper(*args, **kwargs):
- if cls not in dic:
- dic[cls] = cls(*args, **kwargs)
- return dic[cls]
-
- # copy 源数据 docstring name 等等..
- return update_wrapper(wrapper, cls)
-
-
- @singleton
- class Person:
- """
- This is Person
- """
- name = "Frank"
-
-
- if __name__ == '__main__':
- p = Person()
- p2 = Person()
- p3 = Person()
-
- print(p, p2, p3)
-
- print(p == p2 == p3)
- print(id(p), id(p2), id(p3))
-
- pass
实现 单例模式
这种方式 算是 比较标准的单例模式, 直接实现 __new__ 方法 ,同时定义一个类变量保存这个值,如果没有第一次 先生成好,赋值给类变量,之后发布会这个 类变量即可
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- @Time : 2019/5/30 11:01
- @File : redis_single.py
- @Author : frank.chang@shoufuyou.com
- """
-
- import redis
-
- from config.DB import REDIS_CONFIG
-
-
- class RedisClient:
- """
- 单例模式
- """
- _instance = None
-
- @classmethod
- def __new__(cls, *args, **kwargs):
- if not cls._instance:
- cls._instance = redis.StrictRedis(**REDIS_CONFIG, db=0)
-
- return cls._instance
-
-
- if __name__ == '__main__':
- # redis 客户端初始化工作
- r = RedisClient()
- r2 = RedisClient()
- r3 = RedisClient()
-
- print(id(r), id(r2), id(r3))
-
- print(r == r2 == r3)
-
- pass
使用元类来搞事情, 通过生成类的时候 实现call 魔术方法 来完成 类创建实例.
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- @Time : 2019/6/1 18:48
- @File : mysingle4.py
- @Author : frank.chang@shoufuyou.com
- """
-
-
- class SingletonMeta(type):
- def __new__(cls, clsname, bases, clsdict):
- clsobj = super().__new__(cls, clsname, bases, clsdict)
- clsobj._instance = None
- return clsobj
-
- def __call__(self, *args, **kwargs):
- if self._instance is None:
- self._instance = super().__call__(*args, **kwargs)
- return self._instance
-
-
- class Person(metaclass=SingletonMeta):
- def __init__(self, name='frank'):
- self.name = name
-
- def __str__(self):
- return "%s(name=%r)" % (self.__class__.__name__, self.name)
-
-
- if __name__ == '__main__':
- p = Person()
- p2 = Person()
- p3 = Person()
-
- print(p == p2 == p3) # True
- print(id(p), id(p2), id(p3))
- pass
本地作用域——>当前作用域被嵌入的本地作用域——>全局/模块作用域——>内置作用域
协程就是进程和线程的升级版,进程和线程都面临着内核态和用户态的切换问题,而耗费许多切换的时间,而协程就是用户自己控制切换的时间,不再需要陷入系统的内核态。
更多详情
Python函数编程中map()函数是将func作用域seq中的每一个元素,并将所有的调用的结果作为一个list返回。如果func为None,作用同zip()。
(变为一个含有几个元组的列表) 另一个解释,function可以理解为是一个一对一或者多对一的函数,map作用是以参数序列中的每一个元素调用function函数,
返回包含每次function函数返回值的list。
- # 1.1 比如要对一个序列中的每个元素进行平方运算:
- map(lamda x:x**2,[1,2,3,4,5])
- >>[1,4,9,16,25]
-
- #1.2 在参数存在多个序列时,会依次每个序列中相同位置的元素做参数调用function函数。比如要对两个序列中的元素依次求和。
- map(lambda x,y:x+y,[1,3,5,7,9],[2,4,6,8,10])
- >>>[3,7,11,15,19]
-
- # 注意:function函数的参数数量,要和map中提供的集合数量相匹配,如果集合长度不等,会以最小长度对所有集合进行截取。
-
- 1.3 当函数为None是,操作和zip相似
- map(None,[1,3,5,7,9],[2,4,6,8,10])
- >>>[(1,2),(3,4),(5,6),(7,8),(9,10)]
function是一个谓语函数,接受一个参数,返回布尔值TRUE或FALSE。
filter函数会对序列参数sequence中的每个参数调用function函数,
最后返回的结果为TRUE的元素,返回值的类型和参数sequence的类型相同。
- def is_even(x):
- return x&1 != 0
- filter(is_even,[1,2,3,4,5,6,7,8,9,10])
- 结果:
- >>[1,3,5,7,9]
reduce(function,sequence[,initial]) --->value function参数一个有两个参数的函数,
reduce依次从sequence中去一个元素,和上一次调用function的结果做参数在此调用function。
第一次调用function时,如果提供initial参数,会以sequence中第一个元素和initial作为参数调用function,
否则会以序列sequence中前两个元素做参数调用function。 注意:function函数不能为None
- reduce(lambda x,y:x+y,[2,3,4,5,6],1)
- '''21 ((((((1+2)+3)+4)+5)+6)'''
-
- reduce(lambda x,y:x+y,[2,3,4,5,6])
- '''20''
PythonGC主要使用引用技术来跟踪和回收垃圾。
在引用计数的基础上,通过标记-清除解决容器对象可能产生的循环引用问题;通过“分代回收”以空间换时间的方法提高垃圾回收效率。
PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少.引用计数为0时,该对象生命就结束了。
优点:
- 简单
- 实时性
缺点:
- 维护引用计数消耗资源
- 循环引用
基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫一遍内存空间,把所有没标记的对象释放。
分代回收的整体思想是:将系统中的所有内存块根据其存活时间划分为不同的集合,每个集合就成为一个“代”,垃圾收集频率随着“代”的存活时间的增大而减小,存活时间通常利用经过几次垃圾回收来度量。
Python默认定义了三代对象集合,索引数越大,对象存活时间越长。
举例:
当某些内存块M经过了3次垃圾收集的清洗之后还存活时,我们就将内存块M划到一个集合A中去,而新分配的内存都划分到集合B中去。当垃圾收集开始工作时,大多数情况都只对集合B进行垃圾回收,而对集合A进行垃圾回收要隔相当长一段时间后才进行,这就使得垃圾收集机制需要处理的内存少了,效率自然就提高了。在这个过程中,集合B中的某些内存块由于存活时间长而会被转移到集合A中,当然,集合A中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。
is是对比地址, ==是对比值
- import os
-
-
- def print_directory_contents(s_path):
- """
- 这个函数接受文件夹的名称作为输入参数,
- 返回该文件夹中文件的路径,
- 以及其包含文件夹中文件的路径。
- """
- for sChild in os.listdir(s_path):
- s_child_path = os.path.join(s_path, sChild)
- if os.path.isdir(s_child_path):
- print_directory_contents(s_child_path)
- else:
- print(s_child_path)
注意:
- A0 = dict(zip(('a','b','c','d','e'),(1,2,3,4,5)))
- A1 = range(10)
- A2 = [i for i in A1 if i in A0]
- A3 = [A0[s] for s in A0]
- A4 = [i for i in A1 if i in A3]
- A5 = {i:i*i for i in A1}
- A6 = [[i,i*i] for i in A1]
- # 答案
- A0 ={'a':1,'b':2,'c':3,'d':4,'e':5}
- A1 = [0,1,2,3,4,5,6,7,8,9]
- A2 = []
- A3 = [1,2,3,4,5]
- A4 = [1,2,3,4,5]
- A5 = [0:0,1:1,2:4,3:9,4:16,5:25,6:36,7:49,8:64,9:81]
- A6 = [[0, 0], [1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81]]
- def f(x,l=[]):
- for I in range(x):
- l.append(I*I)
- print(l)
- f(2)
- f(3,[3,2,1])
- f(3)
- # 输出最后的答案为
- [0,1]
- [3,2,1,0,1,4]
- [0,1,0,1,4]
random模块,
随机整数:random.randint(a,b);返回随机整数x,a<=x <=b
random.randrange(start,stop,[,step]): 返回一个范围在(start,stop,step)之间的随机整数,不包括结束值
随机实数:random.random()返回0到1之间的浮点数
随机浮点数:random.uniform(a,b)。返回指定范围内的浮点数。
解决方法是在function的开始插入一个global声明:
- def f():
- global x
后期会持续更新
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。