列式存储与行式存储

以前不是特别明白列式存储和行式存储到底有什么区别,对于突然蹦出来的BigTable、HBase、Cassandra这些NoSQL数据库凭什么比MySQL集群,Oracle在分析存储上的强大?思来可以这样说说。

A. 存储

传统RDBMS以行单位做数据存储(字段为空则赋值为‘NULL’),列式存储数据库以列为单位做数据存储。如下:

%title插图%num

%title插图%num

对于列式存储来说,一行数据包含一个列或者多个列,每个列一单独一个cell来存储数据。而行式存储,则是把一行数据作为一个整体来存储。

另外一个不得不提的是,列式存储天生就是适合压缩,因为同一列里面的数据类型基本是相同,笔者在之前使用普通的gzip压缩,200MB的字符串数据,经过压缩之后只剩下8MB。当然gzip并不属于增量压缩,我们可以选择增量压缩的方式来满足一些数据的随机查找。

B.  查询

从查询来说,行式存储比较适合随机查询,并且RDBMS大多提供二级索引,在整行数据的读取上,要优于列式存储。但是,行式存储不适合扫描,这意味着要查询一个范围的数据,行式存储需要扫描整个表(因为这些记录不是顺序存储的),在索引建立不当的情况下,查询大表(千万数据)简直是噩梦。

列式存储,*早接触的可能不是所谓的BigTable,大多数以前的数据仓库都是采用列式存储。列式存储一般行KEY,列KEY(不是列值)都是顺序存储,比如我要查询一个时间段里面,某个值的出现频率,我可能只需要涉及到两个列。

在分析上,列式存储要优于行式存储,列式存储的数据库一般情况下也强烈建议用户按需查找,而不是整行数据去获取。列式存储在这方面减少了IO的压力。

C. 结语

没有说谁比谁更优,在正真实战的情况,考虑实际情况。比如传统的RDBMS提供ACID原子操作和事务,在大多数列式存储数据库上是不具备的,大多数列式存储数据库对分布式支持友好。

需要知道的是,列式存储以及行式存储在查询和存储上的本质,在技术选型上多点筹码。

什么是列式数据库?列式数据库是以列相关存储架构进行数据存储的数据库。卢东明认为数据库发展已经到了一个新阶段,数据库市场需要细分,行式数据库不再满足所有的需求,而有很多需求需要通过内存数据库和列式数据库解决,列式数据库在数据分析、海量存储、BI这三个领域有自己独到。

5 年内可能会发生以下变化:

大多数数据仓库将以列模式存储

大多数 OLTP 数据库将可能是内存数据库 (IMDB),或完全驻留在内存内

大多数大型数据库服务器将通过集群方式进行横向扩展

很多数据收集和报告问题将由没有任何形式图式的数据库解决。

传统的行式数据库,是按照行存储的,维护大量的索引和物化视图无论是在时间(处理)还是空间(存储)方面成本都很高。而列式数据库恰恰相反,列式数据库的数据是按照列存储,每一列单独存放,数据即是索引。只访问查询涉及的列,大大降低了系统I/O,每一列由一个线来处理,而且由于数据类型一致,数据特征相似,*大方便压缩。

*后卢东明很务实的指出,没有万能的数据库,Sybase IQ也并非万能,只不过给DBA们的工具箱里提供更多的选择,DBA需根据自己的应用场景自行选择。

在数据仓库领域,列式数据库和传统的行式数据库有何差别呢?列式数据库和行式数据库的拥护者均认为结合这两种技术的混合数据库是个不错的想法。

行式数据库擅长随机读操作,列式数据库则更擅长大批量数据量查询,而混合数据库则试图同时包含这两种技术的优点,在灾难恢复环境中,数据要么按列式存储,要么按行式存储。

我认为未来将是列式数据库的天下,行数据库和混合型数据库都将渐渐消亡,原因如下:数据增长速度很快,对存储设备(主内存和SSD)的需求也将不断上升,随着主内存和SSD中压缩列所占百分比的提高,列式数据库随机读的弱点反而变成了优点,这样列式数据库不管是应付联机事务处理,还是大批量更新或大型报表需要执行的复杂查询都能应付自如。对于更新操作而言,列式数据库和行式数据库在这方面已经没有多大差距了,因为大部分更新操作只会影响到一行中的一到三列(字段),同时,大部分更新操作影响的是*近的数据,因此主内存/SSD缓存中数据会越来越多。对于插入和删除操作而言,先在内存中快速更新索引,然后再写入磁盘,这意味着在I/O密集型情况下也不会有明显的性能下降。对在线备份而言,按列存储方法压缩数据后备份时间窗口将会更短。

对今天的数据仓库而言,列式数据库的性能和传统行数据库相比,根本不在一个数量级上,列式数据库已经得到了广泛的认可和使用(Sybase IQ已经有十年历史,也出现了一些新兴列式数据库公司,如Vertica),数据库巨人Oracle也按捺不住,在其Exadata数据库机中也加入了按列存储选择,IBM则提供了一个列式专用设备,它可以确定什么数据该按列存储,什么数据该按行存储,然后将事务分流到相应的设备。

列式数据库

维基百科,自由的百科全书

列式数据库是以列相关存储架构进行数据存储的数据库,主要适合与批量数据处理和即席查询。相对应的是行式数据库,数据以行相关的存储体系架构进行空间分配,主要适合与小批量的数据处理,常用于联机事务型数据处理。

[编辑]描述

数据库以行、列的二维表的形式存储数据,但是却以一维字符串的方式存储,例如以下的一个表:

EmpId Lastname Firstname Salary
1 Smith Joe 40000
2 Jones Mary 50000
3 Johnson Cathy 44000

这个简单的表包括员工代码(EmpId), 姓名字段(Lastname and Firstname)及工资(Salary).

这个表存储在电脑的内存(RAM)和存储(硬盘)中。虽然内存和硬盘在机制上不同,电脑的操作系统是以同样的方式存储的。数据库必须把这个二维表存储在一系列一维的“字节”中,又操作系统写到内存或硬盘中。

行式数据库把一行中的数据值串在一起存储起来,然后再存储下一行的数据,以此类推。

1,Smith,Joe,40000;2,Jones,Mary,50000;3,Johnson,Cathy,44000;

列式数据库把一列中的数据值串在一起存储起来,然后再存储下一列的数据,以此类推。

1,2,3;Smith,Jones,Johnson;Joe,Mary,Cathy;40000,50000,44000;

这是一个简化的说法。

列式数据库的代表包括:Sybase IQParAccelSand/DNA Analytics和 Vertica

Sybase IQ: 知道IQ跟其它的关系型数据库相比,它的主要特征是什么?包括查询快、数据压缩比高、Load快,但是插入更新慢,不太适合数据老是变化,它是按列存储的。这时候你就知道它适做DSS(决策支持系统),数据集市,数据仓库,它不适合OLTP。适合OLAP 。

列式数据库的优点:
数据压缩比高,正因为同一类型的列存储在一起。
简化数据建模的复杂性。
由于查询需要读取的blocks少,速度更快。
BI的优秀选择。

阿里云发布vSphere虚拟机备份服务 ,网络带宽有限条件下依然能有效保护数据

常见虚拟机备份技术的挑战

传统常见的虚拟机备份方式是把虚机机当做单独的主机,在每台虚拟机上安装备份软件,然后备份到本地的存储,这种方案可以用在虚拟机数目不大的环境,当虚拟机规模很大的时候,这种备份方案的部署管理就变得非常复杂,不仅影响运维效率,更可能导致备份作业失败,数据得不到有效的保护。

传统备份方案主要的问题:

 备份管理复杂,需要管理多个独立的备份客户端以及相应的备份策略;

 需要部署和维护本地备份存储,存储空间扩容周期长 ;

 缺乏有效的重复数据删除和压缩能力,成本较高;

 生产环境和备份设备在相同的机房,一旦发生灾难情况,生产环境数据和备份数据同时丢失。

以上这些问题长期困扰着备份管理员,混合云备份HBR for vSphere简化备份和恢复策略,减少人工操作,让备份管理员从复杂的日程维护中解放出来。混合云备份提供了vSphere虚拟机备份的完整解决方案, 支持VAPP一键部署,无需部署云下的备份服务器和备份设备,数据经过集成的全局客户端可变长重删后,快速安全高效地备份上云。
**
HBR for vSphere的使用场景**

这里写图片描述

在客户数据中心只需要部署HBR备份VAPP就可以方便地备份VMware ESXi上的虚拟机,借助公网或者专线就可以将vSphere环境和阿里云打通,阿里云备份库的高可用性,云备份库自带的多副本功能,确保客户备份数据的安全可靠。
这里写图片描述

