C语言基础学习PYTHON——基础学习D04                                

20180810内容纲要:

  1 内置函数

  2 装饰器

  3 生成器

  4 迭代器

  5 软件目录结构规范

  6 小结

1 内置函数

内置函数方法详解:https://docs.python.org/3/library/functions.html?highlight=built

 #Author:ZhangKanghui

 print(all([0,-5,4]))
print(all([1,-5,4]))
#all() return true if all elements of the iterable are true (or if the iterable is empty)
#any() 即是有一个真即为真。 a =ascii([1,2])
print(type(a),a)
print(type(a),[a])
#ascii() 把数据对象变成可打印的字符串形式 #bin() #把数字十进制转二进制
print(bool(0))
print(bool(1))
print(bool([]))
print(bool([1])) a =bytes("abcde",encoding="utf-8")
print(a.capitalize(),a) #字符串不可以被修改,因此字节格式的字符串也不能被修改
b =bytearray("abcde",encoding="utf-8") #bytearray()变成列表,这样就可以修改了
print(b[0]) #以ascii码输出第一个字节
b[1] = 100
print(b) print(callable([])) #判断是否可调用,就看能不能加()的方式调用
def a():pass
print(callable(a)) print(chr(98))
print(ord('b')) print(divmod(5,3)) #输出结果(商,余数)
#eval() #把一个字符串变成字典 def var():
local_var =333
print(locals())
var()
print(globals()) #程序的所有变量以key,value字典形式输出
print(globals().get('local_var')) #程序的所有变量以key,value字典形式输出 print(hash('Kanghui')) print(hex(15)) #转十六进制
print(oct(1)) #转八进制
print(pow(3,5)) #3的5次方
d ='<code object <module> at 0x03379230, file "", line 1>'
print(repr(d)) #转成字符串
print(round(1.433,2)) #保留两位小数
f =range(20)
#print(d[slice(2,5)]) 这是什么鬼?说好的切片呢 a ={6:30,8:7,1:4,99:27,18:16}
#print(sorted(a)) #只是把字典中的key排序了,没有value的值
#如何实现带有value的key排序呢/
#print(sorted(a.items())) #排序完成后变成一个列表,因为字典默认是无序的
#那么按value排序怎么办呢?
print(sorted(a.items(),key =lambda x:x[1]))
print(a) m =[1,2,3,4]
n =['a','b','c','d']
print(zip(m,n))
for i in zip(m,n):
print(i)

部分示例

2 装饰器

  a 高阶函数

  b 嵌套函数

高阶函数+嵌套函数》=装饰器

    定义:本质就是函数,为其他函数添加附加功能。

   原则:

1.不能修改被装饰函数的源代码

2.不能修改被装饰函数的调用方式

a 高阶函数

高阶函数1:貌似是一个装饰器,car装饰bar。虽然没有改变bar的源代码为bar添加了附加功能,但是改变了调用方式

 import  time

 def bar():
time.sleep(3)
print('in the bar') def car(func):
start_time =time.time()
func()
stop_time =time.time()
print('the func run time is %s' %(stop_time-start_time)) car(bar)

高阶函数1

高阶函数2:

 import time
def bar():
time.sleep(3)
print('in the bar')
def car(func):
print(func)
return func # print(car(bar))
#二者的区别
# a=car(bar()) #将bar()的执行结果/返回值传给func,这样就不符合高阶函数的定义
# b=car(bar) #将bar的内存地址传给func,
# print(a)
# print(b)
t =car(bar) #将bar的内存地址传给func先执行函数car里面的print(bar的内存地址),然后返回执行函数bar
t()
#此时,把t赋给bar
bar=car(bar)
bar()
#现在好像不修改函数的调用方式也能为其添加附加功能,但是给bar重新定义,将原来函数中的bar给覆盖掉了

高阶函数2

如何实现不改变源代码和调用方式的情况下实现装饰器呢?

b 嵌套函数

嵌套函数:

 #Author:ZhangKanghui

 def foo():
print('in the foo')
def bar(): #此处的函数bar即变量,局部变量。只能在嵌套函数内局部调用
print('in the bar') #bar() 这里不能调用函数bar可以类比局部变量

