Python中怎么引用计数,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。回顾内存地址Python中的任何变量都有对应的内存引用,也就是内存地址。如果不是容器类型,那么直接引用和赋值,内存地址都是不会的。>>> a = 1 >>> b = 1 >>> id(a) 140709385600544 >>> id(b) 140709385600544如果在内存中创建了一个list对象(容器),而且对该对象进行了引用。那么b = [1,2]和c = a有什么区别?>>> a = [1,2] >>> b = [1,2] >>> id(a) 1966828025736 >>> id(b) 1966828044488 >>> c = a >>> id(c) 1966828025736首先在内存1966828025736处创建了一个列表 [1,2],然后定义了一个名为a的变量。b = [1,2]会新开一个内存地址,c = a直接赋值直接引用[1,2]的内存地址。引用计数在一些代码中,如果存在一些变量但是没有用,会造成内存空间,因此叫做垃圾,所以要回收。引用计数也是一种最直观,最简单的垃圾收集技术。原理非常简单,每一个对象都包含了两个头部信息,一个是类型标志符,标识这个对象的类型;另一个是计数器,记录当前指向该对象的引用数目,表示这个对象被多少个变量名所引用。CPython 使用引用计数来管理内存,所有 Python 脚本中创建的实例,都会有一个引用计数,来记录有多少个指针指向它。当引用计数只有 0 时,则会自动释放内存。在Python中通过sys.getrefcount查看引用计数的方法,print(sys.getrefcount())注意调用getrefcount()函数会临时增加一次引用计数,得到的结果比预期的多一次。比如,下面这个例子中,a 的引用计数是 3,因为有 a、b 和作为参数传递的 getrefcount 这三个地方,都引用了一个空列表。>>> import sys >>> a = [] >>> b = a >>> print(sys.getrefcount(a)) 3我们通过一些例子来看下,可以使python对象的引用计数增加或减少的场景。import sys a = [] # 两次引用,一次来自 a,一次来自 getrefcount print(sys.getrefcount(a)) def func(a): # 四次引用,a,python 的函数调用栈,函数参数,和 getrefcount print(sys.getrefcount(a)) func(a) # 两次引用,一次来自 a,一次来自 getrefcount,函数 func 调用已经不存在 print(sys.getrefcount(a)) ########## 输出 ########## 2 4 2引用计数是用来记录对象被引用的次数,每当对象被创建或者被引用时将该对象的引用次数加一,当对象的引用被销毁时该对象的引用次数减一,当对象的引用次数减到零时说明程序中已经没有任何对象持有该对象的引用,换言之就是在以后的程序运行中不会再次使用到该对象了,那么其所占用的空间也就可以被释放了了。计数增加和减少下面引用计数增加的场景:对象被创建并赋值给某个变量,比如:a = 'ABC'变量间的相互引用(相当于变量指向了同一个对象),比如:b=a变量作为参数传到函数中。比如:ref_method(a),将对象放到某个容器对象中(列表、元组、字典)。比如:c = [1, a, 'abc']引用计数减少的场景:当一个变量离开了作用域,比如:函数执行完成时,执行方法前后的引用计数保持不变,这就是因为方法执行完后,对象的引用计数也会减少,如果在方法内打印,则能看到引用计数增加的效果。对象的引用变量被销毁时,比如del a或者del b。注意如果del a,再去获取a的引用计数会直接报错。对象被从容器对象中移除,比如:c.remove(a)直接将整个容器销毁,比如:del c对象的引用被赋值给其他对象,相当于变量不指向之前的对象,而是指向了一个新的对象,这种情况,引用计数肯定会发生改变。(排除两个对象默认引用计一致的场景)。import sys def ref_method(str): print(sys.getrefcount(str)) print("我调用了{}".format(str)) print('方法执行完了') def ref_count(): # 引用计数增加的场景 print('测试引用计数增加') a = 'A' print(sys.getrefcount(a)) b = a print(sys.getrefcount(a)) ref_method(a) print(sys.getrefcount(a)) c = [1, a, 'abc'] print(sys.getrefcount(a)) # 引用计数减少的场景 print('测试引用计数减少') del b print(sys.getrefcount(a)) c.remove(a) print(sys.getrefcount(a)) del c print(sys.getrefcount(a)) a = 783 print(sys.getrefcount(a)) if __name__ == '__main__': ref_count() ########## 输出 ########## 测试引用计数增加 78 #77+1 77在函数中是随机的 79 81 我调用了A 方法执行完了 79 80 测试引用计数减少 79 78 78 4关于Python中怎么引用计数问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注辰讯云资讯频道了解更多相关知识。...
今天就跟大家聊聊有关Python中 Collections 模块如何使用,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。collections模块是一个不用不知道,一用就上瘾的模块。这里主要介绍OrderedDict类、defaultdict类、Counter类、namedtuple类和deque类。collectionscollections的常用类型有:计数器(Counter)双向队列(deque)默认字典(defaultdict)有序字典(OrderedDict)可命名元组(namedtuple)Counter计数器(counter)以字典的形式返回序列中各个字符出现的次数,值为key,次数为valueCounter是对字典类型的补充,用于追踪值得出现次数 。import collections counter = collections.Counter("My name is Runsen") print(counter)输出如下Counter({' ': 3, 'n': 3, 'e': 2, 's': 2, 'M': 1, 'y': 1, 'a': 1, 'm': 1, 'i': 1, 'R': 1, 'u': 1})取得元素重复次数的值print(counter[' ']) 3elements()取得计数器中的所有元素。注:此处非所有元素集合,而是包含所有元素集合的迭代器.counter = collections.Counter('abcabcabcdabcdef') print(counter) # 输出如下 Counter({'a': 4, 'b': 4, 'c': 4, 'd': 2, 'e': 1, 'f': 1}) print(counter.elements()) # 输出如下 <itertools.chain object at 0x0000025B1477BF98> print(list(counter.elements())) # 输出如下 ['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'd', 'e', 'f']将Counter按照value从大到小排列,获取前N个元素,需要使用函数most_common# most_common(N)数量从大到小排列,获取前N个元素 print(counter.most_common(3)) # 输出如下 [('a', 4), ('b', 4), ('c', 4)]sorted将Counter中的key进行排序,返回的是所有key的列表# sorted()列出所有不同的元素并排序 print(sorted(counter)) # 输出如下 ['a', 'b', 'c', 'd', 'e', 'f']将Counter转换成字符串,字符串的join方法可以解决。注意不是原来的模样。# 转换成字符串 print(''.join(counter.elements())) # aaaabbbbccccddef print(''.join(list(counter.elements())))update()更新计数器,其实在原本的counter更新计数器,如果原来没有,则新建key,如果有value则加一# update()更新计数器, d = collections.Counter('a') counter.update(d) print(counter) # 输出如下 Counter({'a': 5, 'b': 4, 'c': 4, 'd': 2, 'e': 1, 'f': 1})update()更新计数器,那么subtract()相减计数器的values,即原来的计数器中的每一个元素的数量减去后添加的元素的数量counter.subtract('abdabcabcg') print(counter) # 输出如下 Counter({'a': 2, 'c': 2, 'b': 1, 'd': 1, 'e': 1, 'f': 1, 'g': -1})dequedeque支持从任意一端增加和删除元素。更为常用的两种结构,就是栈和队列。deque的常见操作#定义一个空的双向队列 d = collections.deque() #从右端增加元素 d.extend("Runsen") d.append("Maoli") d.append("Python") d.append("king") #从左端增加元素 d.appendleft('left') print(d) # 输出如下 (注意:extend和append的区别) deque(['left', 'R', 'u', 'n', 's', 'e', 'n', 'Maoli', 'Python', 'king']) # reverse()反转队列 print(d.reverse()) d.reverse() print(d) # 输出如下 None deque(['king', 'Python', 'Maoli', 'n', 'e', 's', 'n', 'u', 'R', 'left']) d.reverse() d.extend(['qq','ww','ee']) print(d) # deque(['left', 'R', 'u', 'n', 's', 'e', 'n', 'Maoli', 'Python', 'king', 'qq', 'ww', 'ee']) # count()计数 print(d.count('R')) # 输出如下 1 # clear()清空队列 d.clear() print(d) # 输出如下 deque([]) # index()取得元素下标 print(d.index('Maoli')) # 输出如下 7 # insert()指定位置插入元素 d.insert(1,'Runsen') print(d) # deque(['left', 'Runsen',R', 'u', 'n', 's', 'e', 'n', 'Maoli', 'Python', 'king', 'qq', 'ww', 'ee'])OrderedDict使用dict时要保持Key的顺序,可以用OrderedDict。from collections import OrderedDict dic = OrderedDict() dic['k1'] = 'v1' dic['k2'] = 'v2' dic['k3'] = 'v3' print(dic) # 输出如下 OrderedDict([('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3')]) # 字典所有的键 print(dic.keys()) # 输出如下 odict_keys(['k1', 'k2', 'k3']) # 字典所有值 print(dic.values()) # 输出如下 odict_values(['v1', 'v2', 'v3']) # items() 方法以列表返回可遍历的(键, 值) 元组数组 print(dic.items()) # 输出如下 odict_items([('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3')]) #pop()方法,删除指定的键值 dic.pop('k1') print(dic) # 输出如下 OrderedDict([('k2', 'v2'), ('k3', 'v3')]) #popitem()方法,默认删除字典最后一个元素 dic.popitem() print(dic) # 输出如下 OrderedDict([('k2', 'v2')]) # update()更新字典 dic.update({'k1':'v1111','k10':'v10'}) print(dic) # 输出如下 OrderedDict([('k2', 'v2'), ('k1', 'v1111'), ('k10', 'v10')])OrderedDict和字典操作完全相同,区别在于OrderedDict的Key会按照插入的顺序排列,不是Key本身排序>>> from collections import OrderedDict >>> d = dict([('a', 1), ('b', 2), ('c', 3)]) >>> d # dict的Key是无序的 {'a': 1, 'c': 3, 'b': 2} >>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)]) >>> od # OrderedDict的Key是有序的 OrderedDict([('a', 1), ('b', 2), ('c', 3)])defaultdict在使用字典的时候, 如果在使用不存在的key的时候发生KeyError这样的一个报错, 这时候就该defaultdict登场了。defaultdict接受一个工厂函数作为参数来构造:dict =defaultdict( factory_function)这个factory_function可以是list、set、str等等,作用是当key不存在时,返回的是工厂函数的默认值,比如list对应[ ],str对应的是空字符串,set对应set( ),int对应0,如下举例:from collections import defaultdict dict1 = defaultdict(int) dict2 = defaultdict(set) dict3 = defaultdict(str) dict4 = defaultdict(list) dict1[2] ='two' print(dict1[1]) print(dict2[1]) print(dict3[1]) print(dict4[1]) # 输出如下 0 set() []defaultdict类接受类型名称作为初始化函数的参数,这样使得默认值的取值更加灵活。s = 'mynameisrunsen' d = collections.defaultdict(int) for k in s: d[k] += 1 print(d) # 输出如下 defaultdict(<class 'int'>, {'m': 2, 'y': 1, 'n': 3, 'a': 1, 'e': 2, 'i': 1, 's': 2, 'r': 1, 'u': 1})练习有如下值集合 [11,22,33,44,55,66,77,88,99,99]。下面将所有大于 55的值保存至字典的第一个key中,将小于 55 的值保存至第二个key的值中。下面通过defaultdict默认字典对列表进行划分。all_list = [11,22,33,44,55,66,77,88,99] dic = collections.defaultdict(list) for i in all_list: if i > 55: dic['k1'].append(i) else: dic['k2'].append(i) print(dic) # 输出如下 defaultdict(<class 'list'>, {'k2': [11, 22, 33, 44, 55], 'k1': [66, 77, 88, 99]})也可以使用字典,具体代码如下。all_list = [11,22,33,44,55,66,77,88,99] dic = {} for i in all_list: if i > 55: if "k1" in dic.keys(): dic['k1'].append(i) else: dic['k1'] = [i,] else: if "k2" in dic.keys(): dic['k2'].append(i) else: dic['k2'] = [i,] print(dic) # 输出如下 {'k2': [11, 22, 33, 44, 55], 'k1': [66, 77, 88, 99]}namedtuplenamedtuple是用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素。使用命名元组的步骤:# 将元组封装为一个类,可以通过字段名(属性名)来访问元组中的值 # 支持元组的所有操作 from collections import namedtuple # 1、定义一个类 Runsen = namedtuple('Runsen', ['name','sex','age']) # 2、创建对象 runsen = Runsen("Runsen", "帅男", 21) # 3、获取命名元组的值 print(runsen[1]) # 支持元组的索引取值 print(runsen[-2:]) # 支持切片 print(runsen.name) # 支持通过字段名来取值 # _fields,获取命名元组的所有属性名 print(runsen._fields) # _asdict方法,将元组转化为字典 print(runsen._asdict()) # 输出如下 帅男 ('帅男', 21) Runsen ('name', 'sex', 'age') OrderedDict([('name', 'Runsen'), ('sex', '帅男'), ('age', 21)])看完上述内容,你们对Python中 Collections 模块如何使用有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注辰讯云资讯频道,感谢大家的支持。...
这篇文章将为大家详细讲解有关Python中怎么实现深浅拷贝,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。一、深浅copy 1. 赋值运算l1 = [1, 2, 3, [22, 33]] l2 = l1 l1.append(666) print(l1) # [1, 2, 3, [22, 33], 666] print(l2) # [1, 2, 3, [22, 33], 666]图解:注意:l2 = l1是一个指向,是赋值,和深浅copy无关。 2. 浅copy其实列表是一个一个的槽位,每个槽位存储的是该对象的内存地址#例1. 给大列表添加元素 l1 = [1, 2, 3, [22, 33]] l2 = l1.copy() # 或者下面这种方式,也是浅copy # import copy # l2 = copy.copy(l1) l1.append(666) print(l1) # [1, 2, 3, [22, 33], 666] print(l2) # [1, 2, 3, [22, 33]] #例2. 给小列表添加元素 l1 = [1, 2, 3, [22, 33]] l2 = l1.copy() l1[-1].append(666) print(l1) # [1, 2, 3, [22, 33, 666]] print(l2) # [1, 2, 3, [22, 33, 666]]、 例3. 将l1列表中第一个元素改为6 l1 = [1, 2, 3, [22, 33]] l2 = l1.copy() l1[0] = 6 print(l1) # [6, 2, 3, [22, 33]] print(l2) # [1, 2, 3, [22, 33]]图解:例1例2例3小结:浅copy:会在内存中新开辟一个空间,存放这个copy的列表,但是列表里面的内容还是沿用之前对象的内存地址。 3. 深copyimport copy l1 = [1, 2, 3, [22, 33]] l2 = copy.deepcopy(l1) l1.append(666) print(l1) # [1, 2, 3, [22, 33], 666] print(l2) # [1, 2, 3, [22, 33]]图解:本质如下图:但是python对深copy做了一个优化,将可变的数据类型在内存中重新创建一份,而不可变的数据类型则沿用之前的,所以内存中是下面这样的:关于Python中怎么实现深浅拷贝就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。...
Python中怎么实现突变测试,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。首先,写一个简单的单元测试:import angle def test_twelve(): assert angle.between(12, 00) == 0足够了吗?代码没有 if 语句,所以如果你查看覆盖率:$ coverage run `which pytest`============================= test session starts ==============================platform linux -- Python 3.8.3, pytest-5.4.3, py-1.8.2, pluggy-0.13.1rootdir: /home/moshez/src/mut-mut-testcollected 1 item tests/test_angle.py . [100%] ============================== 1 passed in 0.01s ===============================完美!测试通过,覆盖率为 100%,你真的是一个测试专家。但是,当你使用突变测试时,覆盖率会变成多少?$ mutmut run --paths-to-mutate angle.py<snip>Legend for output:? Killed mutants. The goal is for everything to end up in this bucket.⏰ Timeout. Test suite took 10 times as long as the baseline so were killed.? Suspicious. Tests took a long time, but not long enough to be fatal.? Survived. This means your tests needs to be expanded.? Skipped. Skipped.<snip>⠋ 21/21 ? 5 ⏰ 0 ? 0 ? 16 ? 0天啊,在 21 个突变体中,有 16 个存活。只有 5 个通过了突变测试,但是,这意味着什么呢?对于每个突变测试,mutmut 会修改部分源代码,以模拟潜在的错误,修改的一个例子是将 > 比较更改为 >=,查看会发生什么。如果没有针对这个边界条件的单元测试,那么这个突变将会“存活”:这是一个没有任何测试用例能够检测到的潜在错误。是时候编写更好的单元测试了。很容易检查使用 results 所做的更改:$ mutmut results<snip>Survived ? (16) ---- angle.py (16) ---- 4-7, 9-14, 16-21$ mutmut apply 4$ git diffdiff --git a/angle.py b/angle.pyindex b5dca41..3939353 100644--- a/angle.py+++ b/angle.py@@ -1,6 +1,6 @@ def hours_hand(hour, minutes): hour = hour % 12- base = hour * (360 // 12)+ base = hour / (360 // 12) correction = int((minutes / 60) * (360 // 12)) return base + correction这是 mutmut 执行突变的一个典型例子,它会分析源代码并将运算符更改为不同的运算符:减法变加法。在本例中由乘法变为除法。一般来说,单元测试应该在操作符更换时捕获错误。否则,它们将无法有效地测试行为。按照这种逻辑,mutmut 会遍历源代码仔细检查你的测试。你可以使用 mutmut apply 来应用失败的突变体。事实证明你几乎没有检查过 hour 参数是否被正确使用。修复它:$ git diffdiff --git a/tests/test_angle.py b/tests/test_angle.pyindex f51d43a..1a2e4df 100644--- a/tests/test_angle.py+++ b/tests/test_angle.py@@ -2,3 +2,6 @@ import angle def test_twelve(): assert angle.between(12, 00) == 0++def test_three():+ assert angle.between(3, 00) == 90以前,你只测试了 12 点钟,现在增加一个 3 点钟的测试就足够了吗?$ mutmut run --paths-to-mutate angle.py<snip>⠋ 21/21 ? 7 ⏰ 0 ? 0 ? 14 ? 0看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注辰讯云资讯频道,感谢您对辰讯云的支持。...
本篇内容介绍了“linux下如何制作rootfs”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、分析1. 文件系统简介理论上说一个嵌入式设备如果内核能够运行起来,且不需要运行用户进程的话,是不需要文件系统的,文件系统简单的说就是一种目录结构,由于 linux操作系统的设备在系统中是以文件的形式存在,将这些文件进行分类管理以及提供和内核交互的接口,就形成一定的目录结构也就是文件系统,文件系统是为用户反映系统的一种形式,为用户提供一个检测控制系统的接口。根文件系统,我认为根文件系统就是一种特殊的文件系统,那么根文件系统和普通的文件系统有什么区别呢?由于根文件系统是内核启动时挂在的第一个文件系统,那么根文件系统就要包括Linux启动时所必须的目录和关键性的文件;例如Linux启动时都需要有init目录下的相关文件,在 Linux挂载分区时Linux一定会找/etc/fstab这个挂载文件等,根文件系统中还包括了许多的应用程序bin目录等,任何包括这些Linux 系统启动所必须的文件都可以成为根文件系统。Linux支持多种文件系统,包括ext2、ext3、vfat、ntfs、iso9660、jffs、yaffs、romfs和nfs等,为了对各类文件系统进行统一管理,Linux引入了虚拟文件系统VFS(Virtual File System),为各类文件系统提供一个统一的操作界面和应用编程接口。Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。不同的文件系统类型有不同的特点,因而根据存储设备的硬件特性、系统需求等有不同的应用场合。在嵌入式Linux应用中,主要的存储设备为 RAM(DRAM, SDRAM)和ROM(常采用FLASH存储器),常用的基于存储设备的文件系统类型包括:jffs2, yaffs, cramfs, romfs,ramdisk, ramfs/tmpfs等。2. 基于FLASH的文件系统2.1 Cramfs:Compressed ROM File System•它的速度快,效率高,其只读的特点有利于保护文件系统免受破坏,提高了系统的可靠性。由于以上特性,Cramfs在嵌入式系统中应用广泛。但是它的只读属性同时又是它的一大缺陷,使得用户无法对其内容对进行扩充。Cramfs映像通常是放在Flash中。2.2 jffs2•Jffs2: 日志闪存文件系统版本2 (Journalling Flash FileSystem v2)•主要用于NOR型闪存,基于MTD驱动层,特点是:可读写的、支持数据压缩的、基于哈希表的日志型文件系统,并提供了崩溃/掉电安全保护,提供“写平衡”支持等。•缺点主要是当文件系统已满或接近满时,因为垃圾收集的关系而使jffs2的运行速度大大放慢。jffs不适合用于NAND闪存主要是因为NAND闪存的容量一般较大,这样导致jffs为维护日志节点所占用的内存空间迅速增大,另外,jffs 文件系统在挂载时需要扫描整个FLASH的内容,以找出所有的日志节点,建立文件结构,对于大容量的NAND闪存会耗费大量时间。2.3.yaffs:Yet Another Flash File System•yaffs/yaffs2是专为嵌入式系统使用NAND型闪存而设计的一种日志型文件系统。与jffs2相比,它减少了一些功能(例如不支持数据压缩),所以速度更快,挂载时间很短,对内存的占用较小。另外,它还是跨平台的文件系统,除了Linux和eCos,还支持WinCE, pSOS和ThreadX等。yaffs/yaffs2自带NAND芯片的驱动,并且为嵌入式系统提供了直接访问文件系统的API,用户可以不使用Linux中的MTD与 VFS,直接对文件系统操作。当然,yaffs也可与MTD驱动程序配合使用。•yaffs与yaffs2的主要区别在于,前者仅支持小页(512 Bytes) NAND闪存,后者则可支持大页(2KB) NAND闪存。同时,yaffs2在内存空间占用、垃圾回收速度、读/写速度等方面均有大幅提升。2.4. 网络文件系统NFS (Network File System)NFS是由Sun开发并发展起来的一项在不同机器、不同操作系统之间通过网络共享文件的技术。在嵌入式Linux系统的开发调试阶段,可以利用该技术在主机上建立基于NFS的根文件系统,挂载到嵌入式设备,可以很方便地修改根文件系统的内容。所采用的工具:mkfs.cramfs,mkfs.jffs2,mkfs.yaffshttp://sourceforge.net/projects/cramfs/ http://sourceforge.net/projects/jffs2os/ http://sourceforge.net/projects/yaffs/二、根文件系统的组成1. 根文件系统目录内容简介bin :基本的可执行文件opt :添加的软件包boot :启动时需要的一些文件proc :内核及进程信息的虚拟文件系统dev : 设备文件root:root用户目录etc: 系统配置文件sbin:系统管理的程序home : 用户目录tmp : 临时文件lib : 库文件usr : 应用程序mnt : 挂载文件系统的挂载点var : 存放系统日志或一些服务程序的临时文件2. 嵌入式环境需要移植的目录根文件系统中的每一个顶级目录都有特定的用途和目的 ,但并不是所有的目录在嵌入式环境下都需要,我们只创建需要的一些目录:/bin /sbin /etc /proc /tmp /var /dev /mntLinux根文件系统至少应包括以下几项内容。鸿蒙官方战略合作共建——HarmonyOS技术社区基本的文件系统结构,包含一些必需的目录比如:/dev,/proc,/bin,/etc,/lib,/usr,/tmp等。基本程序运行所需的库函数,如glibc。基本的系统配置文件,比如rc.sysinit,inittab等脚本文件。必要的设备文件支持:/dev/hd*,/dev/tty*,/dev/fd0。基本的应用程序,如sh,ls,cp,mv等。3. 移植需要做的工作把全局配置文件放入/etc目录下。将设备文件信息放入/dev目录下,设备名可以作为符号链接定位在/dev中或/dev子目录中的其他设备存在。操作系统核心定位在/或/boot,若操作系统核心不是作为文件系统的一个文件存在,不应用它。库存放的目录是/lib。存放系统编译后的可执行文件、命令的目录是/bin,/sbin,/usr。三、 默认预置条件1) 交叉编译工具需要预先安装好交叉编译器 ,一口君安装版本是:arm-none-linux-gnueabi-gcc 默认在ubuntu中安装目录是:/home/peng/toolchain/gcc-4.6.4/2) tftp服务器开发板下载内核镜像和设备树需要借助tftp服务器,配置信息如下:peng@ubuntu:~$ cat /etc/default/tftpd-hpa # /etc/default/tftpd-hpa TFTP_USERNAME="tftp" TFTP_DIRECTORY="/tftpboot" TFTP_ADDRESS="0.0.0.0:69" TFTP_OPTIONS="--secure"服务器根目录是**/tftpboot**3) nfs服务器内核启动后挂载文件系统需要通过nfs服务器,nfs服务器设置如下:peng@ubuntu:~$ cat /etc/exports # /etc/exports: the access control list for filesystems which may be exported # to NFS clients. See exports(5). # # Example for NFSv2 and NFSv3: # /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check) # # Example for NFSv4: # /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check) # /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check) # /source/rootfs *(rw,sync,no_subtree_check)四、文件系统制作步骤1、 源码下载我们选择的版本是busybox-1.22.1.tar.bz2下载路径为:http://busybox.net/downloads/2、 解压源码$ tar xvf busybox-1.22.1.tar.bz23、 进入源码目录$ cd busybox-1.22.14、 配置源码选择制作静态库,并设置交互编译工具链的前缀arm-none-linux-gnueabi-如果是其他工具链,按照例子填写即可。$ make menuconfig Busybox Settings ---> Build Options ---> [*] Build BusyBox as a static binary (no shared libs) [ ] Force NOMMU build [ ] Build with Large File Support (for accessing files > 2 GB) (arm-none-linux-gnueabi-) Cross Compiler prefix () Additional CFLAGS5、 编译$ make6、 安装busybox默认安装路径为源码目录下的_install$ make install7、 进入安装目录下默认创建以下4个文件或者文件夹$ cd _install $ ls bin linuxrc sbin usr8、 创建其他需要的目录$ mkdir dev etc mnt proc var tmp sys root9、 添加库我们安装的交叉工具链中有我们所需要的可以在开发板上使用的库, 将其拷贝到_install目录下即可:$ cp /home/linux/toolchain/gcc-4.6.4/arm-arm1176jzfssf-linux-gnueabi/lib/ . -a修改文件权限并删除静态库和共享库文件中的符号表$chmod +w lib $chmod +w lib/* $ rm lib/*.a $ arm-none-linux-gnueabi-strip lib/*删除不需要的库,确保所有库大小不超过8M$ du -mh lib/10、 添加系统启动文件在etc下添加文件inittab,文件内容如下:#this is run first except when booting in single-user mode. ::sysinit:/etc/init.d/rcS # /bin/sh invocations on selected ttys # start an "askfirst" shell on the console (whatever that may be) ::askfirst:-/bin/sh # stuff to do when restarting the init process ::restart:/sbin/init # stuff to do before rebooting ::ctrlaltdel:/sbin/reboot在etc下添加文件fstab,文件内容如下:#device mount-point type options dump fsck order proc /proc proc defaults 0 0 tmpfs /tmp tmpfs defaults 0 0 sysfs /sys sysfs defaults 0 0 tmpfs /dev tmpfs defaults 0 0【注意】这里我们挂载的文件系统有三个proc、sysfs和tmpfs。在内核中proc和sysfs默认都支持,而tmpfs是没有支持的,我们需要确保内核有tmpfs的支持。修改内核配置:$ make menuconfig File systems ---> Pseudo filesystems ---> [*] Virtual memory file system support (former shm fs) [*] Tmpfs POSIX Access Control Lists重新编译内核在etc下创建init.d目录,并在init.d下创建rcS文件,rcS文件内容为:#!/bin/sh # This is the first script called by init process /bin/mount -a 挂载fstab制定的所有文件系统 echo /sbin/mdev > /proc/sys/kernel/hotplug /sbin/mdev -s为rcS添加可执行权限:$ chmod +x init.d/rcS在etc下添加profile文件,文件内容为:#!/bin/sh export HOSTNAME=farsight export USER=root export HOME=root export PS1="[$USER@$HOSTNAME \W]\# " PATH=/bin:/sbin:/usr/bin:/usr/sbin LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH export PATH LD_LIBRARY_PATH mknod dev/console c 5 1 该文件节点是必须的重要:新制作的文件系统尺寸若超出8M,删除不需要的库文件,比如c++库等。11. 测试制作完毕的根文件系统可以让开发板启动后通过nfs挂载到ubuntu中,1.删除原先的/source/rootfs$ sudo rm -rf /source/rootfs2.将我们新建的根文件系统拷贝到/source/rootfs目录下$sudo mkdir /source/rootfs $ sudo cp _install/* /source/rootfs –a3.设置uboot环境变量# setenv serverip 192.168.9.120 # setenv ipaddr 192.168.9.233 # setenv bootcmd tftp 41000000 uImage\;tftp 42000000 exynos4412-fs4412.dtb\;bootm 41000000 – 42000000 #setenv bootargs root=/dev/nfs nfsroot=192.168.9.120:/source/rootfs rw console=ttySAC2,115200 init=/linuxrc ip=192.168.9.233 # saveenv重新启动开发板,查看是否能够正常挂载,功能是否正常五、制作ramdisk文件系统通过NFS测试以后,就可以制作ramdisk文件系统了,具体如下:1、制作一个大小为8M的镜像文件$ cd ~ dd if=/dev/zero of=ramdisk bs=1k count=8192 (ramdsik为8M) If: input file Of: output file2、格式化这个镜像文件为ext2$ mkfs.ext2 -F ramdisk3、在mount下面创建initrd目录作为挂载点$ sudo mkdir /mnt/initrd4、将这个磁盘镜像文件挂载到/mnt/initrd下注意这里的ramdisk不能存放在rootfs目录中$ sudo mount -t ext2 ramdisk /mnt/initrd5、将测试好的文件系统里的内容全部拷贝到 /mnt/initrd目录下面$ sudo cp /source/rootfs/* /mnt/initrd –a如果拷贝遇到错误,需要再次删除不需要的库,比如c++库6、卸载/mnt/initrd$ sudo umount /mnt/initrd7、压缩ramdisk为ramdisk.gz$ gzip --best -c ramdisk > ramdisk.gz8、格式化为uboot识别的格式并拷贝到/tftpboot下$ mkimage -n "ramdisk" -A arm -O linux -T ramdisk -C gzip -d ramdisk.gz ramdisk.img $ cp ramdisk.img /tftpboot9、配置内核支持RAMDISK制作完 initrd.img.gz后,需要配置内核支持RAMDISK作为启动文件系统make menuconfig File systems ---> <*> Second extended fs support Device Drivers SCSI device support ---> <*> SCSI disk support Block devices ---> <*>RAM block device support (16)Default number of RAM disks (8192) Default RAM disk size (kbytes) (修改为8M) General setup ---> [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support重新编译内核,复制到/tftpboot10、在U-BOOT命令行重新设置启动参数:# setenv bootcmd tftp 41000000 uImage\;tftp 42000000 exynos4412-fs4412.dtb\;tftp 43000000 ramdisk.img\;bootm 41000000 43000000 42000000 # saveenv重新启动开发板查看能否正常启动【注意】 因为各个开发板命令会有所差异,uboot命令的设置要厂家出厂的手册操作。“linux下如何制作rootfs”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注辰讯云,小编将为大家输出更多高质量的实用文章!...
这篇文章将为大家详细讲解有关微信小程序组件中如何使用contact-button组件,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。微信小程序组件 contact-buttoncontact-button客服会话按钮,用于在页面上显示一个客服会话按钮,用户点击该按钮后会进入客服会话。属性名类型默认值说明sizeNumber18会话按钮大小,有效值 18-27,单位:pxtypeStringdefault-dark会话按钮的样式类型,有效值 default-dark, default-lightsession-fromString用户从该按钮进入会话时,开发者将收到带上本参数的事件推送。本参数可用于区分用户进入客服会话的来源。示例代码<contact-button type="default-light" size="20" session-from="weapp"> </contact-button>关于“微信小程序组件中如何使用contact-button组件”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。...
本篇文章给大家分享的是有关Spark2.x中SparkContext的原理是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。TaskScheduler初始化、向SparkMaster节点进行Application、及Executor反向注册等(核心);DAGScheduler创建和初始化;SparkUI界面的创建和初始化; 下面我就结合源码详细讲解SparkContext的原理和加载过程,这里说明一下我们生产环境用的是Spark2.x,这里就拿Spark2.2.0的源码进行讲解,这里引用网上的一张SparkContext原理剖析图:一.TaskScheduler: 在源码SparkContext.scala中首先调用函数createTaskScheduler()创建TaskScheduler; 在createTaskScheduler中会根据你的提交模式,分别进行对应模式下的代码,不同的提交模式,会创建不同的TaskScheduler,这里我们以standalone模式进行讲解: 函数createTaskScheduler先去创建一个TaskSchedulerImpl(它其实就是TaskScheduler),然后创建SparkDeploySchedulerBackend(它在底层会受TaskSchedulerImp的控制,实际上负责与Master的注册,Executor的反注册,Task发送到Executor等操作),然后调用TaskSchedulerImpl的initialize()方法,代码如下: 最后一行代码会根据不同的调度策略,调用函数buildPools去创建调度池。 TaskScheduler和DAGScheduler创建完成后,调用TaskScheduler的start()函数启动,其实函数内部是调用了SchedulerBackend的start()函数, start()函数中,先是从spark-submit命令行中获取用户提交的一些参数进行了初始化,比如driverUrl、extraJavaOpts、classPathEntries、libraryPathEntries等,通过这些参数创建ApplicationDescription实例,这个ApplicationDescription非常重要,它代表了当前用户提交的application的一切情况,包括application最大需要多少CPU Core,每个slave上需要多少内存等信息。最后去创建一个APPClient实例,由于这里是Standalone模式所以这里创建一个StandaloneAppClient实例,它负责为application与Spark集群进行通信。它会接收一个Spark Master的URL,以及一个application,和一个集群事件的监听器,以及各种事件发生时监听器的回调函数,如下图: 至此TaskScheduler启动完成,调用waitForRegistration()函数等待注册完成;二、DAGScheduler的创建 DAGScheduler类实现了面向stage的调度机制的高层次的调度层,代码位置: DAGScheduler创建主要干了以下几件事: 1).每个job计算一个stage的DAG(有向无环图),stage是根据action进行划分的; 2).追踪RDD的stage输出,是否写入磁盘或者内存等存储介质中; 3).寻找一个消耗(最优、最小)调度机制来运行job; 4).负责将stage封装成Taskset提交到TaskSchdulerImpl,通过集群来运行一批task,这里注意:每一批task运行相同的代码,只是处理不同部分的数据,这里才体现了分布式计算; 5).负责每个task运行的最佳位置,根据当前缓存状态,将这些最佳位置提交给TaskSchdulerImpl; 6).处理由于shuffle导致文件输出丢失导致的失败,该stage会被重新提交;如果不是由于shuffle内部导致的失败,例如OOM,会被TaskSchdulerImpl处理,多次重试每一个task,如果最后还是不行,取消stage运行,最后整个app挂掉。三、SparkUI的创建 这里是SparkContext初始化的最后一步,调用SparkUI中的函数createLiveUI进行界面的创建,默认绑定了4040端口,能显示Application的运行状态,这里会启动一个jetty服务器来显示网页,代码位置:这里注册一个监听SparkListenerBusts,即所有spark消息SparkListenerEvents 被异步的发送给它. ,这个类主要功能如下: 1).保存有消息队列,负责消息的缓存 2).保存有注册过的listener,负责消息的分发补充下yarn常用的三种调度策略: 1).FIFO Scheduler: 把应用按提交的顺序排成一个队列,这是一个先进先出队列,在进行资源分配的时候,先给队列中最头上的应用进行分配资源,待最头上的应用需求满足后再给下一个分配,以此类推。2).Fair Scheduler: 在Fair调度器中,我们不需要预先占用一定的系统资源,Fair调度器会为所有运行的job动态的调整系统资源。如下图所示,当第一个大job提交时,只有这一个job在运行,此时它获得了所有集群资源;当第二个小任务提交后,Fair调度器会分配一半资源给这个小任务,让这两个任务公平的共享集群资源。3).Capacity Scheduler: 而对于Capacity调度器,有一个专门的队列用来运行小任务,但是为小任务专门设置一个队列会预先占用一定的集群资源,这就导致大任务的执行时间会落后于使用FIFO调度器时的时间。以上就是Spark2.x中SparkContext的原理是什么,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注辰讯云资讯频道。...
MySQL中怎么实现用户与授权,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、用户管理1、用户账号用户的账号由用户名和HOST俩部分组成('USERNAME'@'HOST')HOST的表示:主机名具体IP地址网段/掩码可以使用通配符表示,%和_;192.168.%即表示这个网段的所有主机2、增加删除账号主要:在数据库中修改了用户信息需要执行FLUSH PRIVILEGES;来刷新授权表使其生效创建 MariaDB [mysql]> CREATE USER 'user1'@'192.168.%'; MariaDB [mysql]> CREATE USER 'user2'@'192.168.%' IDENTIFIED BY 'your_password'; MariaDB [mysql]> SELECT user,host,password FROM user; +-------+-----------+-------------------------------------------+ | user | host | password | +-------+-----------+-------------------------------------------+ | root | localhost | *4A54C3F37C03C7FBACE31591D6A8C546F93DF5C5 | | root | centos7 | | | root | 127.0.0.1 | | | root | ::1 | | | | localhost | | | | centos7 | | | user1 | 192.168.% | | | user2 | 192.168.% | *9E72259BA9214F692A85B240647C4D95B0F2E08B | +-------+-----------+-------------------------------------------+删除 MariaDB [mysql]> DROP USER user2@'192.168.%'; MariaDB [mysql]> SELECT user,host,password FROM user; +-------+-----------+-------------------------------------------+ | user | host | password | +-------+-----------+-------------------------------------------+ | root | localhost | *4A54C3F37C03C7FBACE31591D6A8C546F93DF5C5 | | root | centos7 | | | root | 127.0.0.1 | | | root | ::1 | | | | localhost | | | | centos7 | | | user1 | 192.168.% | | +-------+-----------+-------------------------------------------+重命名 MariaDB [mysql]> RENAME USER user1@'192.168.%' TO testuser@'%'; MariaDB [mysql]> SELECT user,host,password FROM mysql.user; +----------+-----------+-------------------------------------------+ | user | host | password | +----------+-----------+-------------------------------------------+ | root | localhost | *4A54C3F37C03C7FBACE31591D6A8C546F93DF5C5 | | root | centos7 | | | root | 127.0.0.1 | | | root | ::1 | | | | localhost | | | | centos7 | | | testuser | % | | +----------+-----------+-------------------------------------------+修改密码 MariaDB [mysql]> SET PASSWORD FOR testuser@'%' =PASSWORD('testpass'); MariaDB [mysql]> SELECT user,host,password FROM mysql.user; +----------+-----------+-------------------------------------------+ | user | host | password | +----------+-----------+-------------------------------------------+ | root | localhost | *4A54C3F37C03C7FBACE31591D6A8C546F93DF5C5 | | root | centos7 | | | root | 127.0.0.1 | | | root | ::1 | | | | localhost | | | | centos7 | | | testuser | % | *00E247AC5F9AF26AE0194B41E1E769DEE1429A29 | +----------+-----------+-------------------------------------------+其他修改密码的方法: UPDATE user SET password=PASSWORD('testpass') WHERE user='testuser'; # mysqladmin -uroot -poldpass password 'newpass'3、破解管理账号密码空数据库的情况下恢复密码 # systemctl stop mariadb # rm -rf /var/lib/mysql/* #删库跑路 # systemctl start mariadb有数据的情况下恢复密码 1)在/etc/my.cnf配置文件的[mydqld]下添加skip-grant-tables和skip-networking参数 2)# systemctl restart mariadb 重启服务 3)执行mysql登录到数据库 4)MariaDB [(none)]> UPDATE mysql.user SET password=PASSWORD('newpassword') WHERE user='root' AND host='localhost'; #更新密码 5)MariaDB [(none)]> FLUSH PRIVILEGES; #刷新授权表 6)退出,修改配置文件,删除skip-grant-tables和skip-networking参数,重启服务也可以在启动mysqld进程时,为其使用如下选项:--skip-grant-tables--skip-networking二、授权管理1、授权语法:GRANT priv_type ON [object_type] priv_level TO user@'%' [IDENTIFIED BY 'password'] [WITH GRANT OPTION];授权时如果用户不存在则创建,所以我们一般不会单独去创建一个用户,而是授权创建一块完成。priv_type 授权类型- SELECT- INSERT- UPDATE- DELETE- CREATE- DROP- INDEX- ALTER- SHOW DATABASES- CREATE TEMPORARY TABLES- LOCK TABLES- CREATE VIEW- SHOW VIEW- CREATE USER- ALL PRIVILEGES 或 ALLobject_type 授权对象- TABLE- FUNCTION- PROCEDUREpriv_level 授权级别- *或*.* 表示所有库- db_name.* 表示指定库中的所有表- db_name.tbl_name 指定库中的指定表- tbl_name 表示当前库的表- db_name.routine_name 表示指定库的函数,存储过程,触发器WITH GRANT OPTION- MAX_QUERIES_PER_HOUR count- MAX_UPDATES_PER_HOUR count- MAX_CONNECTIONS_PER_HOUR count- MAX_USER_CONNECTIONS countMariaDB [school]> GRANT SELECT(stuid,name) ON TABLE school.students TO admin@'%' IDENTIFIED BY 'admin'; #把students表的stuid和name字段的查询权限授权于admin@'%'用户 MariaDB [school]> FLUSH PRIVILEGES; #刷新授权表2、查询授权MariaDB [school]> SHOW GRANTS FOR admin@'%'\G #查看指定用户的权限*************************** 1. row ***************************Grants for admin@%: GRANT USAGE ON *.* TO 'admin'@'%' IDENTIFIED BY PASSWORD '*4ACFE3202A5FF5CF467898FC58AAB1D615029441'*************************** 2. row ***************************Grants for admin@%: GRANT SELECT (stuid, name) ON `school`.`students` TO 'admin'@'%'[root@working ~]# mysql -uadmin -padmin -h292.168.0.7 MariaDB [(none)]> SHOW GRANTS FOR CURRENT_USER()\G #查询自己的权限*************************** 1. row ***************************Grants for admin@%: GRANT USAGE ON *.* TO 'admin'@'%' IDENTIFIED BY PASSWORD '*4ACFE3202A5FF5CF467898FC58AAB1D615029441'*************************** 2. row ***************************Grants for admin@%: GRANT SELECT (stuid, name) ON `school`.`students` TO 'admin'@'%'3、收回授权MariaDB [school]> REVOKE SELECT(stuid) ON school.students FROM admin@'%'; #收回admin@'%'用户对stuid字段的查询权限看完上述内容,你们掌握MySQL中怎么实现用户与授权的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注辰讯云资讯频道,感谢各位的阅读!...
这篇文章将为大家详细讲解有关微信小程序中wx.request如何实现封装,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。看项目代码时发现了下面几点问题:网络请求都写在Page里,每个请求都要重复的写wx.request以及一些基础配置;每个页面里都要处理相同类型的异常;后端返的http status code为200以外时,并不能直接进入fail对应函数进行处理;针对这些问题,首先在项目目录里新建了一个apis的目录,把所有与API请求的东西都放在这个目录里,如下图这样。1. 新建一个request类,对wx.request进行简单封装 在request类里做了以下几件事:在构造函数里创建默认请求的http header,可以在header里配制一些内容,在对应请求方法中如果没有设置header参数,就使用此默认header参数;以get post delete put等方法对request进行封装,在发起网络请求不需要重复的写wx.request({method:xxx})这些代码,只要调用getRequest、postRequest等方法就可以了;在rquest的结果返回处理函数success中,判定服务端返回的状态代码,对于200状态代码的按业务处理成功处理,对于非200的状态码按异常处理。预留统一异常处理函数处理接口,可以通过setErrorHandler来设置统一的异常处理,这样对于一些可以统一处理的异常就不用在业务页面里去重复处理了,例如后端返回401的代码,就可以统一转到登录页面让用户登录了;此request不限定服务提供都,可以是自己开发的业务服务端,也可以用于第三方服务的调用;/** * name: api.js * description: request处理基础类 * author: 徐磊 * date: 2018-5-19 */class request { constructor() { this._header = {} }/** * 设置统一的异常处理 */ setErrorHandler(handler) { this._errorHandler = handler; } /** * GET类型的网络请求 */ getRequest(url, data, header = this._header) { return this.requestAll(url, data, header, 'GET') } /** * DELETE类型的网络请求 */ deleteRequest(url, data, header = this._header) { return this.requestAll(url, data, header, 'DELETE') } /** * PUT类型的网络请求 */ putRequest(url, data, header = this._header) { return this.requestAll(url, data, header, 'PUT') } /** * POST类型的网络请求 */ postRequest(url, data, header = this._header) { return this.requestAll(url, data, header, 'POST') } /** * 网络请求 */ requestAll(url, data, header, method) { return new Promise((resolve, reject) => { wx.request({ url: url, data: data, header: header, method: method, success: (res => { if (res.statusCode === 200) { //200: 服务端业务处理正常结束 resolve(res) } else { //其它错误,提示用户错误信息 if (this._errorHandler != null) { //如果有统一的异常处理,就先调用统一异常处理函数对异常进行处理 this._errorHandler(res) } reject(res) } }), fail: (res => { if (this._errorHandler != null) { this._errorHandler(res) } reject(res) }) }) }) } } export default request2. 新建一个agriknow类 在agriknow里面做了以下几件事:实现所有业务服务调用,如查询所有新闻列表【getNews】,查询所有课程列表【getCourseList】;实现统一的异常处理,并传给request;将服务端返回的结果response转成response.data回传给API调用的地方;/** * name: agriknow.js * description: 农知汇服务器提供的服务 * author: 徐磊 * date: 2018-5-19 */import request from './request.js'class agriknow { constructor() { this._baseUrl = 'https://apis.xxx.xxx.com/dev/apis/train/v1/' this._defaultHeader = { 'data-tupe': 'application/json' } this._request = new request this._request.setErrorHandler(this.errorHander) } /** * 统一的异常处理方法 */ errorHander(res) { console.error(res) } /** * 查询所有新闻列表 */ getNews(page = 1, size = 10) { let data = { page: page, size: size } return this._request.getRequest(this._baseUrl + 'news/client', data).then(res => res.data) } /** * 获取所有课程 */ getCourseList(page = 1, size = 10, key = null) { let data = key != null ? { page: page, size: size, queryValue: key } : { page: page, size: size } return this._request.getRequest(this._baseUrl + '/course/mobile', data).then(res => res.data) } } export default agriknow3. 函数的调用在app中引用argriknowimport agriknow from './apis/agriknow.js'App({ onLaunch: function () { // 展示本地存储能力 var logs = wx.getStorageSync('logs') || [] logs.unshift(Date.now()) wx.setStorageSync('logs', logs) …… ……定义一个类型为agriknow的属性并实例化import agriknow from './apis/agriknow.js'App({ onLaunch: function () { // 展示本地存储能力 var logs = wx.getStorageSync('logs') || [] logs.unshift(Date.now()) wx.setStorageSync('logs', logs) …… …… }, agriknow:new agriknow() })在Page里调用const app = getApp(); Page({ data: { courseData: [], page: 1, size: 10, total: 0 }, onLoad: function () { …… …… wx.startPullDownRefresh() this.getdataList(); }, //查询课程列表 getdataList() { app.agriknow.getCourseList(this.data.page++, this.data.size, '') .then(res => { wx.stopPullDownRefresh() let list = this.data.page > 2 ? this.data.courseData.concat(res.list) : res.list this.setData({ courseData: list }) }) .catch(res => { wx.stopPullDownRefresh() wx.showToast({ title: '出错了!', icon: 'none' }) }) }, //下拉刷新 onPullDownRefresh() { console.log("下拉刷新"); this.getdataList(); }, …… …… })关于“微信小程序中wx.request如何实现封装”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。...
今天就跟大家聊聊有关C语言中怎么定义一个常量,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。通过在C语言里面定义常量,可以避免代码出现魔数。#include <stdio.h>int main(){ const int AMOUNT = 100; int price = 0; printf("please input amount of money:"); scanf("%d",&price); int change = AMOUNT - price; printf("give you back %d yuan.\n",change); return 0; }定义double类型变量#include <stdio.h>int main(){ printf("height in foot and inch please :"); double foot; double inch; scanf("%lf %lf",&foot,&inch); printf("height is:%f meters\n",((foot + inch / 12)* 0.3048)); return 0;// printf("%f\n",10.0/3*3);// return 0;// }看完上述内容,你们对C语言中怎么定义一个常量有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注辰讯云资讯频道,感谢大家的支持。...