Jinja2教程循环和条件
欢迎来到我的 Jinja2 教程的第 2 部分。在第 1 部分中,我们了解了 Jinja2 是什么,它的用途是什么,并开始研究模板基础知识。接下来是循环和条件语句,其中包含测试和大量示例! 控制结构
在 Jinja2 中,循环和条件被称为控制结构,因为它们会影响程序的流程。{% 控制结构使用由和%} 字符包围的块。 循环
我们首先要看的结构是循环。
Jinja2 作为一种模板语言不需要广泛的循环类型选择,所以我们只得到for 循环。
For 循环以 开头{% for my_item in my_collection %} 和结尾{% endfor %} 。这与您在 Python 中循环迭代的方式非常相似。
这my_item 是一个循环变量,它将在我们遍历元素时获取值。并且my_collection 是持有对迭代集合的引用的变量的名称。
在循环体内部,我们可以my_item 在其他控制结构中使用变量,比如if 条件,或者简单地使用{{ my_item }} 语句显示它。
好的,但是你会在哪里使用你问的循环?在您的模板中使用单个变量在大多数情况下都可以正常工作,但您可能会发现引入层次结构和循环将有助于抽象您的数据模型。
例如,前缀列表或 ACL 由许多行组成。将这些行表示为单个变量是没有意义的。
最初,您可以使用每行一个变量对特定前缀列表进行建模,如下所示: PL_AS_65003_IN_line1: "permit 10.96.0.0/24" PL_AS_65003_IN_line2: "permit 10.97.11.0/24" PL_AS_65003_IN_line3: "permit 10.99.15.0/24" PL_AS_65003_IN_line4: "permit 10.100.5.0/25" PL_AS_65003_IN_line5: "permit 10.100.6.128/25"
可以在以下模板中使用: # Configuring Prefix List ip prefix-list PL_AS_65003_IN {{ PL_AS_65003_IN_line1 }} {{ PL_AS_65003_IN_line2 }} {{ PL_AS_65003_IN_line3 }} {{ PL_AS_65003_IN_line4 }} {{ PL_AS_65003_IN_line5 }}
渲染结果: # Configuring Prefix List ip prefix-list PL_AS_65003_IN permit 10.96.0.0/24 permit 10.97.11.0/24 permit 10.99.15.0/24 permit 10.100.5.0/25 permit 10.100.6.128/25
这种方法虽然有效,但也存在一些问题。
如果我们想在前缀列表中有更多行,我们必须创建另一个变量,然后再创建一个,以此类推。我们不仅必须将这些新项目添加到我们的数据结构中,模板还必须单独包含所有这些新变量。这是不可维护的,消耗大量时间并且很容易出错。
有一个更好的方法,考虑下面的数据结构: PL_AS_65003_IN: - permit 10.96.0.0/24 - permit 10.97.11.0/24 - permit 10.99.15.0/24 - permit 10.100.5.0/25 - permit 10.100.6.128/25
以及模板渲染前缀列表配置: # Configuring Prefix List ip prefix-list PL_AS_65003_IN {%- for line in PL_AS_65003_IN %} {{ line -}} {% endfor %}
渲染后: # Configuring Prefix List ip prefix-list PL_AS_65003_IN permit 10.96.0.0/24 permit 10.97.11.0/24 permit 10.99.15.0/24 permit 10.100.5.0/25 permit 10.100.6.128/25
如果您仔细观察,您会发现这本质上是对同一事物进行建模,即带有多个条目的前缀列表。但是通过使用列表,我们清楚地说明了我们的意图。即使在视觉上,您也可以立即看出所有缩进的行都属于 PL_AS_65003_IN。
在这里添加前缀列表很简单,我们只需要在块中添加一个新行。此外,我们的模板根本不需要更改。如果我们使用循环来迭代,就像我们在这里所做的那样,遍历这个列表,那么如果我们重新运行渲染,新的行将被拾取。小小的改变,但让事情变得容易多了。
您可能已经注意到这里仍有改进的空间。前缀列表的名称在前缀列表定义和我们的for 循环中是硬编码的。不要害怕,这是我们很快会改进的。 循环遍历字典
现在让我们看看如何遍历字典。我们将再次使用for 循环构造,记住,这就是我们所拥有的!
我们可以使用与迭代列表元素相同的语法,但这里我们将迭代字典键。要检索分配给键的值,我们需要使用下标,即[] 符号。
使用字典而不是列表的一个优点是我们可以使用元素的名称作为参考,这使得检索对象及其值变得更加容易。
假设我们使用 list 来表示我们的接口集合: interfaces: - Ethernet1: description: leaf01-eth51 ipv4_address: 10.50.0.0/31 - Ethernet2: description: leaf02-eth51 ipv4_address: 10.50.0.2/31
没有简单的方法来检索Ethernet2 条目。我们要么必须遍历所有元素并进行键名比较,要么必须求助于高级过滤器。
需要注意的一件事(希望这一点越来越明显)是我们需要花一些时间对数据进行建模,以便于使用。这是您在第一次尝试时很少会做对的事情,所以不要害怕尝试和迭代。
按照我们的示例,我们可以将数据保存在分配给interfaces 字典中键的各个接口上,而不是将它们放在列表中: interfaces: Ethernet1: description: leaf01-eth51 ipv4_address: 10.50.0.0/31 Ethernet2: description: leaf02-eth51 ipv4_address: 10.50.0.2/31
现在我们可以像这样在模板中访问这些数据: {% for intf in interfaces -%} interface {{ intf }} description {{ interfaces[intf].description }} ip address {{ interfaces[intf].ipv4_address }} {% endfor %}
给我们最终结果: interface Ethernet1 description leaf01-eth51 ip address 10.50.0.0/31 interface Ethernet2 description leaf02-eth51 ip address 10.50.0.2/31
这里intf 指的是Ethernet1 和Ethernet2 键。要访问每个接口的属性,我们需要使用interfaces[intf] 符号。
还有另一种迭代字典的方法,我个人更喜欢。items() 我们可以通过使用方法同时检索键和它的值。 {% for iname, idata in interfaces.items() -%} interface {{ iname }} description {{ idata.description }} ip address {{ idata.ipv4_address }} {% endfor %}
最终结果是相同的,但通过使用items() 方法,我们简化了对属性的访问。如果您想递归地迭代深度嵌套的字典,这一点就变得尤为重要。
我还承诺展示如何改进前缀列表示例,这就是它的items() 用武之地。
我们通过使每个前缀列表名称成为字典中的键来对我们的数据结构进行小修改prefix_lists prefix_lists: PL_AS_65003_IN: - permit 10.96.0.0/24 - permit 10.97.11.0/24 - permit 10.99.15.0/24 - permit 10.100.5.0/25 - permit 10.100.6.128/25
我们现在添加外循环迭代字典中的键值对: # Configuring Prefix List {% for pl_name, pl_lines in prefix_lists.items() -%} ip prefix-list {{ pl_name }} {%- for line in pl_lines %} {{ line -}} {% endfor -%} {% endfor %}
渲染给我们同样的结果: # Configuring Prefix List ip prefix-list PL_AS_65003_IN permit 10.96.0.0/24 permit 10.97.11.0/24 permit 10.99.15.0/24 permit 10.100.5.0/25 permit 10.100.6.128/25
在这里,不再有对前缀列表名称的硬编码引用!如果您需要另一个前缀列表,您只需将其添加到字典中,它就会被我们的循环prefix_lists 自动拾取。for
注意: 如果您使用的是 Python < 3.6 的版本,则不订购字典。这意味着您记录数据的顺序可能与模板内处理项目的顺序不同。
如果您依赖于它们被记录的顺序,您应该collections.OrderedDict 在 Python 脚本中使用 Jinja2 时使用,或者您可以dictsort 在模板中应用过滤器以按键或值对字典进行排序。
按键排序: {% for k, v in my_dict | dictsort -%}
按值排序: {% for k, v in my_dict | dictsort(by="value") -%}
这就结束了 Jinja2 模板中循环的基础知识。上述用例应满足您 95% 的需求。
如果您正在寻找与循环相关的一些高级功能的讨论,请放心,我也会写这些内容。我决定在本教程的最后几章留下更深入的 Jinja2 主题,并专注于让您更快地提高工作效率的核心内容。 条件和测试
现在我们已经完成了循环,是时候继续讨论条件了。
Jinja2 实现了一种条件语句,即if 语句。对于分支,我们可以使用elif and else 。
Jinja2 中的条件可以以几种不同的方式使用。现在,我们将看看一些用例以及它们如何与其他语言特性相结合。 比较
我们首先要看的是将值与条件进行比较,这些使用==, !=, >, >=, <, <= 运算符。这些都是相当标准的,但我还是会展示一些例子。
使用比较的一种常见情况是根据已安装操作系统的版本或供应商改变命令语法。例如,前段时间 Arista 由于诉讼而不得不更改一些命令,我 们可以使用一个简单的 if 语句来确保我们的模板适用于所有 EOS 版本:
使用 EOS 4.19 的主机模板、变量和渲染模板: (venv) przemek@quasar:~/nauto/jinja/python$ python j2_render.py -t templates/eos-ver.j2 -f vars/eos-ver-419.yml -d yaml ############################################################################### # Loaded template: templates/eos-ver.j2 ############################################################################### hostname {{ hostname }} {% if eos_ver >= 4.22 -%} Detected EOS ver {{ eos_ver }}, using new command syntax. {% else -%} Detected EOS ver {{ eos_ver }}, using old command syntax. {% endif %} ############################################################################### # Render variables ############################################################################### eos_ver: 4.19 hostname: arista_old_eos ############################################################################### # Rendered template ############################################################################### hostname arista_old_eos Detected EOS ver 4.19, using old command syntax.
运行 EOS 4.22 的设备也是如此: (venv) przemek@quasar:~/nauto/jinja/python$ python j2_render.py -t templates/eos-ver.j2 -f vars/eos-ver-422.yml -d yaml ############################################################################### # Loaded template: templates/eos-ver.j2 ############################################################################### hostname {{ hostname }} {% if eos_ver >= 4.22 -%} Detected EOS ver {{ eos_ver }}, using new command syntax. {% else -%} Detected EOS ver {{ eos_ver }}, using old command syntax. {% endif %} ############################################################################### # Render variables ############################################################################### eos_ver: 4.22 hostname: arista_new_eos ############################################################################### # Rendered template ############################################################################### hostname arista_new_eos Detected EOS ver 4.22, using new command syntax.
非常简单,但非常有用。我们所做的只是检查记录的 EOS 版本是否小于或大于/等于 4.22,这足以确保正确的语法使其进入配置。
为了通过比较显示更复杂的分支,我在这里提供了支持多种路由协议的模板示例,其中仅为每个设备生成相关配置。
首先我们为主机定义一些数据。
运行 BGP 的设备: hostname: router-w-bgp routing_protocol: bgp interfaces: Loopback0: ip: 10.0.0.1 mask: 32 bgp: as: 65001
运行 OSPF 的设备: hostname: router-w-ospf routing_protocol: ospf interfaces: Loopback0: ip: 10.0.0.2 mask: 32 ospf: pid: 1
仅具有默认路由的设备: hostname: router-w-defgw interfaces: Ethernet1: ip: 10.10.0.10 mask: 24 default_nh: 10.10.0.1
然后我们使用带有分支的条件创建一个模板。可以根据需要轻松添加其他协议选择。 hostname {{ hostname }} ip routing {% for intf, idata in interfaces.items() -%} interface {{ intf }} ip address {{ idata.ip }}/{{ idata.mask }} {%- endfor %} {% if routing_protocol == "bgp" -%} router bgp {{ bgp.as }} router-id {{ interfaces.Loopback0.ip }} network {{ interfaces.Loopback0.ip }}/{{ interfaces.Loopback0.mask }} {%- elif routing_protocol == "ospf" -%} router ospf {{ ospf.pid }} router-id {{ interfaces.Loopback0.ip }} network {{ interfaces.Loopback0.ip }}/{{ interfaces.Loopback0.mask }} area 0 {%- else -%} ip route 0.0.0.0/0 {{ default_nh }} {%- endif %}
所有设备的渲染结果: hostname router-w-bgp ip routing interface Loopback0 ip address 10.0.0.1/32 router bgp 65001 router-id 10.0.0.1 network 10.0.0.1/32 hostname router-w-ospf ip routing interface Loopback0 ip address 10.0.0.2/32 router ospf 1 router-id 10.0.0.2 network 10.0.0.2/32 area 0 hostname router-w-defgw ip routing interface Ethernet1 ip address 10.10.0.10/24 ip route 0.0.0.0/0 10.10.0.1
有了它,一个模板支持 3 种不同的配置选项,非常酷。 逻辑运算符
没有逻辑运算符,条件的实现是不完整的。Jinja2 以and, or and not .
的形式提供这些。这里没什么好说的,所以这里只是一个简短的例子,展示了所有这些在行动中的作用: (venv) przemek@quasar:~/nauto/jinja/python$ python j2_render.py -t templates/if-logic-ops.j2 -f vars/if-logic-ops.yml ############################################################################### # Loaded template: templates/if-logic-ops.j2 ############################################################################### {% if x and y -%} Both x and y are True. x: {{ x }}, y: {{ y }} {%- endif %} {% if x or z -%} At least one of x and z is True. x: {{ x }}, z: {{ z }} {%- endif %} {% if not z -%} We see that z is not True. z: {{ z }} {%- endif %} ############################################################################### # Render variables ############################################################################### x: true y: true z: false ############################################################################### # Rendered template ############################################################################### Both x and y are True. x: True, y: True At least one of x and z is True. x: True, z: False We see that z is not True. z: False 真实性
这是查看不同变量类型及其真实性的好地方。与 Python、字符串、列表、字典等的情况一样,如果变量不为空,则它们的计算结果为 True。对于空值,评估结果为 False。
我创建了一个示例来说明非空和空、字符串、列表和字典的真实性: (venv) przemek@quasar:~/nauto/jinja/python$ python j2_render.py -t templates/if-types-truth.j2 -f vars/if-types-truth.yml ############################################################################### # Loaded template: templates/if-types-truth.j2 ############################################################################### {% macro bool_eval(value) -%} {% if value -%} True {%- else -%} False {%- endif %} {%- endmacro -%} My one element list has bool value of: {{ bool_eval(my_list) }} My one key dict has bool value of: {{ bool_eval(my_dict) }} My short string has bool value of: {{ bool_eval(my_string) }} My empty list has bool value of: {{ bool_eval(my_list_empty) }} My empty dict has bool value of: {{ bool_eval(my_dict_empty) }} My empty string has bool value of: {{ bool_eval(my_string_empty) }} ############################################################################### # Render variables ############################################################################### { "my_list": [ "list-element" ], "my_dict": { "my_key": "my_value" }, "my_string": "example string", "my_list_empty": [], "my_dict_empty": {}, "my_string_empty": "" } ############################################################################### # Rendered template ############################################################################### My one element list has bool value of: True My one key dict has bool value of: True My short string has bool value of: True My empty list has bool value of: False My empty dict has bool value of: False My empty string has bool value of: False
我个人建议不要测试非布尔类型的真实性。没有多少情况下这可能有用,它可能会使您的意图不明显。如果您只是想检查变量是否存在is defined ,那么我们将很快看到的测试通常是更好的选择。 测试
Jinja2 中的测试与变量一起使用并返回 True 或 False,具体取决于值是否通过测试。要使用此功能is ,请在变量后添加和测试名称。
最有用的测试是defined 我已经提到的。该测试仅检查给定变量是否已定义,即渲染引擎是否可以在接收到的数据中找到它。
检查是否定义了变量是我在大多数模板中使用的。请记住,默认情况下未定义的变量只会计算为空字符串。通过检查变量是否在其预期用途之前定义,您可以确保您的模板在渲染期间失败。如果没有这个测试,您可能会以不完整的文档结束,并且没有迹象表明有什么不对劲。
我发现方便的另一类测试用于检查变量的类型。某些操作要求两个操作数的类型相同,如果它们不是 Jinja2 将抛出错误。这适用于比较数字或迭代列表和字典之类的事情。
boolean - 检查变量是否为布尔值
integer - 检查变量是否为整数
float - 检查变量是否为浮点数
number - 检查变量是否为数字,整数和浮点数均返回 True
string - 检查变量是否为字符串
mapping - 检查变量是否为映射, 即字典
iterable - 检查变量是否可以迭代,将匹配字符串、列表、字典等
sequence - 检查变量是否为序列
以下是应用了这些测试的一些变量的示例: (venv) przemek@quasar:~/nauto/jinja/python$ python j2_render.py -t templates/tests-type.j2 -f vars/tests-type.yml ############################################################################### # Loaded template: templates/tests-type.j2 ############################################################################### {{ hostname }} is an iterable: {{ hostname is iterable }} {{ hostname }} is a sequence: {{ hostname is sequence }} {{ hostname }} is a string: {{ hostname is string }} {{ eos_ver }} is a number: {{ eos_ver is number }} {{ eos_ver }} is an integer: {{ eos_ver is integer }} {{ eos_ver }} is a float: {{ eos_ver is float }} {{ bgp_as }} is a number: {{ bgp_as is number }} {{ bgp_as }} is an integer: {{ bgp_as is integer }} {{ bgp_as }} is a float: {{ bgp_as is float }} {{ interfaces }} is an iterable: {{ interfaces is iterable }} {{ interfaces }} is a sequence: {{ interfaces is sequence }} {{ interfaces }} is a mapping: {{ interfaces is mapping }} {{ dns_servers }} is an iterable: {{ dns_servers is iterable }} {{ dns_servers }} is a sequence: {{ dns_servers is sequence }} {{ dns_servers }} is a mapping: {{ dns_servers is mapping }} ############################################################################### # Render variables ############################################################################### { "hostname": "sw-office-lon-01", "eos_ver": 4.22, "bgp_as": 65001, "interfaces": { "Ethernet1": "Uplink to core" }, "dns_servers": [ "1.1.1.1", "8.8.4.4", "8.8.8.8" ] } ############################################################################### # Rendered template ############################################################################### sw-office-lon-01 is an iterable: True sw-office-lon-01 is a sequence: True sw-office-lon-01 is a string: True 4.22 is a number: True 4.22 is an integer: False 4.22 is a float: True 65001 is a number: True 65001 is an integer: True 65001 is a float: False {"Ethernet1": "Uplink to core"} is an iterable: True {"Ethernet1": "Uplink to core"} is a sequence: True {"Ethernet1": "Uplink to core"} is a mapping: True ["1.1.1.1", "8.8.4.4", "8.8.8.8"] is an iterable: True ["1.1.1.1", "8.8.4.4", "8.8.8.8"] is a sequence: True ["1.1.1.1", "8.8.4.4", "8.8.8.8"] is a mapping: False
您可能已经注意到,其中一些测试可能看起来有点模棱两可。例如,要测试变量是否是列表,仅检查它是序列还是可迭代是不够的。字符串也是序列和可迭代对象。字典也是如此,即使 vanilla Python 将它们分类为 Iterable 和 Mapping 而不是 Sequence: >>> from collections.abc import Iterable, Sequence, Mapping >>> >>> interfaces = {"Ethernet1": "Uplink to core"} >>> >>> isinstance(interfaces, Iterable) True >>> isinstance(interfaces, Sequence) False >>> isinstance(interfaces, Mapping) True
那么这一切意味着什么呢?好吧,我建议对每种类型的变量进行以下测试: Number、Float、Integer - 这些都按预期工作,因此请选择适合您用例的任何内容。 字符串 - 使用string 测试就足够了:
{{ my_string is string }} 字典 - 使用mapping 测试就足够了:
{{ my_dict is mapping }} 列表 - 这是一个艰难的,完整的检查应该测试变量是否是一个序列,但同时它不能是一个映射或字符串:
{{ my_list is sequence and my list is not mapping and my list is not string }}
在某些情况下,我们知道字典或字符串不太可能出现,因此我们可以通过摆脱mapping 或string 测试来缩短检查:
{{ my_list is sequence and my list is not string }}
{{ my_list is sequence and my list is not mapping }}
有关可用测试的完整列表,请点击参考资料中的链接。 环路滤波
我想简要介绍的最后一件事是循环过滤和in 运算符。
环路过滤正如其名称所暗示的那样。它允许您使用if 带有循环的语句for 来跳过您不感兴趣的元素。
例如,我们可以遍历包含接口的字典并仅处理具有 IP 地址的接口: (venv) przemek@quasar:~/nauto/jinja/python$ python j2_render.py -t templates/loop-filter.j2 -f vars/loop-filter.yml ############################################################################### # Loaded template: templates/loop-filter.j2 ############################################################################### === Interfaces with assigned IPv4 addresses === {% for intf, idata in interfaces.items() if idata.ipv4_address is defined -%} {{ intf }} - {{ idata.description }}: {{ idata.ipv4_address }} {% endfor %} ############################################################################### # Render variables ############################################################################### { "interfaces": { "Loopback0": { "description": "Management plane traffic", "ipv4_address": "10.255.255.34/32" }, "Management1": { "description": "Management interface", "ipv4_address": "10.10.0.5/24" }, "Ethernet1": { "description": "Span port - SPAN1" }, "Ethernet2": { "description": "PortChannel50 - port 1" }, "Ethernet51": { "description": "leaf01-eth51", "ipv4_address": "10.50.0.0/31" }, "Ethernet52": { "description": "leaf02-eth51", "ipv4_address": "10.50.0.2/31" } } } ############################################################################### # Rendered template ############################################################################### === Interfaces with assigned IPv4 addresses === Loopback0 - Management plane traffic: 10.255.255.34/32 Management1 - Management interface: 10.10.0.5/24 Ethernet51 - leaf01-eth51: 10.50.0.0/31 Ethernet52 - leaf02-eth51: 10.50.0.2/31
如您所见,我们总共有 6 个接口,但其中只有 4 个分配了 IP 地址。将is defined 测试添加到循环中,我们过滤掉没有 IP 地址的接口。
当迭代从设备返回的大负载时,循环过滤可能特别强大。在某些情况下,您可以忽略大部分元素并专注于感兴趣的事物。 In操作员
in 放置在两个值之间的运算符可用于检查左侧的值是否包含在右侧的值中。您可以使用它来测试元素是否出现在列表中,或者键是否存在于字典中。
运算符的明显用例in 是检查我们感兴趣的东西是否仅存在于集合中,我们不一定需要检索该项目。
查看前面的示例,我们可以检查 Loopback0 是否在列表接口中,如果是,我们将使用它来获取管理平面数据包,如果不是,我们将使用 Management1 接口。
模板: {% if "Loopback0" in interfaces -%} sflow source-interface Loopback0 snmp-server source-interface Loopback0 ip radius source-interface Loopback0 {%- else %} sflow source-interface Management1 snmp-server source-interface Management1 ip radius source-interface Management1 {% endif %}
渲染结果: sflow source-interface Loopback0 snmp-server source-interface Loopback0 ip radius source-interface Loopback0
请注意,即使interfaces 是一个包含大量数据的字典,我们也没有对其进行迭代或检索任何键。我们只想知道Loopback0 钥匙的存在。
老实说,上面的模板可以进行一些调整,我们基本上复制了 3 行配置和硬编码的接口名称。这不是一个很好的做法,我将在下一篇文章中向您展示我们如何在这里进行改进。
至此,我们已经结束了 Jinja2 教程的第 2 部分。接下来我将介绍空格,以便您可以使您的文档看起来恰到好处,我们将继续研究语言功能。我希望你在这里学到了一些有用的东西,并且回来获得更多! 参考Jinja2 (2.11.x) 最新版本的官方文档。可在:https ://jinja.palletsprojects.com/en/2.11.x/ Jinja2 内置测试。可在:https ://jinja.palletsprojects.com/en/2.11.x/templates/#list-of-builtin-tests PyPi 上的 Jinja2 Python 库。可在:https ://pypi.org/project/Jinja2/ 带有 Jinja 源代码的 GitHub 存储库。可在:https ://github.com/pallets/jinja/ 包含这篇文章资源的 GitHub 存储库。可在:https ://github.com/progala/ttl255.com/tree/master/jinja2/jinja-tutorial-p2-loops-conditionals
AI智能摄像机的新应用市场探讨人工智能与机器学习在安防行业的应用与技术日趋成熟,在此基础上推出的智能摄像机已经逐步打破传统安全防范应用的藩篱,在数字化时代中,被赋予智能的摄像机正朝着机器视觉的大方向演进。针对此
周看点人脸相关政策出台江门一小区安装人脸门禁被判侵权一周热点昆明惠州市出台政策规范商品房销售场所人脸识别系统使用行为近日,昆明市和惠州市住房和城乡建设局相继下发了关于规范商品房销售场所人脸识别系统使用行为的通知,通知强调,将加强商品
商业领域人脸识别频繁暴雷,何解?这几年来,随着人工智能技术的快速发展,以人脸识别为代表的AI技术逐渐从公检法金融等高安全性领域朝普通行业市场渗透。人脸识别的应用出现在社区门禁公司考勤展会通道闸机景区入口通道等多个
夜视摄像机选购的常见误解用户对于夜视摄像机的误解,容易影响选购,并对摄像机后期的体验造成影响,本文整理了当前业内比较常见的误解,方便读者更加了解夜视摄像机误解一夜视摄像机只能看到黑白画面传统的印象很容易让
摄像机入户为哪般说起摄像机,监控属性自然而然的地首入视线但在消费领域,监控并不是其主要功能,相反视频会成为家庭成员间相互关爱的可视化表达,此外还有侦测防范夜间成像等功能,这是过去家庭摄影机所无法比
从万御安防,看安防服务的未来趋势2019年11月,万科物业与海康威视通过战略合资成立万御安防2020年10月,万科物业更名为万物云。2021年5月,万科云发布发布安防机电服务品牌万御安防。现在看起来行业好像是因为
2021。6。146。18,AIoT产业一周新品速递本期新品包括中国航天海鹰毫米波安检仪MiR全新牵引产品MiR250Hook珑璟光电衍射光波导模组LCE2104H东芝全球最小固态激光雷达ImpinjRAINRFID芯片FOTRIC
AIoT周看点四部门联合整治摄像头黑产区块链物联网安全国标立项一周看点四部门联合行动开展摄像头偷窥黑产集中治理近日,从中央网信办获悉,中央网信办工信部公安部市场监管总局联合发布公告,自2021年5月至8月,在全国范围组织开展摄像头偷窥黑产集中
AI第一股梦碎依图何图AI四小龙的神奇或许不复存在了。截止至2021年3月上旬,据统计已经有95家企业终止了IPO审核,而当时依图科技给出的回应是中止不是终止,而这一次据上交所官网显示,依图科技的科创板
百度昆仑芯独立门户造芯渡己渡人6月25日,百度宣布旗下AI芯片部门近期成立独立新公司昆仑芯(北京)科技有限公司,注册资本1660万元,百度芯片首席架构师欧阳剑出任昆仑芯片公司CEO。关注互联网或科技领域的朋友应
四部委共推城市停车发展,新政解读近日,国家发展改革委等四部门发布关于推动城市停车设施发展的意见。意见提出,到2025年,全国大中小城市基本建成配建停车设施为主路外公共停车设施为辅路内停车为补充的城市停车系统。到2