混合云备份采用CBT(Change Block Tracking)技术,实现了更快的数据备份和恢复,相对于全量备份时将VMDK的全部数据保存到备份库, 基于CBT的增量备份只需要保存上次备份后发生了变化的数据块。VMware ESXi为每个开启了CBT功能的虚拟磁盘都创建了ctk文件,用于保存变化块的元数据。混合云备份基于CBT技术只传输变化的数据块,并且在备份的过程中可以和上一次备份的索引快速合并形成全量备份,这样可以显著提高备份还原效率。

HBR for vSphere的优势

快速备份:采用CBT技术只备份增量数据,可以有效缩短备份窗口
降低使用成本:支持不同的虚拟机镜像备份到同一个备份库,虚拟机镜像之间的重复数据非常多,高效的重删压缩算法可以大幅减少所需的备份库存储空间
运维简单: 无需管理备份服务器和备份库,备份客户端安装配置简单,备份*速上云,云端集中监控
阿里云此次推出的HBR for vSphere提供了端到端虚拟机备份、恢复和云端管理功能,让客户在整个虚拟机生命周期中更好的保护虚拟机。

朴素贝叶斯-使用训练样本量来画学习曲线

朴素贝叶斯-使用训练样本量来画学习曲线

#绘制学习曲线
import numpy as np
import matplotlib.pyplot as plt
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import ShuffleSplit
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.tree import DecisionTreeClassifier as DTC
from sklearn.linear_model import LogisticRegression as LR
from sklearn.datasets import load_digits
from sklearn.model_selection import learning_curve
from time import time
import datetime
#定义一个绘制学习曲线的函数
def plot_learning_curve(estimator,title,X,y,
ax,#选择子图
ylim=None,#设置纵坐标范围
cv=None,#交叉验证
n_jobs=None#设定线程
):

train_sizes,train_scores,test_scores=learning_curve(estimator,X,y,cv=cv,n_jobs=4)
ax.set_title(title)
if ylim is not None:
ax.set_ylim(*ylim)
ax.set_xlabel(“Training examples”)
ax.set_ylabel(“Score”)
ax.grid()#显示网格作为背景
ax.plot(train_sizes,np.mean(train_scores,axis=1),’o-‘,color=’r’,label=”Training sore”)
ax.plot(train_sizes,np.mean(test_scores,axis=1),’o-‘,color=’g’,label=”Test sore”)
#因为是分成50份,所以会有50个结果,所以要取均值,另外,o-表示以点横的样子画图
ax.legend(loc=”best”)
return ax

#把数据集分成50分,其中百分之20是测试集,
digits=load_digits()
X,y=digits.data,digits.target
title=[“Naive Bayes”,”DecisionTree”,”SVM,RBF kernel”,”RandomForest”,”Logistic”]
model=[GaussianNB(),DTC(),SVC(gamma=0.001),RFC(n_estimators=50),LR(C=0.1,solver=”lbfgs”)]
cv=ShuffleSplit(n_splits=50,test_size=0.2,random_state=0)

fig,axes=plt.subplots(1,5,figsize=(30,6))#设置多个子图,一行5列
#函数返回一个figure图像和子图ax的array列表

fig, axes = plt.subplots(1,5,figsize=(30,6))
for ind,title_,estimator in zip(range(len(title)),title,model):
times = time()
plot_learning_curve(estimator, title_, X, y,
ax=axes[ind], ylim = [0.7, 1.05],n_jobs=4, cv=cv)
print(“{}:{}”.format(title_,datetime.datetime.fromtimestamp(time()-
times).strftime(“%M:%S:%f”)))
plt.show()#注意缩进

决策树为什么快呢:没有计算所有特征的信息熵,而是是从中随机选择的几个,随着样本量增大会越来越慢
朴素贝叶斯:再很少的样本上得到不错的效果,随着样本量增大会比决策树跑的更快一些,
因为当特征很大的时候,决策树是万万不敢只选择几个特征进行建模的,但是,朴素贝叶斯仍然会有不错的结果
逻辑回归为什么慢:受到的特征过多,稀疏矩阵的原因,再线性上比较快
再训练集上:其他算法都是百分之百,但是贝叶斯为什么达不到百分之百,而且还在下降,说明贝叶斯不是一个很好的分类器,而且随着样本量增加,需要学习的东西越来越多,贝叶斯学习能力下降
再过拟合方面:过拟合就是训练集上的表现比测试集上的表现好很多的现象,也就是两条线的差异
总之,如果追求概率的话,再能使用逻辑回归的情况下都会使用逻辑回归,因为当数据量比较大的时候,贝叶斯测试结果已经到了*限,没有调参的空间。数据高维,很多的时候,贝叶斯很快

webrtc android 打包成aar

webrtc android 打包成aar

我的环境:webrtc*新的, ubuntu20.04, python2.7

webrtc android 打包成aar,执行 tools_webrtc/android/release_aar.py –verbose –build-dir out/aar_release  会出现下面一些错误:

Traceback (most recent call last):
File “tools_webrtc/android/release_aar.py”, line 31, in <module>
import requests
ImportError: No module named requests
错误明显是没安装requests,

需要对 src/gedit tools_webrtc/android/release_aar.py 做修改,而且支持python2.7,需要安装pip,再用pip 安装requests,具体怎么安装网上查找实现,

安装好requests后,再执行上面的命令出现如下错误:

INFO:root:Releasing AAR version 1.0.33829 with hash 448d18b18d57871d1030fc8748b34250e48be385
Traceback (most recent call last):
File “tools_webrtc/android/release_aar.py”, line 307, in <module>
sys.exit(main())
File “tools_webrtc/android/release_aar.py”, line 303, in main
ReleaseAar(args.use_goma, args.skip_tests, args.publish, args.build_dir)
File “tools_webrtc/android/release_aar.py”, line 255, in ReleaseAar
‘Environment variables BINTRAY_USER and BINTRAY_API_KEY ‘
Exception: Environment variables BINTRAY_USER and BINTRAY_API_KEY must be defined.
这是需要你验证用户信息,因为发布到api.bintray.com上去需要验证用户信息,但我们现在用不上,解决方法是,修改release_aar.py ,把其他没用的注释掉即可,修改如下:

#!/usr/bin/env python

# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
“””Script for publishing WebRTC AAR on Bintray.
Set BINTRAY_USER and BINTRAY_API_KEY environment variables before running
this script for authentication.
“””

import argparse
import json
import logging
import os
import re
import shutil
import subprocess
import sys
import tempfile
import time

SCRIPT_DIR = os.path.dirname(os.path.realpath(sys.argv[0]))
CHECKOUT_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, os.pardir, os.pardir))

sys.path.append(os.path.join(CHECKOUT_ROOT, ‘third_party’))
import requests
import jinja2

sys.path.append(os.path.join(CHECKOUT_ROOT, ‘tools_webrtc’))
from android.build_aar import BuildAar

