Compare commits

..

No commits in common. 'master' and 'master' have entirely different histories.

@ -1,165 +0,0 @@
##### 项目代码:
Copyright (C) 2018 Google Inc.
#
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
#
http://www.apache.org/licenses/LICENSE-2.0
#
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
#!/usr/bin/env bash
Exit when any command fails.
每一文件包含以下项,依次是:
###### 1) 版权copyright statement如Copyright 2008 Google Inc.
###### 2) 许可版本license boilerplate为项目选择合适的许可证版本如Apache 2.0 、BSD 、LGPL 、GPL
当我们使用github或者其它地方的开源项目时候需要注意开源项目的授权协议。
开源不等于免费使用,如果公司使用开源项目时候违反其开源协议,有可能给公司或者个人带来版权纠纷。
使用时候需要慎重阅读开源代码提供者的授权条件。
###### 指定解释器
不管在linux还是在windows下要运行一个python文件比如hello.py的方式一般都是
python ./hello.py。然而有一种方式可以直接运行hello.py文件那就是直接在python文件开头指定所使用的python解释器。然后就可以直接用./hello.py 运行了。在python文件开头指定解释器”的方式有两种。
###### 1.1. 直接指定解释器路径
#!/usr/bin/python
上面这种方式,指定了必须用/usr/bin/python这个解释器来解释本python文件。
当然了,也可以写成
#!/usr/local/python3/bin/python3.4
只要那个路径下有python解释器。
###### 1.2. 指定系统环境变量设定的解释器路径
#!/usr/bin/env python
而这种方式指定了使用linux环境变量$PATH里某个路径下名为python的解释器来解释本python文件。
(注意到开头/usr/bin/env是linux里读写环境变量的一个程序
如果环境变量$PATH的内容是/usr/bin:/usr/local/bin:/usr/local/python3/bin那么上面的注释就意味着会依序寻找这些路径
1. /usr/bin/python
2. /usr/local/bin/python
3. /usr/local/python3/bin/python
第一个存在的路径就会作为python解释器使用。
当然,如果写成这样
#!/usr/bin/env python3
那么查找释器的路径顺序就会变成
1. /usr/bin/python3
2. /usr/local/bin/python3
3. /usr/local/python3/bin/python3
2. 标明本py文件的编码类型比如GBK、UTF-8、UCS2之类。
##### 项目代码:
-*- coding: utf-8 -*-
Copyright 2018 Google LLC. All Rights Reserved.
#
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
#
http://www.apache.org/licenses/LICENSE-2.0
#
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
python文件第二行一般是下面两种之一
-*- coding: utf-8 -*-
或者
coding: utf-8
这一行的意思是告诉python解释器这个文件是以UTF-8方式编码存储的。其实类似文本文件开头的BOM。
对于全文都是ASCII编码的py文件而言这行注释一般没用因为ASCII字符在绝大多数编码存储方式中都是相同的除了UCS2这种
但是如果代码中出现了明文的中文、日文之类非ASCII的字符作为字符串常量或注释他们在不同编码存储方式下在硬盘上的字节流是不同的。
例如下面这段python代码
s = "函数"
如果不告诉Python解释器如何理解这个py文件就会出现乱码。
比如如果py文件实际上是以UTF-8方式存储的就是表格第二行但python解释器却以GBK编码存储去理解它那么这段代码就会出现乱码。那么用print(s) 打印字符串时,就会看到乱码文字了。
##### 项目代码:
def init(self, operating_system, architecture):
"""Constructs a new platform.
Args:
operating_system: OperatingSystem, The OS
architecture: Architecture, The machine architecture.
"""
self.operating_system = operating_system
self.architecture = architecture
Args:
```java
列出每个参数的名字, 并在名字后使用一个冒号和一个空格, 分隔对该参数的描述.如果描述太长超过了单行80字符,使用2或者4个空格的悬挂缩进(与文件其他部分保持一致).
```
##### 样例:
#!usr/bin/env python
-*- coding: utf-8 -*-
def is_prime(num):
"""
Args:
param num: 正整数
return: 是素数返回True不是素数返回False
"""
i = 2
while i < num:
r = num % i
if r == 0:
return False
i += 1
return True

@ -1,11 +1,13 @@
## 概要
对开源项目的学习和使用。我们选择学习在GitHub托管的开源项目<a href="https://github. com/google/python-fire">python-fire</a>
## 开源学习
* 大型项目是一个层次化的知识体系,也是一个技术的宝库。看源码的项目,应该把它使用的一些技术和代码记下来,再去了解这个技术相关的背景知识,功能和它的实现。通过一个大项目,可以学到非常多的技术、知识和技巧,也能看到前人留下的设计思想和处理问题的经验。
* 学习开源项目也可以了解到生产环境的代码规范,脚手架,开发测试和上线发布的运维流程。
* 通过学习增强我们自身的能力,在未来的工作中活学活用。
## 我如何完成任务?
1. 在[任务点](#mission)中选择一个
1. fork自己的分支(点击复刻,在页面左上角)
2. 在自己的分支中参照任务1的markdown文件修改或添加markdown文件。然后把任务完成报告用[markdown](#descriptMD)语言完成。
如果有编写代码,也可以添加到分支中。
3. 每次作出修改应该尽快提交merge请求
4. 跳到第2埠持续修改优化完善
## <h2 id='mission'>任务点:</h2>
1. 掌握git等工具的使用了解github等代码托管平台
@ -20,6 +22,11 @@
7. 体会项目中的动态语言开发过程中的轻盈性,并提高自己的编码水平(努力写出干净. 简洁的python)
## <h2 id='descriptMD'>markdown? </h2>
参考 <a href='http://markdown. p2hp. com/getting-started/'>markdown中文网</a>
### 如何在markdown插入图片
将图片上传到QQ空间微博或者其他的图床平台然后复制图片链接在markdown中使用图片标签或者html \<a\>标签插入图片。
## 小组作业要求

@ -1,120 +0,0 @@
# Python Fire可以做什么
这是一个通过暴露复杂系统内部接口利用管道和CLI来方便测试的工具。
它可以自动扫描module, object, class, function并自动构建管道
Expose functionality to user by archive them in a function / module / object / class / dict
# Python fire 源码分析:
## \_\_main__.py
主要负责import被使用的module或者file将其导入Fire.fire()函数。
## trace.py
此module具有用于跟踪fire执行状况的类。fire的执行被分割为数个步骤它们取值属于如下集合
(INITIAL_COMPONENT,INSTANTIATED_CLASS,CALLED_ROUTINE,CALLED_CALLABLE,ACCESSED_PROPERTY,COMPLETION_SCRIPT,INTERACTIVE_MODE
)
FireTrace由一系列FireTraceElement对象组成内部用list表示。在需要时可以由GetLastHealthyElement().component返回当前被操作的元素。
表示一个fire执行时的操作。一项行动可能是实例化类、调用例程或访问属性。
每个操作fire._CallAndUpdateTrace()都使用参数并产生一个新component。最后一部分由Fire序列化为stdout并由Fire方法返回。如果出现Fire使用错误例如提供的参数不足无法调用
一个函数则该Error将在trace中被capture并且final component将被设定为None。
## inspect.py/inspectutils.py
提供inspection操作的功能支持。也就是对callable对象参数的解析。
主要的核心函数如下:
```
def Py3GetFullArgSpec(fn):
```
内置getfullargspec的替代方法。
其实现使用库的_signature_from_callable()
```
sig = inspect._signature_from_callable( # pylint: disable=protected-access
fn,
skip_bound_arg=True,
follow_wrapper_chains=True,
sigcls=inspect.Signature)
```
## decorators.py
这些decorators为python fire提供函数metadata。
这里的fn是指被调用的函数是fire将准备好的参数传入的终端。
SetParseFn和SetParseFns允许设置被Fire用于解析命令行参数的函数。这些函数将被用于客户端代码。
### SetParseFns(*positional, **named)
设置fire的fns以便在调用被修饰的fn时用于解析参数。
返回一个decorator当应用于函数时它会将元数据添加到函数告诉Fire如何将字符串命令行参数转换为正确的用于调用函数的Python参数。
解析函数应该接受单个字符串参数并向在调用修饰函数时在其位置使用。
## core.py
### _Fire(component, args, parsed_flag_args, context, name=None)
这是python fire的核心部分完成fire程序的核心逻辑。几种参数含义如下
* component: 是fire构建CLI的初始元素可以是module, class, routine, object...
* args: 待component使用的参数序列
* parsed_flag_args: 启动fire的flag定制化一些fire行为
* context: 调用fire时的local和global变量
* name: 可选的名字在interactive模式使用
fire的一般执行过程如下
1. 检查并处理flag(--xxx)
1. 选择当前component作为当前被处理的对象根据参数的类型
* 是class则实例化被使用的class
* 是routine则调用该routine
* 是sequence使用紧接的参数访问sequence
* 否则,尝试用紧接的属性访问该对象
* 否则如果是callable的示例调用
1. 返回上一个步骤重复直到所有args被消耗
当不再能够继续执行时fire将结果序列化后输出。以上就是对fire主要功能的简单描述。其比较具体的实现如下。
我们可以注意到其比较核心的功能需要用到代码分析技术而fire的实现如下
```
is_callable = inspect.isclass(component) or inspect.isroutine(component)
is_callable_object = callable(component) and not is_callable
is_sequence = isinstance(component, (list, tuple))
is_map = isinstance(component, dict) or inspectutils.IsNamedTuple(component)
```
其中主要使用到inspect库的各种isXXX函数。去到这个库的源文件查看可以发现如下十分方便的函数ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction() isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(), isroutine()。
再检视inspect.py文件可以发现大部分的isXXX()的实现用到了python builtins的库函数isinstance()issubclass()getattr()hasattr()...
有了python提供的这些函数就可以实现变量的动态查找和识别然后根据这些变量的不同类别进行不同的操作。
当检测到component是class, routine, callable object时调用_CallAndUpdateTrace()
### _CallAndUpdateTrace()实现
重要部分:
```
# 返回filename, line number
filename, lineno = inspectutils.GetFileAndLine(component)
# 生成当前component的metadata
metadata = decorators.GetMetadata(component)
# fn是在这个阶段工作中被调用的Callable对象
fn = component.__call__ if treatment == 'callable' else component
# 生成fn的parse function
parse = _MakeParseFn(fn, metadata)
# 把被调用fn的参数解析出来把args列表变为
# (varargs, kwargs), remaining_args的形式
(varargs, kwargs), consumed_args, remaining_args, capacity = parse(args)
```
metadata用以描述属性的数据在fire中使用一个<属性,值>的字典存储。
它的生成主要依靠 **getattr()**。 源代码如下:
```
def GetMetadata(fn):
# ...
metadata = getattr(fn, FIRE_METADATA, default)
# ...
```
最后,也是最关键的调用部分,非常直接。我们把已经处理好的(varargs, kwargs)传入:
```
if inspectutils.IsCoroutineFunction(fn):
loop = asyncio.get_event_loop()
component = loop.run_until_complete(fn(*varargs, **kwargs))
else:
component = fn(*varargs, **kwargs)
```

@ -1,127 +0,0 @@
## 使用Fire最简单的方法是在任何Python程序结束时调用fire.Fire()。 这会将程序的全部内容暴露给命令行。
import fire
def hello(name):
return 'Hello {name}!'.format(name=name)
if __name__ == '__main__':
fire.Fire()
从命令行运行程序:
$ python example.py hello World
Hello World!
## 暴露多个命令最简单的方法是编写多个函数然后调用Fire。
import fire
def add(x, y):
return x + y
def multiply(x, y):
return x * y
if __name__ == '__main__':
fire.Fire()
我们可以这样使用它:
$ python example.py add 10 20
30
$ python example.py multiply 10 20
200
## 下面是一个如何使用分组命令创建命令行界面的示例。
class IngestionStage(object):
def run(self):
return 'Ingesting! Nom nom nom...'
class DigestionStage(object):
def run(self, volume=1):
return ' '.join(['Burp!'] * volume)
def status(self):
return 'Satiated.'
class Pipeline(object):
def __init__(self):
self.ingestion = IngestionStage()
self.digestion = DigestionStage()
def run(self):
self.ingestion.run()
self.digestion.run()
if __name__ == '__main__':
fire.Fire(Pipeline)
以下是使用方式:
$ python example.py run
Ingesting! Nom nom nom...
Burp!
$ python example.py ingestion run
Ingesting! Nom nom nom...
$ python example.py digestion run
Burp!
$ python example.py digestion status
Satiated.
1参数的类型取决于它们的值而不是使用它们的函数签名。 您可以从命令行传递任何Python文本数字字符串元组列表字典仅在某些版本的Python中支持集合。只要它们只包含文字您也可以任意嵌套这些集合。
为了演示这个,我们将制作一个小程序,通过这个小程序告诉我们传给它的参数类型:
import fire
fire.Fire(lambda obj: type(obj).__name__)
我们会像这样使用它:
$ python example.py 10
int
$ python example.py 10.0
float
$ python example.py hello
str
$ python example.py '(1,2)'
tuple
$ python example.py [1,2]
list
$ python example.py True
bool
$ python example.py {name: David}
dict
在最后一个例子中,你会注意到裸词会自动替换为字符串。
要注意! 如果你想传递字符串"10"而不是int 10你需要转义或者引用你的引号。 否则Bash将会把你的引用取消并将一个没有引号的10传递给你的Python程序在那里Fire将把它解释为一个数字。
$ python example.py 10
int
$ python example.py "10"
int
$ python example.py '"10"'
str
$ python example.py "'10'"
str
$ python example.py \"10\"
str
要注意! 记住Bash首先处理你的参数然后Fire解析结果。 如果你想将dict {"name""David Bieber"}传递给你的程序,你可以试试这个:
$ python example.py '{"name": "David Bieber"}' # Good! Do this.
dict
$ python example.py {"name":'"David Bieber"'} # Okay.
dict
$ python example.py {"name":"David Bieber"} # Wrong. This is parsed as a string.
str
$ python example.py {"name": "David Bieber"} # Wrong. This isn't even treated as a single argument.
<error>
$ python example.py '{"name": "Justin Bieber"}' # Wrong. This is not the Bieber you're looking for. (The syntax is fine though :))
dict
2rue和False被解析为布尔值。
你也可以通过--flag语法--name和--noname来指定布尔值它们分别将名称设置为True和False。
继续前面的例子,我们可以运行以下任何一个:
$ python example.py --obj=True
bool
$ python example.py --obj=False
bool
$ python example.py --obj
bool
$ python example.py --noobj
bool

@ -1,212 +0,0 @@
# 什么是单元测试?
单元测试(又称为模块测试, Unit Testing是针对程序模块软件设计的最小单位来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中一个单元就是单个程序、函数、过程等对于面向对象编程最小单元就是方法包括基类超类、抽象类、或者派生类子类中的方法。单元测试粒度最小一般由开发人员采用白盒方式来测试主要测试单元是否符合设计。单元测试的主要过程仍是通过给定的输入判断得到的结果是否符合预期的代码结果测试的过程。
# 为什么需要单元测试?
单元测试有以下好处:
1. 确保代码质量。
2. 改善代码设计,难以测试的代码一般是设计不够简洁的代码。
3. 保证重构不会引入新问题,以函数为单位进行重构的时候,只需要重新跑测试就基本可以保证重构没引入新问题。
4. 通过单元测试,可以增强代码的执行与预期一致,增强对于代码的自信。
5. 在测试驱动编程的理念中首先程序员要编写测试程序然后编写可以通过测试的程序。测试程序就是程序的需求说明它能够帮助程序员在开发程序时不偏离需求。TTD[Test-Driven Development]最大的好处就是确保一个程序模块的行为符合我们设计的测试用例。
# 怎么编写单元测试?
对于Python代码而言常用的测试工具有doctest和unittest。doctest是简单一些的模块是检测文档用的。doctet.test_mod函数从一个模块中读取所有文档字符串找出所有看起来像是在交互式解释器中输入的例子的文本之后检查例子是否符合实际要求。在实际工作中为python写单元测试时更加强大和常用的模块是unittest模块unittest基于Java的流行测试框架Junit通过使用unittest我们可以以结构化的方式编写大型而且周详的测试集。
# unittest模块
unittest 模块使用的模式有三种,如下:
## 通过unittest.main()来执行测试用例的方式:
```
import unittest
class UCTestCase(unittest.TestCase):
def setUp(self):
#测试前需执行的操作
.....
def tearDown(self):
#测试用例执行完后所需执行的操作
.....
# 测试用例1
def testCreateFolder(self):
#具体的测试脚本
......
# 测试用例2
def testDeleteFolder(self):
#具体的测试脚本
......
if __name__ == "__main__":
unittest.main()
```
## 通过testsuit来执行测试用例的方式
```
import unittest
# 执行测试的类
class UCTestCase(unittest.TestCase):
def setUp(self):
#测试前需执行的操作
.....
def tearDown(self):
#测试用例执行完后所需执行的操作
.....
# 测试用例1
def testCreateFolder(self):
#具体的测试脚本
......
def testDeleteFolder(self):
# 具体的测试脚本
If __name__ == "__main__":
# 构造测试集, 添加测试用例
suite = unittest.TestSuite()
suite.addTest(UC7TestCase("testCreateFolder"))
suite.addTest(UC7TestCase("testDeleteFolder"))
#执行测试, 构造runner。
runner = unittest.TextTestRunner()
runner.run(suite)
```
## 通过testloader运行测试集
```
import unittest
class TestCase1(unittest.TestCase):
#def setUp(self):
#def tearDown(self):
def testCase1(self):
print 'aaa'
def testCase2(self):
print 'bbb'
class TestCase2(unittest.TestCase):
#def setUp(self):
#def tearDown(self):
def testCase1(self):
print 'aaa1'
def testCase2(self):
print 'bbb1'
if __name__ == "__main__":
#此用法可以同时测试多个类
suite1=unittest.TestLoader().loadTestsFromTestCase(TestCase1)
suite2=unittest.TestLoader().loadTestsFromTestCase(TestCase2)
suite = unittest.TestSuite([suite1, suite2])
unittest.TextTestRunner(verbosity=2).run(suite)
```
# Mock和MagicMock
在单元测试进行的同时就离不开mock模块的存在初次接触这个概念的时候会有这样的疑问把要测的东西都模拟掉了还测试什么呢
但在实际生产中的项目是非常复杂的,对其进行单元测试的时候,会遇到以下问题:
1. 接口的依赖
2. 外部接口调用
3. 测试环境非常复杂
单元测试应该只针对当前单元进行测试, 所有的内部或外部的依赖应该是稳定的, 已经在别处进行测试过的。使用mock 就可以对外部依赖组件实现进行模拟并且替换掉, 从而使得单元测试将焦点只放在当前的单元功能。因为在为代码进行单元测试的同时会发现该模块依赖于其他的模块例如数据库网络或者第三方模块的存在而我们对一个模块进行单元测试的目的是测试当前模块正常工作这样就要避开对其他模块的依赖而mock主要作用便在于专注于待测试的代码。而在单元测试中如何灵活的使用mock模块是核心所在。
## mock模块的使用
在mock模块中两个常用的类型为MockMagicMock两个类的关系是MagicMock继承自Mock最重要的两个属性是return_value, side_effect。
```
from mock import Mock
fake_obj = Mock()
fake_obj.return_value = 'This is a mock object'
fake_obj()
'This is a mock object'
```
我们通过Mock()可以创建一个mock对象通过renturn_value 指定它的返回值。即当下文出现fake_obj()会返回其return_value所指定的值。
也可以通过side_effect指定它的副作用这个副作用就是当你调用这个mock对象是会调用的函数,也可以选择抛出一个异常,来对程序的错误状态进行测试。
```
>>>def b():
... print 'This is b'
...
>>>fake_obj.side_effect = b
>>>fake_obj()
This is b
>>>fake_obj.side_effect = KeyError('This is b')
>>>fake_obj()
...
KeyError: 'This is b'
```
如果要模拟一个对象而不是函数你可以直接在mock对象上添加属性和方法并且每一个添加的属性都是一个mock对象也就是说可以对这些属性进行配置,并且可以一直递归的定义下去。
```
fake_obj.fake_a.return_value = 'This is fake_obj.fake_a'
fake_obj.fake_a()
'This is fake_obj.fake_a'
```
上述代码片段中fake_obj是一个mock对象而fake_obj.fake_a的这种形式使得fake_a变成了fake_obj的一个属性作用是在fake_obj.fake_a()调用时会返回其return_value。
另外也可以通过为side_effect指定一个列表这样在每次调用时会依次返回如下
```
fake_obj = Mock(side_effect = [1, 2, 3])
fake_obj()
1
fake_obj()
2
fake_obj()
3
```
## 函数如何mock
在rbd_api.py文件中如下内容
```
import DAO_PoolMgr
def checkpoolstat(pool_name)
ret poolstat = DAO_PoolMgr.DAO_query_ispoolok(pool_name)
if ret != MGR_COMMON.MONGO_SUCCESS:
return ret
if poolstat is False:
return MGR_COMMON.POOL_STAT_ERROR
return MGR_COMMON.SUCCESS
```
要为这个函数撰写单元测试因为其有数据库的操作因而就需要mock 出DAO_query_ispoolok操作。
因此我们在test_rbd_api.py文件中可以这么写因为DAO_query_ispoolok是类DAO_PoolMgr的操作因此可以这么写
```
#!/usr/bin/python
import DAO_PoolMgr
import unittest
import rbd_api as rbdAPI
class TestAuxiliaryFunction(unittest.TestCase):
def setUp(self):
self.pool_name = "aaa"
def tearDown(self):
self.pool_name = None
@mock.patch.object(DAO_PoolMgr, "DAO_query_ispoolok")
def test_checkpoolstat(self, mock_DAO_query_ispoolok):
mock_DAO_query_ispoolok.return_value = (MGR_COMMON.POOL_STAT_ERROR, None)
self.assert(rbdAPI.checkpoolstat(self.pool_name), MGR_COMMON.POOL_STAT_ERROR)
mock_DAO_query_ispoolok.return_value = (MGR_COMMON.SUCCESS, False)
self.assert(rbdAPI.checkpoolstat(self.pool_name), MGR_COMMON.POOL_STAT_ERROR)
mock_DAO_query_ispoolok.return_value = (MGR_COMMON.SUCCESS, True)
self.assert(rbdAPI.checkpoolstat(self.pool_name), MGR_COMMON.SUCCESS)
```
测试用例上的装饰器含义如下:
@mock.pathc.object(类名,“类中函数名”),而如果想要忽略某个测试用例,则可以通过装饰器@unittest.skip(“原因”)
而对于另外一种情形则是在另外一个函数中调用了checkpoolstat函数。
如下rbd_api.py
```
def checkpoolstat():
……
class Disk(Resource):
def __init__(self):
……
def delete(self, pool, img):
ret = rbd_api.checkpoolstat()
……
```
这样我们在为delete函数撰写单元测试时也可以在test_rbd_api.py中使用如下的方式
```
import rbd_api
class TestDisk(unittest.TestCase):
def setup():
def teardown():
@mock.patch(“rbd_api.checkpoolstat”, Mock(return_value = True))
def test_delete():
# rbd_api.checkpoolstat 已经成为一个mock对象了调用时返回True
```
此时的装饰器应该为:
@mock.patch(“模块名.函数名”)

@ -1,113 +0,0 @@
##什么是动态语言?
Dynamic Programming Language (动态语言或动态编程语言) 动态语言准确地说是指程序在运行时可以改变其结构新的函数可以被引进已有的函数可以被删除等在结构上的变化。比如众所周知的ECMAScript(JavaScript)便是一个动态语言。除此之外如Ruby、Python等也都属于动态语言而C、C++等语言则不属于动态语言。
为什么说Python是一门动态语言
看下面这个例子:
def choose_class(name):
    if name == 'foo':
        class Foo(object):
            pass
        return Foo     # 返回的是类,不是类的实例
    else:
        class Bar(object):
            pass
        return Bar
不难看出Python是可以实现动态类的创建类在任意代码位置符合正确的书写格式或者给类增加删除属性。因为类也是对象你可以在运行时动态的创建它们就像其他任何对象一样。你可以在函数中创建类使用class关键字即可。
可能你觉得还不够动态因为你仍然需要自己编写整个类的代码。由于类也是对象所以它们必须是通过什么东西来生成的才对。当你使用class关键字时Python解释器自动创建这个对象。但就和Python中的大多数事情一样Python仍然提供给你手动处理的方法。内建函数中有一个名叫type的内建函数这个内建函数古老但强大的函数 它能够让你知道一个对象的类型是什么就像这样
 
>>> MyShinyClass = type('MyShinyClass', (), {})  # 返回一个类对象
>>> print MyShinyClass<class '__main__.MyShinyClass'
>>>> print MyShinyClass()  #  创建一个该类的实例
<__main__.MyShinyClass object at 0x8997cec>另附type使用方法
#type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
##如何动态添加属性?
 ###2.1 添加对象属性
class Obj(object):
def __init__(self):
self.name = '张亚飞'
obj = Obj()
obj.age = 23
print(obj.age)
obj2 = Obj()
print(obj2.age)
由以上代码可知Obj类有两个属性name和age。通过[对象名.属性名]给类对象obj动态添加了对象属性addr而Obj的另一个类对象obj2却不能调用这个属性。
注:通过对象名添加的对象属性,只有这个对象能使用
###2.2 添加类属性
Obj.score = 100
print(obj.score)
print(obj2.score)
 由以上代码可知,通过[类名.属性名]给类Obj动态添加了类属性addrObj的类对象obj和obj2都能调用这个属性
    注:通过类名添加的类属性,这个类的所有对象都能使用
 
##如何动态添加方法?
类中有三种方法,实例方法,静态方法和类方法,三种方法的区别如下:
实例方法需要绑定要一个对象上第一个参数默认使用self会把对象作为第一个参数传递进来
静态方法:使用装饰器@staticmethod进行定义类和对象都可以调用不需要默认参数
类方法:使用装饰器@classmethod进行定义类和对象都可以调用第一个参数默认使用cls会把类作为第一个参数传递进来
from types import MethodType
class Obj(object):
# __slots__ = ('name', 'age')
def __init__(self):
self.name = '张亚飞'
def set_score(self, score):
self.score = score
@staticmethod
def static_func():
print('static_func')
@classmethod
def class_func(cls):
print('class_method')
类中有三种方法,实例方法,静态方法和类方法,三种方法的区别如下:
实例方法需要绑定要一个对象上第一个参数默认使用self会把对象作为第一个参数传递进来
静态方法:使用装饰器@staticmethod进行定义类和对象都可以调用不需要默认参数
类方法:使用装饰器@classmethod进行定义类和对象都可以调用第一个参数默认使用cls会把类作为第一个参数传递进来
# 动态添加实例方法
obj = Obj()
obj.set_score = MethodType(set_score, obj)
obj.set_score(99)
print(obj.score) # 99
obj2.set_score(99) # AttributeError: 'Obj' object has no attribute 'set_score'
由以上代码可知Obj类有一个方法eat()方法。通过[types.MethodType(方法名, 对象名)]给类对象zhangsan动态添加了对象方法run()同理Obj的另一个类对象lisi不能调用这个方法
注:通过对象名添加的对象方法,只有这个对象能使用
# 添加静态方法
Obj.static_func = static_func
Obj.static_func()
obj.static_func()
obj2.static_func()
由以上代码可知,通过[类名.静态方法名]给类Obj动态添加了静态方法static_func()Obj类的Obj对象和obj2对象都能调用这个方法
注:通过类名添加的静态方法,这个类及这个类的所有对象都能使用
# 添加类方法
Obj.class_func = class_func
Obj.class_func()
obj.class_func()
obj2.class_func()
由以上代码可知,通过[类名.类方法名]给类Obj动态添加了类方法class_func()Obj类的obj对象和obj2对象都能调用这个方法
注:通过类名添加的类方法,这个类及这个类的所有对象都能使用
##__slots__的使用
  通过以上内容我们知道如何动态的添加属性和方法。但是如果我们想要限制class的属性该怎么办例如只允许Obj实例添加name和age属性。为了达到这个目的Python允许在定义class的时候定义一个特殊变量__slots__来限制该class能添加的属性。
class Obj(object):
__slots__ = ('name', 'age')
obj = Obj()
obj.name = 'zhangyafei'
obj.age = 23
obj.score = 99 # AttributeError: 'Obj' object has no attribute 'score'
Obj.score = 100
print(obj.score) # 100
obj.score = 99 # AttributeError: 'Obj' object attribute 'score' is read-only
通过以上代码可知__slots__对Obj类的动态添加没有限制而Obj类对象obj不能再动态添加对象属性和方法。
对于__slot__有以下几个需要注意的地方
__slots__只对类对象进行限制不对类进行限制
__slots__不仅限制类对象的属性还限制类对象的方法
__slots__仅对当前类起作用对继承的子类不起作用
在子类中定义__slots__子类允许定义的属性就是自身的__slots__加上父类的__slots__
 

@ -1,52 +0,0 @@
# 实例1 单个函数python 模块名 参数1 参数2
在Common目录下新建一个test_fire.py的模块
import fire
def add(a, b):
count = a + b
return count
if __name__ == '__main__':
fire.Fire(add)
当不接参数时执行python test_fire.py会显示帮助信息
帮助信息里显示了fire.Fire()的参数类型(function)、文件路径、文档字符串、参数用法等信息
加参数运行的结果如下:
注意:两种方法调用,一种是直接跟实参,一种是–形参 实参的形式,为了方便,本文采取第一种
# 实例2 多个函数python 模块名 函数名 参数
import fire
def add(a, b):
count = a + b
return count
def sub(a, b):
result = a - b
return result
if __name__ == '__main__':
fire.Fire()
# 实例3 类(对象) 多个函数python 模块名 函数名 参数
import fire
class Calculator(object):
def add(self, a, b):
count = a + b
return count
def sub(self, a, b):
result = a - b
return result
if __name__ == '__main__':
fire.Fire(Calculator) #这里用类名Calculator或者类的实例化对象Calculator()结果都是一样的

@ -1,142 +0,0 @@
# start## 任务要求
整理一些git工具常用命令以及使用git进行版本管理的方法
1.Git常用命令如下
git init 把当前的目录变成可以管理的git仓库生成隐藏.git文件。
git add XX 把xx文件添加到暂存区去。
git commit m “XX” 提交文件 m 后面的XX是 注释。
git status 查看仓库状态
git diff XX 查看XX文件修改了那些内容
git log 查看历史记录
git reset hard HEAD^ 或者 git reset hard HEAD~ 回退到上一个版本 (如果想回退到100个版本使用git reset hard HEAD~100 )
cat XX 查看XX文件内容
git reflog 查看历史记录的版本号id
git checkout — XX 把XX文件在工作区的修改全部撤销。
git rm XX 删除XX文件
git remote add origin https://github.com/tugenhua0707/testgit 关联一个远程库
git push u(第一次要用-u 以后不需要) origin master 把当前master分支推送到远程库
git clone https://github.com/tugenhua0707/testgit 从远程库中克隆
git checkout b dev 创建dev分支 并切换到dev分支上
git branch 查看当前所有的分支
git checkout master 切换回master分支
git merge dev 在当前的分支上合并dev分支
git branch d dev 删除dev分支
git branch name 创建分支
git stash 把当前的工作隐藏起来 等以后恢复现场后继续工作
git stash list 查看所有被隐藏的文件列表
git stash apply 恢复被隐藏的文件,但是内容不删除
git stash drop 删除文件
git stash pop 恢复文件的同时 也删除文件
git remote 查看远程库的信息
git remote v 查看远程库的详细信息
git push origin master Git会把master分支推送到远程库对应的远程分支上
附git指令大全https://www.jianshu.com/p/93318220cdce
2.git进行版本管理的方法
使用gitee进行版本管理
git是分布式版本控制系统没有中央服务器每个人的电脑是一个完整的版本库这样工作的时候可不需要联网因为版本都在自己电脑上即每个人的电脑都有一个完整的版本库Git 是一个开源的分布式版本控制系统用于敏捷高效地处理任何或小或大的项目。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。Git 与常用的版本控制工具 CVS, Subversion 等不同它采用了分布式版本库的方式不必服务器端软件支持。那么如何实现多人协作呢比如自己在电脑上修改了文件A别人也修改了文件A此时需要把两人之间各自所做的修改推送给对方就可以互相看到对方所做的修改了。
使用Git前需要先建立一个仓库(repository)。您可以使用一个已经存在的目录作为Git仓库或创建一个空目录。
使用当前目录作为Git仓库我们只需使它初始化。
git init
使用我们指定目录作为Git仓库。
git init newrepo
从现在开始我们将假设用户在Git仓库根目录下除非另有说明。
添加新文件
我们有一个仓库但什么也没有可以使用add命令添加文件。
git add filename
可以使用add... 继续添加任务文件。
提交版本
现在我们已经添加了这些文件我们希望它们能够真正被保存在Git仓库。
为此,我们将它们提交到仓库。
git commit -m "Adding files"
如果您不使用-m会出现编辑器来让你写自己的注释信息。
当我们修改了很多文件而不想每一个都add想commit自动来提交本地修改我们可以使用-a标识。
git commit -a -m "Changed some files"
git commit 命令的-a选项可将所有被修改或者已删除的且已经被git管理的文档提交到仓库中。
千万注意,-a不会造成新文件被提交只能修改。
发布版本
我们先从服务器克隆一个库并上传。
git clone ssh://example.com/~/www/project.git
现在我们修改之后可以进行推送到服务器。
git push ssh://example.com/~/www/project.git
取回更新
如果我们按上面的进行push下面命令表示当前分支自动与唯一一个追踪分支进行合并。
git pull
从非默认位置更新到指定的url。
git pull http://git.example.com/project.git
已经超过了五分钟?
删除
如何我们想从资源库中删除文件我们使用rm。
git rm file
分支与合并
分支在本地完成速度快。要创建一个新的分支我们使用branch命令。
git branch test
branch命令不会将我们带入分支只是创建一个新分支。所以我们使用checkout命令来更改分支。
git checkout test
第一个分支,或主分支,被称为"master"。
git checkout master
对其他分支的更改不会反映在主分支上。如果想将更改提交到主分支则需切换回master分支然后使用合并。
git checkout master
git merge test
如果我们想删除分支,我们使用-d标识。
git branch -d test
1下载git,并在c盘中创建相应的文件通过git bash进入并进行操作。
![](/api/attachments/1834153)
2登录gitee.com注册相应的账户并在gui中获得自己的公钥并将其存入gitee账户中。
![](/api/attachments/1834151)]
3创建仓库用于存放本地上传的文件(这里我上传的文件为demo.html)![](/api/attachments/1834154)
(4)最后通过git gui 建立于目标仓库的连接通过push操作将文件上传至gitee目标仓库中。
![](/api/attachments/1834152)
完成了通过git实现版本管理操作

Binary file not shown.
Loading…
Cancel
Save