嵌套函数

接下来,把高阶函数和嵌套函数结合起来有很么用呢?

>>装饰器:

 #Author:ZhangKanghui
#装饰器 import time
def timer(func): #高阶函数,返回值中包含函数名
def dec(): #嵌套函数
start_time = time.time()
func() #run bar()
stop_time = time.time() #添加功能
print('the func run time is %s' % (stop_time - start_time))
return dec #返回函数dec的内存地址
#@timer #bar=timer(bar)
def bar():
time.sleep(3)
print('in the bar')
bar=timer(bar)
bar() #bar()=dec()
# 如果想要传参数
@timer
def test2(name):
print("test2:",name)
test2()

装饰器(基础版)

 #Author:ZhangKanghui
#模拟网站,一个函数就是一个网页,部分网页需要登录,添加验证功能 user,passwd = 'Kanghui','abc123' #先写个特殊情况下指定用户账号密码
import time
def auth(func):
def wrapper(*args,**kwargs):
user_name =input("user_name:").strip() #去掉两头的空格和回车
password =input("passwd:").strip() if user ==user_name and passwd ==password:
print("\033[32;1mUser has passed authentication\033[0m")
func(*args,**kwargs) else:
exit("\031[32;1mInvalid password\033[0m")
return wrapper def index():
print("welcome to index page")
@auth
def bbs():
print("welcome to bbs page") index()
bbs()
#此时这个装饰器的基本功能已经完成。虽然正常情况下只需登录一次即可。
#接下来有个问题:没有改变函数源代码和调用方式但是函数执行以后的返回值发生了变化
@auth
def home():
print("welcome to home page")
return "from home"
print(home()) #调用home()相当于调用wrapper()
#如何获取到home的返回值
# 将func() 换成return func(*args,**kwargs) #这个可以使home()获取到自己的返回值

装饰器(进阶版)

 #Author:ZhangKanghui
user,passwd = 'Kanghui','abc123' #先写个特殊情况下指定用户账号密码
import time
def auth(auth_type):
print("auth_type:",auth_type)
def out_wrapper(func):
def wrapper(*args,**kwargs):
print("wrapper func args:",*args,**kwargs)
if auth_type =='local':
user_name =input("user_name:").strip() #去掉两头的空格和回车
password =input("passwd:").strip() if user ==user_name and passwd ==password:
print("\033[32;1mUser has passed authentication\033[0m")
func(*args,**kwargs) else:
exit("\031[32;1mInvalid password\033[0m")
elif auth_type=='ldap':
print("搞毛线") return wrapper
return out_wrapper
def index():
print("welcome to index page")
@auth(auth_type ='local')
def bbs():
print("welcome to bbs page")
@auth(auth_type ='ldap')
def home():
print("welcome to home page")
return "from home"

装饰器(高级版)

那么装饰器是如何实现在不改变源代码和调用方式的情况下为函数添加附加功能的呢?可以通过以上三个案例debug一下,看一下程序运行过程。

装饰器的作用;

  • 封闭:已实现的功能代码块不应该被修改
  • 开放:对现有功能的扩展开放

这里还有一个额外扩展练习:

 user_status = False #用户登录了就把这个改成True

 def login(auth_type): #把要执行的模块从这里传进来
def auth(func):
def inner(*args,**kwargs):#再定义一层函数
if auth_type == "qq":
_username = "alex" #假装这是DB里存的用户信息
_password = "abc!23" #假装这是DB里存的用户信息
global user_status if user_status == False:
username = input("user:")
password = input("pasword:") if username == _username and password == _password:
print("welcome login....")
user_status = True
else:
print("wrong username or password!") if user_status == True:
return func(*args,**kwargs) # 看这里看这里,只要验证通过了,就调用相应功能
else:
print("only support qq ")
return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数 return auth def home():
print("---首页----") @login('qq')
def america():
#login() #执行前加上验证
print("----欧美专区----") def japan():
print("----日韩专区----") @login('weibo')
def henan(style):
'''
:param style: 喜欢看什么类型的,就传进来
:return:
'''
#login() #执行前加上验证
print("----河南专区----") home()
# america = login(america) #你在这里相当于把america这个函数替换了
#henan = login(henan) # #那用户调用时依然写
america() # henan("3p")