ARCHS = [‘armeabi-v7a’, ‘arm64-v8a’, ‘x86’, ‘x86_64’]
MAVEN_REPOSITORY = ‘https://google.bintray.com/webrtc’
API = ‘https://api.bintray.com’
PACKAGE_PATH = ‘google/webrtc/google-webrtc’
CONTENT_API = API + ‘/content/’ + PACKAGE_PATH
PACKAGES_API = API + ‘/packages/’ + PACKAGE_PATH
GROUP_ID = ‘org/webrtc’
ARTIFACT_ID = ‘google-webrtc’
COMMIT_POSITION_REGEX = r’^Cr-Commit-Position: refs/heads/master@{#(\d+)}$’
API_TIMEOUT_SECONDS = 10.0
UPLOAD_TRIES = 3
# The sleep time is increased exponentially.
UPLOAD_RETRY_BASE_SLEEP_SECONDS = 2.0
GRADLEW_BIN = os.path.join(CHECKOUT_ROOT,
‘examples/androidtests/third_party/gradle/gradlew’)
ADB_BIN = os.path.join(CHECKOUT_ROOT,
‘third_party/android_sdk/public/platform-tools/adb’)
AAR_PROJECT_DIR = os.path.join(CHECKOUT_ROOT, ‘examples/aarproject’)
AAR_PROJECT_GRADLE = os.path.join(AAR_PROJECT_DIR, ‘build.gradle’)
AAR_PROJECT_APP_GRADLE = os.path.join(AAR_PROJECT_DIR, ‘app’, ‘build.gradle’)
AAR_PROJECT_DEPENDENCY = “implementation ‘org.webrtc:google-webrtc:1.0.+'”
AAR_PROJECT_VERSION_DEPENDENCY = “implementation ‘org.webrtc:google-webrtc:%s'”

def _ParseArgs():
parser = argparse.ArgumentParser(description=’Releases WebRTC on Bintray.’)
parser.add_argument(‘–use-goma’,
action=’store_true’,
default=False,
help=’Use goma.’)
parser.add_argument(‘–skip-tests’,
action=’store_true’,
default=False,
help=’Skips running the tests.’)
parser.add_argument(
‘–publish’,
action=’store_true’,
default=False,
help=’Automatically publishes the library if the tests pass.’)
parser.add_argument(
‘–build-dir’,
default=None,
help=’Temporary directory to store the build files. If not specified, ‘
‘a new directory will be created.’)
parser.add_argument(‘–verbose’,
action=’store_true’,
default=False,
help=’Debug logging.’)
return parser.parse_args()

def _GetCommitHash():
commit_hash = subprocess.check_output([‘git’, ‘rev-parse’, ‘HEAD’],
cwd=CHECKOUT_ROOT).strip()
return commit_hash

def _GetCommitPos():
commit_message = subprocess.check_output(
[‘git’, ‘rev-list’, ‘–format=%B’, ‘–max-count=1’, ‘HEAD’],
cwd=CHECKOUT_ROOT)
commit_pos_match = re.search(COMMIT_POSITION_REGEX, commit_message,
re.MULTILINE)
if not commit_pos_match:
raise Exception(‘Commit position not found in the commit message: %s’ %
commit_message)
return commit_pos_match.group(1)

def _UploadFile(user, password, filename, version, target_file):
# URL is of format:
# <repository_api>/<version>/<group_id>/<artifact_id>/<version>/<target_file>
# Example:
# https://api.bintray.com/content/google/webrtc/google-webrtc/1.0.19742/org/webrtc/google-webrtc/1.0.19742/google-webrtc-1.0.19742.aar

target_dir = version + ‘/’ + GROUP_ID + ‘/’ + ARTIFACT_ID + ‘/’ + version
target_path = target_dir + ‘/’ + target_file
url = CONTENT_API + ‘/’ + target_path

logging.info(‘Uploading %s to %s’, filename, url)
with open(filename) as fh:
file_data = fh.read()

for attempt in xrange(UPLOAD_TRIES):
try:
response = requests.put(url,
data=file_data,
auth=(user, password),
timeout=API_TIMEOUT_SECONDS)
break
except requests.exceptions.Timeout as e:
logging.warning(‘Timeout while uploading: %s’, e)
time.sleep(UPLOAD_RETRY_BASE_SLEEP_SECONDS**attempt)
else:
raise Exception(‘Failed to upload %s’ % filename)

if not response.ok:
raise Exception(‘Failed to upload %s. Response: %s’ %
(filename, response))
logging.info(‘Uploaded %s: %s’, filename, response)

def _GeneratePom(target_file, version, commit):
env = jinja2.Environment(loader=jinja2.PackageLoader(‘release_aar’), )
template = env.get_template(‘pom.jinja’)
pom = template.render(version=version, commit=commit)
with open(target_file, ‘w’) as fh:
fh.write(pom)

def _TestAAR(tmp_dir, username, password, version):
“””Runs AppRTCMobile tests using the AAR. Returns true if the tests pass.”””
logging.info(‘Testing library.’)
env = jinja2.Environment(loader=jinja2.PackageLoader(‘release_aar’), )

gradle_backup = os.path.join(tmp_dir, ‘build.gradle.backup’)
app_gradle_backup = os.path.join(tmp_dir, ‘app-build.gradle.backup’)

# Make backup copies of the project files before modifying them.
shutil.copy2(AAR_PROJECT_GRADLE, gradle_backup)
shutil.copy2(AAR_PROJECT_APP_GRADLE, app_gradle_backup)

try:
maven_repository_template = env.get_template(‘maven-repository.jinja’)
maven_repository = maven_repository_template.render(
url=MAVEN_REPOSITORY, username=username, password=password)

# Append Maven repository to build file to download unpublished files.
with open(AAR_PROJECT_GRADLE, ‘a’) as gradle_file:
gradle_file.write(maven_repository)

# Read app build file.
with open(AAR_PROJECT_APP_GRADLE, ‘r’) as gradle_app_file:
gradle_app = gradle_app_file.read()

if AAR_PROJECT_DEPENDENCY not in gradle_app:
raise Exception(‘%s not found in the build file.’ %
AAR_PROJECT_DEPENDENCY)
# Set version to the version to be tested.
target_dependency = AAR_PROJECT_VERSION_DEPENDENCY % version
gradle_app = gradle_app.replace(AAR_PROJECT_DEPENDENCY,
target_dependency)

# Write back.
with open(AAR_PROJECT_APP_GRADLE, ‘w’) as gradle_app_file:
gradle_app_file.write(gradle_app)

# Uninstall any existing version of AppRTCMobile.
logging.info(
‘Uninstalling previous AppRTCMobile versions. It is okay for ‘
‘these commands to fail if AppRTCMobile is not installed.’)
subprocess.call([ADB_BIN, ‘uninstall’, ‘org.appspot.apprtc’])
subprocess.call([ADB_BIN, ‘uninstall’, ‘org.appspot.apprtc.test’])

# Run tests.
try:
# First clean the project.
subprocess.check_call([GRADLEW_BIN, ‘clean’], cwd=AAR_PROJECT_DIR)
# Then run the tests.
subprocess.check_call([GRADLEW_BIN, ‘connectedDebugAndroidTest’],
cwd=AAR_PROJECT_DIR)
except subprocess.CalledProcessError:
logging.exception(‘Test failure.’)
return False # Clean or tests failed

return True # Tests pass
finally:
# Restore backups.
shutil.copy2(gradle_backup, AAR_PROJECT_GRADLE)
shutil.copy2(app_gradle_backup, AAR_PROJECT_APP_GRADLE)

def _PublishAAR(user, password, version, additional_args):
args = {
‘publish_wait_for_secs’: 0 # Publish asynchronously.
}
args.update(additional_args)

url = CONTENT_API + ‘/’ + version + ‘/publish’
response = requests.post(url,
data=json.dumps(args),
auth=(user, password),
timeout=API_TIMEOUT_SECONDS)

if not response.ok:
raise Exception(‘Failed to publish. Response: %s’ % response)

def _DeleteUnpublishedVersion(user, password, version):
url = PACKAGES_API + ‘/versions/’ + version
response = requests.get(url,
auth=(user, password),
timeout=API_TIMEOUT_SECONDS)
if not response.ok:
raise Exception(‘Failed to get version info. Response: %s’ % response)

version_info = json.loads(response.content)
if version_info[‘published’]:
logging.info(‘Version has already been published, not deleting.’)
return

logging.info(‘Deleting unpublished version.’)
response = requests.delete(url,
auth=(user, password),
timeout=API_TIMEOUT_SECONDS)
if not response.ok:
raise Exception(‘Failed to delete version. Response: %s’ % response)

def ReleaseAar(use_goma, skip_tests, publish, build_dir):
version = ‘1.0.’ + _GetCommitPos()
commit = _GetCommitHash()
logging.info(‘Releasing AAR version %s with hash %s’, version, commit)

user = os.environ.get(‘BINTRAY_USER’, None)
api_key = os.environ.get(‘BINTRAY_API_KEY’, None)
#if not user or not api_key:
# raise Exception(
# ‘Environment variables BINTRAY_USER and BINTRAY_API_KEY ‘
# ‘must be defined.’)

# If build directory is not specified, create a temporary directory.
use_tmp_dir = not build_dir
if use_tmp_dir:
build_dir = tempfile.mkdtemp()

try:
base_name = ARTIFACT_ID + ‘-‘ + version
aar_file = os.path.join(build_dir, base_name + ‘.aar’)
third_party_licenses_file = os.path.join(build_dir, ‘LICENSE.md’)
pom_file = os.path.join(build_dir, base_name + ‘.pom’)

logging.info(‘Building at %s’, build_dir)
BuildAar(ARCHS,
aar_file,
use_goma=use_goma,
ext_build_dir=os.path.join(build_dir, ‘aar-build’))
_GeneratePom(pom_file, version, commit)

#_UploadFile(user, api_key, aar_file, version, base_name + ‘.aar’)
#_UploadFile(user, api_key, third_party_licenses_file, version,
# ‘THIRD_PARTY_LICENSES.md’)
#_UploadFile(user, api_key, pom_file, version, base_name + ‘.pom’)

tests_pass = skip_tests or _TestAAR(build_dir, user, api_key, version)
if not tests_pass:
logging.info(‘Discarding library.’)
#_PublishAAR(user, api_key, version, {‘discard’: True})
_DeleteUnpublishedVersion(user, api_key, version)
raise Exception(‘Test failure. Discarded library.’)

if publish:
logging.info(‘Publishing library.’)
#_PublishAAR(user, api_key, version, {})
else:
logging.info(
‘Note: The library has not not been published automatically.’
‘ Please do so manually if desired.’)
finally:
if use_tmp_dir:
shutil.rmtree(build_dir, True)

def main():
args = _ParseArgs()
logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
ReleaseAar(args.use_goma, args.skip_tests, args.publish, args.build_dir)

if __name__ == ‘__main__’:
sys.exit(main())
再进入src目下,执行:tools_webrtc/android/release_aar.py –verbose –build-dir out/aar_release

–build-dir是只输出目录

输出结果如下:

INFO:root:Releasing AAR version 1.0.33829 with hash 448d18b18d57871d1030fc8748b34250e48be385
INFO:root:Building at out/aar_release
INFO:root:Building: armeabi-v7a
DEBUG:root:Running: [‘/usr/bin/python’, ‘/home/proj/webrtc_linux/src/third_party/depot_tools/gn.py’, ‘gen’, ‘out/aar_release/aar-build/armeabi-v7a’, ‘–args=arm_version=7 use_goma=false target_cpu=”arm” is_component_build=false is_debug=false rtc_include_tests=false target_os=”android”‘]
Done. Made 5367 targets from 299 files in 5600ms
DEBUG:root:Running: [‘/home/proj/webrtc_linux/src/third_party/depot_tools/ninja’, ‘-C’, ‘out/aar_release/aar-build/armeabi-v7a’, ‘sdk/android:libwebrtc’, ‘sdk/android:libjingle_peerconnection_so’]
ninja: Entering directory `out/aar_release/aar-build/armeabi-v7a’
[3774/3774] STAMP obj/sdk/android/libwebrtc.stamp
INFO:root:Building: arm64-v8a
DEBUG:root:Running: [‘/usr/bin/python’, ‘/home/proj/webrtc_linux/src/third_party/depot_tools/gn.py’, ‘gen’, ‘out/aar_release/aar-build/arm64-v8a’, ‘–args=use_goma=false target_cpu=”arm64″ is_component_build=false is_debug=false rtc_include_tests=false target_os=”android”‘]
Done. Made 5364 targets from 299 files in 1442ms
DEBUG:root:Running: [‘/home/proj/webrtc_linux/src/third_party/depot_tools/ninja’, ‘-C’, ‘out/aar_release/aar-build/arm64-v8a’, ‘sdk/android:libwebrtc’, ‘sdk/android:libjingle_peerconnection_so’]
ninja: Entering directory `out/aar_release/aar-build/arm64-v8a’
[3709/3709] STAMP obj/sdk/android/libwebrtc.stamp
INFO:root:Building: x86
DEBUG:root:Running: [‘/usr/bin/python’, ‘/home/proj/webrtc_linux/src/third_party/depot_tools/gn.py’, ‘gen’, ‘out/aar_release/aar-build/x86’, ‘–args=use_goma=false target_cpu=”x86″ is_component_build=false is_debug=false rtc_include_tests=false target_os=”android”‘]
Done. Made 5383 targets from 301 files in 1083ms
DEBUG:root:Running: [‘/home/proj/webrtc_linux/src/third_party/depot_tools/ninja’, ‘-C’, ‘out/aar_release/aar-build/x86’, ‘sdk/android:libwebrtc’, ‘sdk/android:libjingle_peerconnection_so’]
ninja: Entering directory `out/aar_release/aar-build/x86′
[3896/3896] STAMP obj/sdk/android/libwebrtc.stamp
INFO:root:Building: x86_64
DEBUG:root:Running: [‘/usr/bin/python’, ‘/home/proj/webrtc_linux/src/third_party/depot_tools/gn.py’, ‘gen’, ‘out/aar_release/aar-build/x86_64’, ‘–args=use_goma=false target_cpu=”x64″ is_component_build=false is_debug=false rtc_include_tests=false target_os=”android”‘]
Done. Made 5383 targets from 301 files in 1024ms
DEBUG:root:Running: [‘/home/proj/webrtc_linux/src/third_party/depot_tools/ninja’, ‘-C’, ‘out/aar_release/aar-build/x86_64’, ‘sdk/android:libwebrtc’, ‘sdk/android:libjingle_peerconnection_so’]
ninja: Entering directory `out/aar_release/aar-build/x86_64′
[3892/3892] STAMP obj/sdk/android/libwebrtc.stamp
INFO:root:Collecting common files.
INFO:root:Collecting: armeabi-v7a
INFO:root:Collecting: arm64-v8a
INFO:root:Collecting: x86
INFO:root:Collecting: x86_64
到*后生成的文件如下:

%title插图%num

python – 内置对象 之 自定义函数

python – 内置对象 之 自定义函数

目录

一、自定义函数基础

1.定义一个函数

2.函数调用

3.参数传递

4.函数参数类型

二、函数变量作用域

1.理解变量作用域

2.全局变量与局部变量

三、lambda匿名函数

1.lambda函数定义

2.lambda函数实例

3.lambda函数的特点和使用场景

四、return返回特性

1.return返回元组列表字典

2.return跳出循环或终止执行下面语句

 

一、自定义函数基础
1.定义一个函数
# 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
# 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
# 函数的*行语句可以选择性地使用文档字符串—用于存放函数说明。
# 函数内容以冒号起始,并且缩进。
# return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
2.函数调用
函数名([形参值])
# 形参值指创建函数时要求传入的各个形参的值。注意,创建函数时有多少个形参,那么调用时就需要传入多少个值,且顺序必须和创建函数时一致。即便该函数没有参数,函数名后的小括号也不能省略。
在定义函数时,函数名后面括号中的变量名称叫做形式参数,或者称为形参。
在调用函数时,函数名后面括号中的变量名称叫做实际参数,或者称为实参。
3.参数传递
(1)不可变类型

# 如整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
#!/usr/bin/python

# -*- coding: UTF-8 -*-

def ChangeInt( a ):

a = 10

b = 2

ChangeInt(b)

print(b) # 结果是 2
(2)传可变对象实例

# 如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响
(2)传可变对象实例
# 如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 可写函数说明
def changeme( mylist ):
“修改传入的列表”
mylist.append([1,2,3,4]);
print(“函数内取值: “, mylist)
return

# 调用changeme函数
mylist = [10,20,30];
changeme( mylist );
print(“函数外取值: “, mylist)
# 函数内取值: [10, 20, 30, [1, 2, 3, 4]]
# 函数外取值: [10, 20, 30, [1, 2, 3, 4]]
4.函数参数类型
# 必备参数 # 关键字参数 # 默认参数 # 不定长参数

(1)必备参数

# 必备参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。

def printme( str1,str2 ):
“打印任何传入的字符串”
print(str1,str2);
return;

#调用printme函数
printme(‘john’,’harry’);
(2)关键字参数

# 函数调用使用关键字参数来确定传入的参数值,使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。

def printinfo( name, age ):
“打印任何传入的字符串”
print “Name: “, name;
print “Age “, age;
return;

#调用printinfo函数
printinfo( age=50, name=”miki” );
(3)默认参数

# 调用函数时,默认参数的值如果没有传入,则被认为是默认值。下例会打印默认的age,如果age没有被传入:

def printinfo( name, age = 35 ):
“打印任何传入的字符串”
print “Name: “, name;
print “Age “, age;
return;

#调用printinfo函数
printinfo( age=50, name=”miki” );
printinfo( name=”miki” );
(4)不定长参数:*args 和 **kwargs

元组参数,即 *args,参数格式化存储在一个元组中,长度没有限制,必须位于普通参数和默认参数之后。在函数调用时,*会以单个元素的形式解包一个元祖,使其成为独立的参数。
字典参数,即 **kwargs,参数格式化存储在一个字典中,必须位于参数列表的*后面。**会以键/值对的形式解包一个字典,使其成为独立的关键字参数。
#*args例子
def printinfo( arg1, *vartuple ):
“打印任何传入的参数”
print “输出: ”
print arg1
for var in vartuple:
print var
return;

# 调用printinfo 函数
printinfo( 10 );
printinfo( 70, 60, 50 );
# 输出:
# 10
# 输出:
# 70
# 60
# 50

#**kwargs例子
def print_values(**kwargs):
for key, value in kwargs.items():
print(“The value of {} is {}”.format(key, value))

print_values(my_name=”Sammy”, your_name=”Casey”)

def fun(name, age=1, *args, **kwargs):
print(‘Hello’, name, age, ‘年’) # Hello World 1 年
print(args) # (‘I’, ‘love’, ‘it’)
for i in args:
print(i)
print(kwargs) # {‘my’: ‘jack’, ‘like’: ‘girl’}
for m in kwargs:
print(m, ‘:’, kwargs[m])

fun(‘World’, 1, ‘I’, ‘love’, ‘it’, my=’jack’, like=’girl’)
# 结果:
# Hello World 1 年
# (‘I’, ‘love’, ‘it’)
# I
# love
# it
# {‘my’: ‘jack’, ‘like’: ‘girl’}
# my : jack
# like : girl
(5)关于**kwargs、位置参数、*args、默认参数混用问题:(注意顺序)

# 位置参数、*args、**kwargs三者的顺序必须是:位置参数、*args、**kwargs,否则会出错。
def func(x,*args,**kwargs):
print(‘x = ‘,x)
print(‘args = ‘,args)
print(‘kwargs = ‘,kwargs)

func(1,2,3,4,y=1,a=2,b=3,c=4)
# 结果:
# x = 1
# args = (2, 3, 4)
# kwargs = {‘b’: 3, ‘c’: 4, ‘a’: 2, ‘y’: 1}
位置参数、默认参数、**kwargs的顺序必须为:位置参数、默认参数、**kwargs,否则会报错。

def func(x,y=2,**kwargs):
print(‘x = ‘,x)
print(‘y = ‘,y)
print(‘kwargs = ‘,kwargs)

func(1,y=1,a=2,b=3,c=4)
# 结果为:
x = 1
y = 1
kwargs = {‘c’: 4, ‘a’: 2, ‘b’: 3}
二、函数变量作用域
1.理解变量作用域
(1)变量的作用域

在Python程序中创建、改变、查找变量名时,都是在一个保存变量名的空间中进行,我们称之为命名空间,也被称之为作用域。python的作用域是静态的,在源代码中变量名被赋值的位置决定了该变量能被访问的范围。即Python变量的作用域由变量所在源代码中的位置决定。
(2)作用域的产生

就作用域而言,Python与C有着很大的区别,在Python中并不是所有的语句块中都会产生作用域。只有当变量在Module(模块)、Class(类)、def(函数)中定义的时候,才会有作用域的概念。
需要注意的是:在if-elif-else、for-else、while、try-except\try-finally等关键字的语句块中并不会产成作用域。
(3)作用域的类型

# L (Local) 局部作用域
# E (Enclosing) 闭包函数外的函数中
# G (Global) 全局作用域
# B (Built-in) 内建作用域
(4)查找规则

# 以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。
# 闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
x = int(2.9) # 内建作用域B
g_count = 0 # 全局作用域G
def outer():
o_count = 1 # 闭包函数外的函数中E
def inner():
i_count = 2 # 局部作用域L
2.全局变量与局部变量
# 局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。
# 当内部作用域想修改外部作用域的变量时,就要用到 global 和 nonlocal 关键字了。
(1)修改全局变量

num = 1
def fun1():
global num # 需要使用 global 关键字声明
print(num)
num = 123
print(num)
fun1()
print(num)

# >>>
# 1
# 123
# 123
(2)修改嵌套作用域中的变量

def outer():
num = 10
def inner():
nonlocal num # nonlocal关键字声明
num = 100
print(num)
inner()
print(num)
outer()

# >>>
# 100
# 100
三、lambda匿名函数
1.lambda函数定义
# python 使用 lambda 来创建匿名函数。lambda函数的语法只包含一个语句,如下:
lambda [arg1 [,arg2,…..argn]]:expression
# lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个表达式的值。
# lambda匿名函数的格式:冒号前是参数,可以有多个,用逗号隔开,冒号右边的为表达式。其实lambda返回值是一个函数的地址,也就是函数对象。
2.lambda函数实例
s=lambda x,y:x+y

h=lambda x,y,z:x+y-z

print(s(10,20),h(10,20,50))

 

3.lambda函数的特点和使用场景
(1)特点

# 从函数命名的角度:匿名,直接返回可供调用的值
# 从输入输出的角度:支持多个输入参数,但只支持一个表达式
# 从函数功能的角度:结构简单,无须定义函数名。但所能实现的功能也*其受限。
# 从访问变量的角度:只支持访问lambda自己定义的变量。不支持外部变量访问
# 从运行效率的角度:lambda实际上仍开辟了一个内存单元,并没有提升运行效率
(2)使用场景

# lambda函数复制给变量:减少函数定义的麻烦,同时支持代码复用。
# lambda函数赋值给函数:利用lambda函数实现对已有函数的重新定义。
# 利用lambda函数进行函数嵌套:利用lambda构造嵌套的内部和外部函数,实现闭包编程
# 将lambda函数作为参数传递给其他函数
部分Python内置函数接收函数作为参数。典型的此类内置函数有这些。

filter函数

此时lambda函数用于指定过滤列表元素的条件。

filter(lambda x: x % 3 == 0, [1, 2, 3])

指定将列表[1,2,3]中能够被3整除的元素过滤出来,其结果是[3]。

sorted函数

此时lambda函数用于指定对列表中所有元素进行排序的准则。

sorted([1, 2, 3, 4, 5, 6, 7, 8, 9], key=lambda x: abs(5-x))

将[1, 2, 3, 4, 5, 6, 7, 8, 9]按照与5距离从小到大进行排序,结果是[5, 4, 6, 3, 7, 2, 8, 1, 9]

map函数

此时lambda函数用于指定对列表中每一个元素的共同操作。

如map(lambda x: x+1, [1, 2,3])

将列表[1, 2, 3]中的元素分别加1,其结果[2, 3, 4]。

reduce函数

此时lambda函数用于指定列表中两两相邻元素的结合条件。

reduce(lambda a, b: ‘{}, {}’.format(a, b), [1, 2, 3, 4, 5, 6, 7, 8, 9])

将[1, 2, 3, 4, 5, 6, 7, 8, 9]中元素从左往右两两以逗号分隔的字符的形式依次结合起来,其结果是’1, 2, 3, 4, 5, 6, 7, 8, 9’。

 

四、return返回特性
1.return返回元组列表字典
(1)返回元组

def func():
x=0
y=1
z=2
return x,y #返回元组

print(type(func()))
(2)返回列表

def func():
x=0
y=1
z=2
return [x,y] #返回列表

print(type(func()))
(3)返回字典

def func():
x=0
y=1
z=2
return {x,y} #返回字典

print(type(func()))
2.return跳出循环或终止执行下面语句
执行到return语句时,会退出函数,return之后的语句不再执行,有循环也会跳出循环。但将return语句放在try语句块中,是个例外。
(1)普通情况:遇return退出函数,不执行return之后语句

def test_return(x):
if x > 0:
return x
else:
return 0
(2)有循环也出跳出循环

def test_return(x):
for i in range(x):
if i>=4:
return i
print(i)

test_return(10)
#结果:
#0
#1
#2
#3

def return_y(j):
while j<10:
print(j)
j+=1
if j==3:
return 3
print(return_y(1))
#结果:
1
2
3
(3)try..finally 结构中的return,遇到return后,还是会执行finally中的语句

def func():
try:
print(98)
return ‘ok’ # 函数得到了一个返回值
finally: # finally语句块中的语句依然会执行
print(18)

print(func())
#结果:
#98
#18
#ok
(4)try..finally 结构中各有一个return,*后返回的是finally中的return

def func():
try:
x=0
y=1
z=2
return [x,y] # 函数得到了一个返回值
finally: #finally语句块中的语句依然会执行
print(“last return”)
return {x,z}

print(func())
#结果:
#last return
#{0, 2}

当我们谈深度学习时,我们用它落地了什么?阿里云内容安全功能全新升级

现今伴随人工智能在技术上的不断突破,一些领域如计算机视觉,已开始与各个行业进行了深度融合。例如保险行业已通过人脸识别这种新时代的认证方式,来对用户身份信息进行识别与审核。深度学习对人工智能的发展起着至关重要的影响。

近日,阿里云在深度学习方面动作频频,先后发布了OCR证件识别,声纹检测,人脸搜索,视频鉴黄服务以及相似图片搜索功能,下面小编就一一为大家介绍五大功能应用。

云盾内容安全敏感人脸搜索商业化发布;主要针对教育,学校,以及部分工厂企业,公安对于违法犯罪份子,以及敏感人物,进行1:N识别服务,客户可以增删减建立和管理自己的人脸库,然后对进入监控环境的人进行敏感人物和危险人物的核对使用。

云盾内容安全相似图片搜索商业化发布;主要为图片版权保护的客户提供侵权判定检测服务,用户可以对自己所拥有版权的图片建立图片库,通过客户自有舆情和关注渠道的图片进行比对判定是否侵权。减少外部盗版对正常业务的资损问题。主要面向摄影类平台使用。

云盾内容安全国际视频鉴黄服务;为国内直播短视频出海用户提供海外视频违法检测能力,因为中国公民也受国内法律监管,而色情在海外也有管控要求 为国际用户提供海外视频鉴黄服务,协助客户解决在所在地的内容合规问题

云盾内容安全-OCR证件识别(公测)发布;OCR证件识别是云盾内容安全通过OCR图文结构化识别的技术方式来辨别证件真伪的一个服务,主要是为需要证件核验单位使用,如税务局,民政局等。主要是帮助客户通过机器的方式来判定而不是人肉,提升识别率,降低人力成本

云盾内容安全-声纹1:1(公测)发布;去年,人民的名义大火,落马官员丁义珍伪造证件潜逃出国。通过云盾声纹的对比,对直播,视频内违法人员及敏感人物落马官员等信息进行识别,无处可逃。

python:String-模版替换操作

python:String-模版替换操作

capwords函数

将序列中的每个单词变成首字母大写

def capwords(s, sep=None):
“””capwords(s [,sep]) -> string
Split the argument into words using split, capitalize each
word using capitalize, and join the capitalized words using
join. If the optional second argument sep is absent or None,
runs of whitespace characters are replaced by a single space
and leading and trailing whitespace are removed, otherwise
sep is used to split and join the words.
“””
return (sep or ‘ ‘).join(x.capitalize() for x in s.split(sep))
从源码中我们在return处可以看到是先使用了split进行切割(默认走空格切割),然后在使用join进行结果的合并

栗子:

import string

s = ‘this is old old man’
print(s)

print(string.capwords(s))
运行后的结果如下

this is old old man
This Is Old Old Man

Process finished with exit code 0
从运行结果看,可以清晰的看出原本小写的单词,*后变成首字母大写了…

 

模版

模版拼接也是内置拼接的代替方法,使用string.Template拼接时,要在名字前加前缀$来标识变量(例如:$var),如果要和周围的变量区分的话,那就加一个花括号(例如:${var})。

栗子:

import string

values = {‘var’: 66}

t = string.Template(“””
variable : $var
escape : $var
variable in text : ${var}和我拼接
“””)
print(t.substitute(values))
print(t.safe_substitute(values))
运行后的结果如下

variable : 66
escape : 66
variable in text : 66和我拼接

variable : 66
escape : 66
variable in text : 66和我拼接
从上述结果来看,数据是已经替换成功了,唯一不好的就是数据都是字符型,如果参数的类型需要更换,就得再做一层处理… 具体怎么做可自行动手操作

 

substitute和safe_substitute方法

substitute处理替换时,存在就替换,不存在则抛KeyError错误

safe_substitute处理替换时,存在就替换,不存在就是原参数返回,不会抛错误

栗子:substitute方法

import string

values = {‘var’: 66}

t = string.Template(“””
variable : $var
escape : $var
missing : $missing
variable in text : ${var}和我拼接
“””)
print(t.substitute(values))
运行后的结果如下

Traceback (most recent call last):
File “/Users/lifeng/python-projects/Test/pythonScripts/python_string.py”, line 21, in <module>
print(t.substitute(values))
File “/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/string.py”, line 121, in substitute
return self.pattern.sub(convert, self.template)
File “/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/string.py”, line 114, in convert
return str(mapping[named])
KeyError: ‘missing’
从上述运行结果可以看出,报错是KeyError:’missing’

 

栗子:safe_substitute方法

import string

values = {‘var’: 66}

t = string.Template(“””
variable : $var
escape : $var
missing : $missing
variable in text : ${var}和我拼接
“””)
print(t.safe_substitute(values))
运行后的结果如下

variable : 66
escape : 66
missing : $missing
variable in text : 66和我拼接

Process finished with exit code 0
从上述运行结果看,没有参数替换的参数,就原参数返回,且不会报错

 

 

可能有些时候我们觉得$符号不舒服,想更换一种符号用,那这样我们就可以继承Template进行重写操作

class MyTemplate(string.Template):
delimiter = ‘!’

l = MyTemplate(“””
variable : !var
escape : !var
missing : $missing
variable in text : ${var}和我拼接
“””)
print(l.substitute(values))
在上述代码中我们只是把源码中的delimiter变量的值修改了,运行后的结果如下

上述代码中我们把定界符$符号修改成了!符号,参数替换也是成功的,当然你如果想重写别处代码也是可以的,因为Template这个类本身就有正则表达式,只要源码看得懂那就改起来吧…

 

Python高阶函数原理分析及其应用

Python高阶函数原理分析及其应用

三 高阶函数, 闭包和装饰器
所谓高阶函数就是把函数做为参数传入的一类函数. 另外, 返回函数的函数也属于高阶函数.

3.1 函数做为参数传入另外一个函数
3.1.1 高阶函数引入
Python中函数也是对象:

>>> type(abs)
<class ‘builtin_function_or_method’>

因此也可以将函数赋值给其它变量, 当然该变量也可以像调用函数一样进行使用.

>>> f=abs
>>> type(f)
<class ‘builtin_function_or_method’>
>>> f(-1)

既然函数可以赋值给一个变量, 那么当然也可以*为参数传入另外一个函数进行使用:

>>> def add(f, x, y):
… return f(x)+f(y)

>>> add(abs, -1, -1)

3.1.2 Python内置的高阶函数
map()和filter()是两个内置函数, 它们复制了生成器表达式的功能. 因此它们都返回的是一个迭代器.

3.1.2.1 map()
map(func, *iterables), 由函数声明的原型我们可以看出: map()函数可以接收一个函数和多个可迭代对象.

当只传入一个可迭代对象时, map()的作用就是把函数func逐个施加于可迭代对象的每一个元素, 结果以迭代器返回:
>>> m = map(lambda x: x*x, range(10))
>>> type(m)
<class ‘map’>
>>> from collections.abc import Iterable
>>> from collections.abc import Iterator
>>> isinstance(m, Iterable) # map是可迭代对象
True
>>> isinstance(m, Iterator) # map也是迭代器
True

既然map()返回的是 一个迭代器实例, 因此可以用在for循环中:

>>> for n in m:
… print(n)

0
1
4
9
16
25
36
49
64
81

map()也可以接受多个可迭代对象做为参数:
>>> m=map(lambda x, y: str(x)+str(y), [‘x’]*10, range(10))
>>> list(m)
[‘x0’, ‘x1’, ‘x2’, ‘x3’, ‘x4’, ‘x5’, ‘x6’, ‘x7’, ‘x8’, ‘x9’]

3.1.2.2 filter()
filter(predicate, iterable), 由函数声明原型可知: filter()是将断言应用到可迭代对象的每个元素, 将断言为真的元素以迭代器返回.

>>> def is_even(x): # 判断一个数为偶数
… return x % 2 == 0

>>> list(filter(is_even, range(10)))
[0, 2, 4, 6, 8]

实际上, map()和filter()完成的功能大部分都可以使用列表推断来完成.

3.1.3 其它常用的高阶函数
functools.reduce(func, iterable[, initializer]): 使用一个带有两个参数的函数来累积可迭代对象中的元素, 从左到右进行, *后返回一个计算的值.
>>> reduce(lambda x,y: x*y, [1,2,3,4])
24
>>> reduce(lambda x,y: x+y, [1,2,3,4])
10

3.2 返回函数的函数
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

3.2.1 函数的嵌套
当一个函数定义中又放置了另外的一个函数定义, 那么就构成函数的嵌套定义:

g_var = “hello global variable!” # 全局变量(globa variable)
print(abs) # 内置变量(builtins variable)
def outer():
print(g_var)
e_var=”hello enclosed variable!” # 局部变量(但也称为enclosed variable)
def inner():
print(e_var)
l_val=”hello local variable!” # 局部变量(local variable)
print(l_val)

inner()

outer()

3.2.1.1 变量作用域
有了嵌套函数的定义, 那么就不得不说说Python中变量的作用域, Python中变量的作用域分为四种:

Local variable: 局部作用域, 也就是函数内部定义的变量都是局部变量, 也包含函数的参数.

Enclosed variable: 封闭作用域, 当在一个函数定义中内置了另外一个函数的定义, 那么外层函数中的局部变量就称为封闭作用域变量.

Global variable: 全局作用域, 在模块中定义的变量就是全局变量.

Builtins varable: 在Python builtins中定义的变量. 下面是查看builtins中的定义:

import builtins
>>> dir(builtins)
[‘ArithmeticError’, ‘AssertionError’, ‘AttributeError’, ‘BaseException’, ‘BlockingIOError’, ‘BrokenPipeError’, ‘BufferError’, ‘BytesWarning’, ‘ChildProcessError’, ‘ConnectionAbortedError’, ‘ConnectionError’, ‘ConnectionRefusedError’, ‘ConnectionResetError’, ‘DeprecationWarning’, ‘EOFError’, ‘Ellipsis’, ‘EnvironmentError’, ‘Exception’, ‘False’, ‘FileExistsError’, ‘FileNotFoundError’, ‘FloatingPointError’, ‘FutureWarning’, ‘GeneratorExit’, ‘IOError’, ‘ImportError’, ‘ImportWarning’, ‘IndentationError’, ‘IndexError’, ‘InterruptedError’, ‘IsADirectoryError’, ‘KeyError’, ‘KeyboardInterrupt’, ‘LookupError’, ‘MemoryError’, ‘ModuleNotFoundError’, ‘NameError’, ‘None’, ‘NotADirectoryError’, ‘NotImplemented’, ‘NotImplementedError’, ‘OSError’, ‘OverflowError’, ‘PendingDeprecationWarning’, ‘PermissionError’, ‘ProcessLookupError’, ‘RecursionError’, ‘ReferenceError’, ‘ResourceWarning’, ‘RuntimeError’, ‘RuntimeWarning’, ‘StopAsyncIteration’, ‘StopIteration’, ‘SyntaxError’, ‘SyntaxWarning’, ‘SystemError’, ‘SystemExit’, ‘TabError’, ‘TimeoutError’, ‘True’, ‘TypeError’, ‘UnboundLocalError’, ‘UnicodeDecodeError’, ‘UnicodeEncodeError’, ‘UnicodeError’, ‘UnicodeTranslateError’, ‘UnicodeWarning’, ‘UserWarning’, ‘ValueError’, ‘Warning’, ‘WindowsError’, ‘ZeroDivisionError’, ‘__build_class__’, ‘__debug__’, ‘__doc__’, ‘__import__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘abs’, ‘all’, ‘any’, ‘ascii’, ‘bin’, ‘bool’, ‘breakpoint’, ‘bytearray’, ‘bytes’, ‘callable’, ‘chr’, ‘classmethod’, ‘compile’, ‘complex’, ‘copyright’, ‘credits’, ‘delattr’, ‘dict’, ‘dir’, ‘divmod’, ‘enumerate’, ‘eval’, ‘exec’, ‘exit’, ‘filter’, ‘float’, ‘format’, ‘frozenset’, ‘getattr’, ‘globals’, ‘hasattr’, ‘hash’, ‘help’, ‘hex’, ‘id’, ‘input’, ‘int’, ‘isinstance’, ‘issubclass’, ‘iter’, ‘len’, ‘license’, ‘list’, ‘locals’, ‘map’, ‘max’, ‘memoryview’, ‘min’, ‘next’, ‘object’, ‘oct’, ‘open’, ‘ord’, ‘pow’, ‘print’, ‘property’, ‘quit’, ‘range’, ‘repr’, ‘reversed’, ’round’, ‘set’, ‘setattr’, ‘slice’, ‘sorted’, ‘staticmethod’, ‘str’, ‘sum’, ‘super’, ‘tuple’, ‘type’, ‘vars’, ‘zip’]
1
2
3
3.2.1.2 解释器查找变量的原则
Python解释器查找变量的原则是:L -> E -> G -> B .

分析上述代码中内嵌函数的代码:

def inner():
print(e_var)
l_val=”hello local variable!” # 局部变量(local variable)
print(l_val)

解释器遇到print(e_val)时, 首先在局部作用域(L)中查找, 结果没有定义, 所以就到外层函数定义中查找, 也就是封闭作用域中(E), 因为外层函数中定义了e_val, 所以就可以输出hello enclosed variable!.

def outer():
print(g_var)
e_var=”hello enclosed variable!” # 局部变量(但也称为enclosed variable)
def inner():
print(e_var)
l_val=”hello local variable!” # 局部变量(local variable)
print(l_val)

从上面的示例我们可以得到如下结论:

Python对变量的查找总是始于所在作用域, 如果所在作用域没有定义就会往上一级作用域查找!

下面是一段有问题的代码:

g_var = “hello global variable!”
print(abs)
def outer():
print(g_var)
e_var=”hello enclosed variable!”
def inner():
e_var = e_var + “+ local varialb”
print(e_var)

inner()

outer()

上述代码运行会抛出异常:UnboundLocalError: local variable ‘e_var’ referenced before assignment

异常抛出的位置就在这行代码:e_var = e_var + “+ local varialb”, 原因分析如下:

这就是一条赋值语句. 根据运算符优先级, 先执行等号右侧的字符串+运算, 那么在这里先访问变量e_var, 于是解释器开始在本作用域查找该变量的定义, 如果找不到才会去外曾查找, 但是一定要注意python定义变量就是通过赋值语句完成的, 所以这里其实是有变量的定义, 但是违背了先定义后使用的原则! 因此抛出了异常.

3.2.1.3 作用域提升
所谓变量作用域提升,就是指在嵌套函数中修改封闭作用域中的变量, 以及在封闭作用域中修改全局变量的手段.

nonlocal关键字用于嵌套函数内提升作用域:
g_var = “hello global variable!”
print(abs)
def outer():
print(g_var)
e_var=”hello enclosed variable!”
def inner():
nonlocal e_var
e_var = e_var + “+ local varialb”
print(e_var)

inner()

outer()

上述代码通过nonlocal关键字告诉解释器, 这是在封闭作用域定义的那个e_var, 因此程序就可以正确运行了.

global关键字用于函数中提升局部变量为全局变量:

g_var = “hello global variable!”
print(abs)
def outer():
print(g_var)
e_var=”hello enclosed variable!”
def inner():
global g_var
g_var = g_var + “+ local varialb”
print(g_var)

inner()

outer()

同样的道理, 这里的关键字global用于告诉解释器这里的g_var就是全局作用域定义的.

3.2.2 闭包
简单来说就是一个函数定义中引用了函数外定义的变量,并且该函数可以在其定义环境外被执行。也就是说闭包必须是嵌套函数的定义, 而且内部函数引用了外部函数定义的变量.

def outer():
i = 0
def inner(name):
nonlocal i
i += 1
print(“{} 第 {} 次运行输出”.format(name, i))
return inner

上面代码中在outer函数中又定义了函数inner, 并且内部函数可以访问外部函数的参数或局部变量, 当outer返回函数inner时, 相关的参数和变量都保存在返回的函数中, 这种称为闭包的程序结构具有强大的能力.

添加测试代码如下:


if __name__ == ‘__main__’:

f1 = outer()
f1(‘f1’)
f1(‘f1’)
f1(‘f1’)
f2 = outer()
f2(‘f2’)
f1(‘f1’)
f2(‘f2’)

运行输出:

f1 第 1 次运行输出
f1 第 2 次运行输出
f1 第 3 次运行输出
f2 第 1 次运行输出
f1 第 4 次运行输出
f2 第 2 次运行输出

从这个例子我们可以看出在闭包中, 内层嵌套函数引用的外层变量又如下特定:

外层函数的变量只与具体的闭包关联. 闭包的每个实例引用的外层函数的变量互不干扰.

一个闭包实例对外层变量的修改会被传递到下一次该闭包实例的调用.

3.3 装饰器
闭包又很多应用, 其中装饰器就是一个常用的场景.装饰器的作用通常用于丰富一个已经存在的函数的功能. 尤其是在拿不到原来函数定义的源代码时.

3.3.1 简单的装饰器
比如我们希望每次在调用一个函数时,添加一个日志记录, 通过装饰器来完成, 代码如下:

from datetime import datetime
def log(func):
def wrapper(*args, **kwargs):
print(‘call {}(): at {}’.format(func.__name__, datetime.now()))
return func(*args, **kwargs)
return wrapper

观察上面的log, 因为它接收一个函数做为参数, 并返回一个函数, 在内层函数中, 首先记录了函数调用的时间, 然后再调用该函数. 这就是一个装饰器. 装饰器的使用要通过@语法完成.

@log
def hello():
print(‘hello’)

将@log放置在一个函数前面, 那么这个函数就是一个被装饰的函数了, 它不仅可以完成原有的功能, 而且还具有了装饰器为其添加的功能.

>>> hello()
call hello(): at 2021-05-03 20:44:01.184195
hello

另一方面, 把@log 放置在函数定义处, 相对于执行了语句:

now = log(now)

由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。

wrapper()函数的参数定义是wrapper(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。

3.3.2 带有参数的装饰器
如果装饰器本身需要传入参数, 那就需要编写一个返回装饰器的高阶函数, 写出来会稍微复杂一点. 比如, 带有自定义文本的log装饰器:

def log(text):
def decorator(func):
def wrapper(*args, **kwargs):
print(‘{} call {}(): at {}’.format(text,func.__name__, datetime.now()))
return func(*args, **kwargs)
return wrapper
return decorator

这个带有参数的装饰器使用如下, 首先通过@log(text)来装饰一个函数:

@log(‘execute’)
def hello():
print(‘hello’)

然后执行该函数, 结果如下:

>>> hello()
execute call hello(): at 2021-05-04 07:54:17.025915
hello

和两层嵌套的装饰器相比, 三层嵌套的效果相当于执行下面的语句:

hello=log(‘execute’)(hello)

也就是说, 首先执行log(‘execute’), 返回的是decorator函数, 再调用返回的函数, 参数是hello函数, 返回值*终是wrapper函数.

3.3.3 自定义装饰器的完善
尽管现在我们的装饰器已经能够加强一个函数的功能, 但是还有一个瑕疵, 那就是函数的__name__属性依然能暴露其本来的面目, 这就为依赖函数签名的一些应该留下了隐患.

>>> hello.__name__
‘wrapper’

很明显, 现在函数hello的底层签名依然是wrapper, 而不是hello!

Python的标准模块functools可以帮助我们完成需要的功能, 一个完整的装饰器如下:

import functools
from datetime import datetime

def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(‘{} call {}(): at {}’.format(text,func.__name__, datetime.now()))
return func(*args, **kwargs)
return wrapper
return decorator

@log(‘execute’)
def hello():
print(‘hello’)

测试如下:

>>> hello()
execute call hello(): at 2021-05-04 08:13:22.007876
hello
>>> hello.__name__
‘hello’

python – 内置类型 之 迭代器类型

python – 内置类型 之 迭代器类型

目录

一、迭代器iterator

1.理解迭代器

2.迭代器函数iter和next

3.迭代器运用案例

二、生成器generator

1.理解生成器

2.创建生成器

3.yield函数

 

一、迭代器iterator
1.理解迭代器
(1)什么是迭代器

迭代器也称迭代对象,指可for .. in ..等语句进行循环,这样的过程叫迭代,该对象称为迭代对象
迭代器用于迭代数据,记录每次访问的数据,以及返回下一个数据,用__next__取下一个指向的值
(2)可迭代对象有哪些

列表,元祖,字典,字符串,set集合等都是可迭代对象
(3)通过isinstance()来判断一个对象是否是迭代对象

 

2.迭代器函数iter和next
(1)iter(iterable)

从可迭代对象中返回一个迭代器,iterable必须是能提供一个迭代器的对象
(2)next(iterator)

从迭代器iterator中获取下一了记录,如果无法获取下一条记录,则触发stoptrerator异常
注意:迭代器只能往前取值,不会后退
3.迭代器运用案例
(1)创建迭代器

l = [1,3,5,7]

it = iter(l)

next(it) #1

next(it) #3

next(it) #5

next(it) #7

next(it) #StopIterable 异常

(2)用迭代器轮循列表

l = [2,3,5,7]
it = iter(l)
while True:
try:
x = next(it) #获取一个数据并绑定到x
print(x) #2,3,5,7
except StopIteration:
break
(3)自定义可迭代的类

在类中添加了__iter__方法即取得迭代器
在通过__next__方法指出所有的数据
class Fab(object):
def __init__(self, max):
self.max = max
self.n, self.a, self.b = 0, 0, 1

def __iter__(self):
“””返回一个迭代器”””
return self

def __next__(self):
“””返回迭代器下一个指向的值”””
if self.n < self.max:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.n = self.n + 1
return r
else:
raise StopIteration()

if __name__==’__main__’:
for key in Fab(5):
print(key)
二、生成器generator
1.理解生成器
生成器有什么作用: 省内存

生成器一次只能返回一个值,将大大减小占用内存,而且允许调用函数快速的处理前几个返回值,因此生成器看起来像函数,但表现得却像迭代器
2.创建生成器
(1)把列表的[]改为()就创建generator

lis = [x*x for x in range(10)]
print(lis)
#[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

#生成器
generator_ex = (x*x for x in range(10))
print(generator_ex)
# <generator object <genexpr> at 0x000002A4CBF9EBA0>

使用next(generator_ex)函数获得generator的下一个返回值
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
结果:
0
1
4
每次调用next()就返回generator的下一个值,多次调用next()直到*后一个元素,若再调用next()则抛出StopIteration的错误

所以正确的方法是使用for循环,因为generator也是可迭代对象,所以我们创建一个generator后,基本上永远不会调用next(),而是通过for循环来迭代

#生成器

generator_ex = (x*x for x in range(10))

for i in generator_ex:

print(i)
3.yield函数
yield 函数创建生成器generator。yield相当于 return 返回一个值,并且记住这个返回的位置,下次迭代时,代码从yield的下一条语句开始执行。
send()和next()一样,都能让生成器继续往下走一步(下次遇到yield停),但send()能传一个值,这个值作为yield表达式整体的结果
例子:
def fib(max):
n,a,b =0,0,1
while n < max:
yield b
a,b =b,a+b
n = n+1
return ‘done’
for i in fib(6):
print(i)

结果:
1
1
2
3
5
8

def fib(max):
n,a,b =0,0,1
while n < max:
yield b
a,b =b,a+b
n = n+1
return ‘done’
g = fib(6)
while True:
try:
x = next(g)
print(‘generator: ‘,x)
except StopIteration as e:
print(“生成器返回值:”,e.value)
break

结果:
generator: 1
generator: 1
generator: 2
generator: 3
generator: 5
generator: 8
生成器返回值: done

破解云数据库MongoDB运行变慢指南

阿里云数据库小分队破解了致使云数据库MongoDB运行变慢的原因,*大“祸首”竟是索引。

索引对于数据库来说有多重要?

索引的目的在于提高查询效率,类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql。如果没有索引,那么你可能需要把所有单词看一遍才能找到你想要的,当然数据库的索引要比这个复杂的多。

总的来说,索引的一个主要目的就是加快检索表中数据的方法,也能协助信息搜索者尽快的找到符合限制条件的记录ID的辅助数据结构。

索引的优点无可厚非,但是如果运用不当,就会使数据库运行变慢。用户在使用阿里云数据库MongoDB时,常会因为漏加索引或者使用不恰当的索引,导致数据库性能差,影响业务使用。数据库性能差表现为查询语句慢或超时,CPU使用率高。

基于此,阿里云MongoDB推出了索引推荐功能,帮助用户发现漏加索引或者使用不恰当索引的慢查询,并为这些慢查询提供相应的*优索引,达到提升数据库性能的目标。

在审计日志开通的前提下,可默认生成*近3天(每天0点-24点为一份报告,共3份)的索引诊断报告。超过3天的报告内容不保留。
用户根据自身需求,或监控数据,自定义分析*近3天内任意一个时间段的慢查询及索引推荐报告。

索引推荐操作步骤:
1.登录MongoDB管理控制台,找到目标实例。
2.单击实例ID或者管理进入基本信息页面。
3.在左侧导航栏中,选择CloudDBA->推荐索引查看索引诊断报告列表,如下图所示。
1

4.单击自定义分析打开自定义分析对话框,您可以设置查询时间查看具体时间段内的索引诊断报告。
2

5.单击某个索引列表后的查看详情查看指定索引诊断详情。
3

6.单击上图集合列表后的查询详情,打开分析详情窗口,您可以查看推荐索引以及合并推荐索引等详细信息。
4

据悉,索引推荐功能暂时支持华东1,华东2,华南1,华北1,华北2 五个地域。MongoDB副本集及集群版实例支持索引推荐功能,单节点实例暂不支持。