隔壁老王讲述装饰器

3 生成器

>>生成器generator:

  1.只有在调用时才会生成相应的数据

  2.只记录当前位置

  3.只有一个__next__()方法逐个调用生成器中的数据

先来做个对比:

列表生成式:

 列表生成式:
>>>[i*2 for i in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18] a=[]
>>> for i in range(10):
... a.append(i*2)
...
>>> a
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18] >>> ( i*2 for i in range(10) )
<generator object <genexpr> at 0x0155B030>

cmd列表生成式

生成器方式:

 通过生成器的方式
>>> b=( i*2 for i in range(10) )
>>> for i in b:
... print(i)
...
0
2
4
6
8
10
12
14
16
18

cmd生成器方式

[]和()的区别在于:[]这个在访问之前,所有的数据都已经准备完毕。而()只是提供了一种算法数据暂时不存在,只有访问的时候才会存在

这样能够节省内存空间。不信可以试试这个

 a=[for i*2 in range(100000000)]

     a[1000]

     b=(for i*2 in range(100000000))

     b[1000]

     TypeError: 'generator' object is not subscriptable

试试你的电脑怎么样

那除了循环还有什么方式可以调用生成器中的数据呢?

 >>> b=( i*2 for i in range(10) )

 >>> b.__next__()

 0

view code

generator非常强大,如果推算的算法比较复杂,用类似列表的生成式的for循环无法实现的时候,还可以用函数实现。

比如著名的斐波那契数列(Fibonacci)除第一个和第二个外,任一个数都可以由前两个数相加得到。

1,1,2,3,5,8,13,...

 #Author:ZhangKanghui

 #斐波那契数列的推算
'''
def fib(max):
n,a,b =0,0,1
while n<max:
print(b)
a,b =b, a+b #注意赋值语句
#一般会理解成:a=0 b=1 a=b a=1
#b=a+b b=1+1=2 但实际上b=0+1=1。。。。下面有详解
n=n+1
return 'done'
fib(10)
''' #注意赋值语句: a,b =b, a+b
#t =[a,a+b] #t是一个tumple
#a =t[0]
#b=t[1]
#但不必显式写出临时变量t就可以赋值。

斐波那契数列的推算

#此时,离生成器只有一步之遥,fib函数只是定义了斐波那契数列推算的规则,这种逻辑很类似生成器
#此时,只需要吧print(b)改成yeild b神奇的事情就会发生了
 def fib(max):
n,a,b =0,0,1
while n<max:
yield b
a,b =b, a+b
n=n+1
return 'done'
print(fib(10))
#<generator object fib at 0x003BCDE0>
b=fib(10)
print(b.__next__())
print("i am your dad")
print(b.__next__())
print("hello world")
print(b.__next__())
#此时,我们能够完成随时在生成器访问值的过程中添加其他操作。
'''
print("---new strat---")
for i in b:
print(i)
'''
#并且可以随时再次接着继续访问生成器中的值
#那么最终会打印输出 return "done"吗?
#在for 循环中就不会打印。但是...一路next呢?

生成器之斐波那契数列

在一路next之后,出现异常该怎么抓住异常呢?

 def fib(max):
n,a,b =0,0,1
while n<max:
yield b
a,b =b, a+b
n=n+1
return 'done'
print(fib(10))
#<generator object fib at 0x003BCDE0>
b=fib(10)
print(b.__next__())
print("i am your dad")
print(b.__next__())
print("hello world")
print(b.__next__())
#此时,我们能够完成随时在生成器访问值的过程中添加其他操作。
'''
print("---new strat---")
for i in b:
print(i)
'''
#并且可以随时再次接着继续访问生成器中的值
#那么最终会打印输出 return "done"吗?
#在for 循环中就不会打印。但是...一路next呢?
print(b.__next__())
print(b.__next__())
print(b.__next__())
print(b.__next__())
print(b.__next__())
print(b.__next__())
print(b.__next__())
print(b.__next__())
print(b.__next__())
#异常 :StopIteration: done
#那么我们如何抓住这个异常呢?下面是一段捕获异常的代码

先来看看异常

 g=fib(6)
while True:
try:
x =next(g)
print('g',x)
except StopIteration as e:
print("Generator return value:",e.value)
break

如何捕获异常

generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,

在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

补充一条:

 def send(self,value)
'''Resume the generator and “send” a value that becomes the result of the current yield-expression.'''

send介绍

还可通过yield实现在单线程的情况下实现并发运算的效果:

 #Author:ZhangKanghui
import time
def consumer(name):
print("%s is ready to eat baozi" %name)
while True:
baozi =yield #保存当前状态 print("baozi %s is coming,%s miximixi" %(baozi,name)) '''
c =consumer('Kanghui')
c.__next__()
b1 ='beef'
c.send(b1)
c.__next__() #此时包子并没有传值进去,只是在调用yield,继续执行yield之前保存的状态
'''
def producer(name):
c1 =consumer('A') #这样只是把函数变成生成器还没开始运行,所以下面要调用next、
c2 =consumer('B')
c1.__next__()
c2.__next__()
print("Your dad is ready to make baozi")
for i in range(10):
time.sleep(1)
print("Have made two")
c1.send(i)
c2.send(i) producer('Kanghui')
#这样就能实现交互式地

生成器并发运算

4 迭代器

可直接作用于for循环的数据类型:

  一、集合数据类型:list、tuple、dict、set、str等

  二、generat,包括生成器和带yield的generator function

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

可以使用isinstance()判断一个对象是一个什么样的类型。

 >>> from collections import Iterable
>>> isinstance([],Iterable)
True

isinstance用法1

可以被next()函数调用并不断返回下一个值的对象成为迭代器:Interator 。

 >>> from collections import Iterator
>>> isinstance((x for x in range(10)),Iterator)
True
>>> isinstance([],Iterator)
False

isinstance用法2

虽然list、dict、str是Iterable 但是却不是Iterator

把这些变成Iterator可以使用iter()函数

 >>> isinstance(iter([]),Iterator)
True

iter函数

这是为什么呢?因为在Python中的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并返回下个数据,直到没有数据抛出

StopIteration错误。可以把这个数据流看做是一个有序序列,但不知道长度,只能通过next()函数实现按需计算下一个数据,所以Iterator是

惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以是一个无限大的数据流,例如全体自然数,而使用list是不可能存储全体自然数的。

Python的for循环实际上就是通过不断调用的next()函数实现的。

 #Author:ZhangKanghui

 for x in [1,2,3,4,5]:
pass
#实际上就等价于:
it = iter([1,2,3,4,5]) #迭代器
while True:
try:
x =next(it)
except StopIteration:
break

for循环的本质

5 软件目录结构规范

目录的组织方式:在Stackoverflow的上,能看到大家对Python目录结构的讨论。点击这里

大概都会是这个样子。

如果你想写一个开源软件,目录该如何组织,可以参考这篇文章
可以参考Redis源码中Readme的写法,这里面简洁但是清晰的描述了Redis功能和源码结构。
一般来说,用setup.py来管理代码的打包、安装、部署问题。业界标准的写法是用Python流行的打包工具setuptools来管理这些事情。
setuptools的文档比较庞大,刚接触的话,可能不太好找到切入点。学习技术的方式就是看他人是怎么用的,可以参考一下Python的一个Web框架,flask是如何写的: setup.py
https://jeffknupp.com/blog/2013/08/16/open-sourcing-a-python-project-the-right-way/
https://github.com/antirez/redis#what-is-redis
https://github.com/pallets/flask/blob/master/setup.py
https://pip.readthedocs.io/en/1.1/requirements.html

6 小结
当你陷入绝望的时候,那就放弃吧!
 #===============>star.py
import sys,os
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR) from core import src if __name__ == '__main__':
src.run()
#===============>settings.py
import os BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DB_PATH=os.path.join(BASE_DIR,'db','db.json')
LOG_PATH=os.path.join(BASE_DIR,'log','access.log')
LOGIN_TIMEOUT=5 """
logging配置
"""
# 定义三种日志输出格式
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' # log配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
},
'filters': {},
'handlers': {
#打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
#打印到文件的日志,收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': LOG_PATH, # 日志文件
'maxBytes': 1024*1024*5, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
},
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
},
},
} #===============>src.py
from conf import settings
from lib import common
import time logger=common.get_logger(__name__) current_user={'user':None,'login_time':None,'timeout':int(settings.LOGIN_TIMEOUT)}
def auth(func):
def wrapper(*args,**kwargs):
if current_user['user']:
interval=time.time()-current_user['login_time']
if interval < current_user['timeout']:
return func(*args,**kwargs)
name = input('name>>: ')
password = input('password>>: ')
db=common.conn_db()
if db.get(name):
if password == db.get(name).get('password'):
logger.info('登录成功')
current_user['user']=name
current_user['login_time']=time.time()
return func(*args,**kwargs)
else:
logger.error('用户名不存在') return wrapper @auth
def buy():
print('buy...') @auth
def run(): print('''
1 购物
2 查看余额
3 转账
''')
while True:
choice = input('>>: ').strip()
if not choice:continue
if choice == '':
buy() #===============>db.json
{"egon": {"password": "", "money": 3000}, "alex": {"password": "alex3714", "money": 30000}, "wsb": {"password": "", "money": 20000}} #===============>common.py
from conf import settings
import logging
import logging.config
import json def get_logger(name):
logging.config.dictConfig(settings.LOGGING_DIC) # 导入上面定义的logging配置
logger = logging.getLogger(name) # 生成一个log实例
return logger def conn_db():
db_path=settings.DB_PATH
dic=json.load(open(db_path,'r',encoding='utf-8'))
return dic #===============>access.log
[2017-10-21 19:08:20,285][MainThread:10900][task_id:core.src][src.py:19][INFO][登录成功]
[2017-10-21 19:08:32,206][MainThread:10900][task_id:core.src][src.py:19][INFO][登录成功]
[2017-10-21 19:08:37,166][MainThread:10900][task_id:core.src][src.py:24][ERROR][用户名不存在]
[2017-10-21 19:08:39,535][MainThread:10900][task_id:core.src][src.py:24][ERROR][用户名不存在]
[2017-10-21 19:08:40,797][MainThread:10900][task_id:core.src][src.py:24][ERROR][用户名不存在]
[2017-10-21 19:08:47,093][MainThread:10900][task_id:core.src][src.py:24][ERROR][用户名不存在]
[2017-10-21 19:09:01,997][MainThread:10900][task_id:core.src][src.py:19][INFO][登录成功]
[2017-10-21 19:09:05,781][MainThread:10900][task_id:core.src][src.py:24][ERROR][用户名不存在]
[2017-10-21 19:09:29,878][MainThread:8812][task_id:core.src][src.py:19][INFO][登录成功]
[2017-10-21 19:09:54,117][MainThread:9884][task_id:core.src][src.py:19][INFO][登录成功]

从入门到放弃

D04——C语言基础学PYTHON的更多相关文章

  1. D10——C语言基础学PYTHON

    C语言基础学习PYTHON——基础学习D10 20180906内容纲要: 1.协程 (1)yield (2)greenlet (3)gevent (4)gevent实现单线程下socket多并发 2. ...

  2. D16——C语言基础学PYTHON

    C语言基础学习PYTHON——基础学习D16 20180927内容纲要: 1.JavaScript介绍 2.JavaScript功能介绍 3.JavaScript变量 4.Dom操作 a.获取标签 b ...

  3. D15——C语言基础学PYTHON

    C语言基础学习PYTHON——基础学习D15 20180926内容纲要: 1.CSS介绍 2.CSS的四种引入方式 3.CSS选择器 4.CSS常用属性 5.小结 6.练习 1 CSS介绍 层叠样式表 ...

  4. D07——C语言基础学PYTHON

    C语言基础学习PYTHON——基础学习D07 20180826内容纲要: 面向对象进阶学习 1 静态方法 2 类方法 3 属性方法 4 类的特殊成员方法(本节重点) 5 反射(本节重点) 6 异常(本 ...

  5. D06——C语言基础学PYTHON

    C语言基础学习PYTHON——基础学习D06 20180821内容纲要: 面向对象初级学习 1 面向对象 2 类 (1)封装 (2)继承 (3)多态 3 小结 4 练习:选课系统 5 课外拓展:答题系 ...

  6. D05——C语言基础学PYTHON

    C语言基础学习PYTHON——基础学习D05 20180815内容纲要: 1 模块 2 包 3 import的本质 4 内置模块详解 (1)time&datetime (2)datetime ...

  7. D17——C语言基础学PYTHON

    C语言基础学习PYTHON——基础学习D17 20181014内容纲要: 1.jQuery介绍 2.jQuery功能介绍 (1)jQuery的引入方式 (2)选择器 (3)筛选 (4)文本操作 (5) ...

  8. D14——C语言基础学PYTHON

    C语言基础学习PYTHON——基础学习D14 20180919内容纲要: 1.html认识 2.常用标签 3.京东html 4.小结 5.练习(简易淘宝html) 1.html初识(HyperText ...

  9. D13——C语言基础学PYTHON

    C语言基础学习PYTHON——基础学习D13 20180918内容纲要: 堡垒机运维开发 1.堡垒机的介绍 2.堡垒机的架构 3.小结 4.堡垒机的功能实现需求 1 堡垒机的介绍 百度百科 随着信息安 ...

随机推荐

  1. javascript的一些札记

    1. 原来放在不同js文件里面的$(document).ready(function(){})都会执行到. 2. $(window).scroll(function(){})  窗口滚动事件. 3.  ...

  2. bootstrap-datepicker 与bootstrapValidator同时使用时,选择日期后,无法正常触发校验

    bootstrap-datepicker 与bootstrapValidator同时使用时,选择日期后,无法正常触发校验 (解决办法) http://blog.csdn.net/biedazhangs ...

  3. 负值之美:负margin在页面布局中的应用

    本文转载自:http://www.topcss.org/?p=94,有修改. 负数给人总是一种消极.否定.拒绝之感,不过有时利用负margin可以达到奇妙的效果,今天就表一表负值在页面布局中的应用.这 ...

  4. jquery 插入节点的方法

    方法 描述 示例 append() 向每个匹配的元素内部追加内容 HTML代码: <p>我想说:</p> jQuery代码: $("p").append(& ...

  5. 2018.07.18 [NOI2018]归程(return)(kruskal重构树)

    传送门 新鲜出炉的noi2018试题. 下面讲讲这题的解法: 首先要学习一个叫做kruskal重构树的东东. 听名字就知道跟kruskal算法有关,没错,原来的kruskal算法就是用并查集实现的,但 ...

  6. hdu-1130(卡特兰数+大数乘法,除法模板)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1130 卡特兰数:https://blog.csdn.net/qq_33266889/article/d ...

  7. 第二章:冠词(Les articles)

    ★定冠词(Les articles définis ): 阳性单数:le(l') 阴性单数:la(l') 阴阳性复数:les ()表示前面已经提到的人或事物: ()有关的名词已被其它的成分(补语,关系 ...

  8. Python 插件(add-in)基础知识

    1)  Python插件为何物 一个插件(add-in)就是一个客户化,比如嵌入到ArcGIS应用程序中的工具条上的一系列工具,这些工具作为ArcGIS标准程序的补充可以为客户完成特殊任务. ArcG ...

  9. id 与 void * 转换

    MRC 环境下: id 变量赋值给 void * 变量运行时不会有问题. id obj1 = [NSObject new];void * p = obj1; void * 变量赋值给 id 变量并调用 ...

  10. 《Android开发艺术探索》第11章 Android的线程和线程池

    第11章 Android的线程和线程池 11.1 主线程和子线程 (1)在Java中默认情况下一个进程只有一个线程,也就是主线程,其他线程都是子线程,也叫工作线程.Android中的主线程主要处理和界 ...