范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Spring使用Mypy检查30万行代码,总结出3大痛点与6个技巧

  作者:Charlie Marsh
  译者:豌豆花下猫@Python猫
  英文:Using Mypy in production at Spring (https://notes.crmarsh.com/using-mypy-in-production-at-spring)
  在 Spring ,我们维护了一个大型的 Python 单体代码库(英:monorepo),用上了 Mypy 最严格的配置项,实现了 Mypy 全覆盖。简而言之,这意味着每个函数签名都是带注解的,并且不允许有隐式的  Any   转换。
  (译注:此处的 Spring 并不是 Java 中那个著名的 Spring 框架,而是一家生物科技公司,专注于找到与年龄相关的疾病的疗法,2022 年 3 月曾获得比尔&梅琳达·盖茨基金会 120 万美元的资助。)
  诚然,代码行数是一个糟糕的衡量标准,但可作一个粗略的估计:我们的代码仓有超过 30 万行 Python 代码,其中大约一半构成了核心的数据平台,另一半是由数据科学家和机器学习研究员编写的终端用户代码。
  我有个大胆的猜测,就这个规模而言,这是最全面的加了类型的 Python 代码仓之一。
  我们在 2019 年 7 月首次引入了 Mypy,大约一年后实现了全面的类型覆盖,从此成为了快乐的 Mypy 用户。
  几周前,我跟 Leo Boytsov 和 Erik Bernhardsson 在 Twitter 上对 Python 类型有一次简短的讨论——然后我看到 Will McGugan 也对类型大加赞赏。由于 Mypy 是我们在 Spring 公司发布和迭代 Python 代码的关键部分,我想写一下我们在过去几年中大规模使用它的经验。
  一句话总结: 虽然采用 Mypy 是有代价的(前期和持续的投入、学习曲线等),但我发现它对于维护大型 Python 代码库有着不可估量的价值。Mymy 可能不适合于所有人,但它十分适合我。Mypy 是什么?
  (如果你很熟悉 Mypy,可跳过本节。)
  Mypy 是 Python 的一个静态类型检查工具。如果你写过 Python 3,你可能会注意到 Python 支持类型注解,像这样: def greeting(name: str) -> str:     return "Hello " + name
  Python 在 2014 年通过 PEP-484 定义了这种类型注解语法。虽然这些注解是语言的一部分,但 Python(以及相关的第一方工具)实际上并不拿它们来强制做到类型安全。
  相反,类型检查通过第三方工具来实现。Mypy 就是这样的工具。Facebook 的 Pyre 也是这样的工具——但就我所知,Mypy 更受欢迎(Mypy 在 GitHub 上有两倍多的星星,它是 Pants 默认使用的工具)。IntelliJ 也有自己的类型检查工具,支持在 PyCharm 中实现类型推断。这些工具都声称自己"兼容 PEP-484",因为它们使用 Python 本身定义的类型注解。
  (译注:最著名的类型检查工具还有谷歌的 pytype   和微软的pyright   ,关于基本情况介绍与对比,可查阅这篇文章《介绍几款 Python 类型检查工具》 )
  换句话说:Python 认为自己的责任是定义类型注解的语法和语义(尽管 PEP-484 本身很大程度上受到了 Mypy 现有版本的启发),但有意让第三方工具来检查这些语义。
  请注意,当你使用像 Mypy 这样的工具时,你是在 Python 本身之外运行它的——比如,当你运行 mypy path/to/file.py   后,Mypy 会把推断出的违规代码都吐出来。Python 在运行时显露但不利用那些类型注解。
  (顺便一提:在写本文时,我了解到相比于 Pypy 这样的项目,Mypy 最初有着非常不同的目标。那时还没有 PEP-484(它的灵感来自 Mypy!),所以 Mypy 定义了自己的语法,与 Python 不同,并实现了自己的运行时(也就是说,Mypy 代码是通过 Mypy 执行的)。当时,Mypy 的目标之一是利用静态类型、不可变性等来提高性能——而且明确地避开了与 CPython 兼容。Mypy 在 2013 年切换到兼容 Python 的语法,而 PEP-484 在 2015 年才推出。("使用静态类型加速 Python"的概念催生了 Mypyc,它仍然是一个活跃的项目,可用于编译 Mypy 本身。)) 在 Spring 集成 Mypy
  我们在 2019 年 7 月将 Mypy 引入代码库(#1724)。当首次发起提议时,我们有两个主要的考虑: 虽然 Mypy 在 2012 年的 PyCon 芬兰大会上首次亮相,并在 2015 年初发布了兼容 PEP-484 的版本,但它仍然是一个相当新的工具——至少对我们来说是这样。尽管我们在一些相当大的 Python 代码库上工作过(在可汗学院和其它地方),但团队中没有人使用过它。 像其它增量类型检查工具一样(例如 Flow),随着代码库的注解越来越多,Mypy 的价值会与时俱增。由于 Mypy 可以并且将会用最少的注解捕获 bug,所以你在代码库上投入注解的时间越多,它就会变得越有价值。
  尽管有所犹豫,我们还是决定给 Mypy 一个机会。在公司内部,我们有强烈偏好于静态类型的工程师文化(除了 Python,我们写了很多 Rust 和 TypeScript)。所以,我们准备使用 Mypy。
  我们首先类型化了一些文件。一年后,我们完成了全部代码的类型化(#2622),并升级到最严格的 Mypy 设置(最关键的是  disallow_untyped_defs   ,它要求对所有函数签名进行注解),从那时起,我们一直维护着这些设置。(Wolt 团队有一篇很好的文章,他们称之为"专业级的 Mypy 配置",巧合的是,我们使用的正是这种配置。)
  Mypy 配置:https://blog.wolt.com/engineering/2021/09/30/professional-grade-mypy-configuration/  反馈
  总体而言: 我对 Mypy 持积极的看法。  作为核心基础设施的开发人员(跨服务和跨团队使用的公共库),我认为它极其有用。
  我将在以后的任何 Python 项目中继续使用它。 好处
  Zulip 早在 2016 年写了一篇漂亮的文章,内容关于使用 Mypy 的好处(这篇文章也被收入了 Mypy 官方文档 中)。
  Zulip 博文:https://blog.zulip.com/2016/10/13/static-types-in-python-oh-mypy/#benefitsofusingmypy
  我不想重述静态类型的所有好处(它很好),但我想简要地强调他们在帖子中提到的几个好处: 改善可读性 :有了类型注解,代码趋向于自描述(与文档字符串不同,这种描述的准确性可以静态地强制执行)。(英:self-documenting)捕获错误: 是真的!Mypy 确实能找出 bug。从始至终。自信地重构: 这是 Mypy 最有影响力的一个好处。有了 Mypy 的广泛覆盖,我可以自信地发布涉及数百甚至数千个文件的更改。当然,这与上一条好处有关——我们用 Mypy 找出的大多数 bug 都是在重构时发现的。
  第三点的价值怎么强调都不为过。毫不夸张地说,在 Mypy 的帮助下,我发布更改的速度快了十倍,甚至快了一百倍。
  虽然这是完全主观的,但在写这篇文章时,我意识到: 我信任 Mypy 。虽然程度还不及,比如说 OCaml 编译器,但它完全改变了我维护 Python 代码的关系,我无法想象回到没有注解的世界。痛点
  Zulip 的帖子同样强调了他们在迁移 Mypy 时所经历的痛点(与静态代码分析工具的交互,循环导入)。
  坦率地说,我在 Mypy 上经历的痛点与 Zulip 文章中提到的不一样。我把它们分成三类: 外部库缺乏类型注解 Mypy 学习曲线 对抗类型系统
  让我们来逐一回顾一下: 1. 外部库缺乏类型注解
  最重要的痛点是,我们引入的大多数第三方 Python 库要么是无类型的,要么不兼容 PEP-561。在实践中,这意味着对这些外部库的引用会被解析为不兼容,这会大大削弱类型的覆盖率。
  每当在环境里添加一个第三方库时,我们都会在 mypy.ini   里添加一个许可条目,它告诉 Mypy 要忽略那些模块的类型注解(有类型或提供类型存根的库,比较罕见):[mypy-altair.*] ignore_missing_imports = True  [mypy-apache_beam.*] ignore_missing_imports = True  [mypy-bokeh.*] ignore_missing_imports = True  ...
  由于有了这样的安全出口,即使是随便写的注解也不会生效。例如,Mypy 允许这样做: import pandas as pd  def return_data_frame() -> pd.DataFrame:     """Mypy interprets pd.DataFrame as Any, so returning a str is fine!"""     return "Hello, world!"
  除了第三方库,我们在 Python 标准库上也遇到了一些不顺。例如, functools.lru_cache   尽管在 typeshed 里有类型注解,但由于复杂的原因,它不保留底层函数的签名,所以任何用 @functools.lru_cache   装饰的函数都会被移除所有类型注解。
  例如,Mypy 允许这样做: import functools  @functools.lru_cache def add_one(x: float) -> float:     return x + 1  add_one("Hello, world!")
  第三方库的情况正在改善。例如,NumPy 在 1.20 版本中开始提供类型。Pandas 也有一系列公开的类型存根 ,但它们被标记为不完整的。(添加存根到这些库是非常重要的,这是一个巨大的成就!)另外值得一提的是,我最近在 Twitter 上看到了 Wolt 的 Python 项目模板 ,它也默认包括类型。
  所以,类型正在变得不再罕见。过去当我们添加一个有类型注解的依赖时,我会感到惊讶。有类型注解的库还是少数,并未成为主流。 2. Mypy 学习曲线
  大多数加入 Spring 的人没有使用过 Mypy(写过 Python),尽管他们基本知道并熟悉 Python 的类型注解语法。
  同样地,在面试中,候选人往往不熟悉 typing   模块。我通常在跟候选人作广泛的技术讨论时,会展示一个使用了typing.Protocol   的代码片段,我不记得有任何候选人看到过这个特定的构造——当然,这完全没问题!但这体现了 typing 在 Python 生态的流行程度。
  所以,当我们招募团队成员时,Mypy 往往是他们必须学习的新东西。虽然类型注解语法的基础很简单,但我们经常听到这样的问题:"为什么 Mypy 会这样?"、"为什么 Mypy 在这里报错?"等等。
  例如,这是一个通常需要解释的例子: if condition:  value: str = "Hello, world" else:   # Not ok -- we declared `value` as `str`, and this is `None`!   value = None  ...  if condition:  value: str = "Hello, world" else:   # Not ok -- we already declared the type of `value`.   value: Optional[str] = None  ...  # This is ok! if condition:  value: Optional[str] = "Hello, world" else:   value = None
  另外,还有一个容易混淆的例子: from typing import Literal  def my_func(value: Literal["a", "b"]) -> None:   ...  for value in ("a", "b"):  # Not ok -- `value` is `str`, not `Literal["a", "b"]`.   my_func(value)
  当解释之后,这些例子的"原因"是有道理的,但我不可否认的是,团队成员需要耗费时间去熟悉 Mypy。有趣的是,我们团队中有人说 PyCharm 的类型辅助感觉还不如在同一个 IDE 中使用 TypeScript 得到的有用和完整(即使有足够的静态类型)。不幸的是,这只是使用 Mypy 的代价。
  除了学习曲线之外,还有持续地注解函数和变量的开销。我曾建议对某些"种类"的代码(如探索性数据分析)放宽我们的 Mypy 规则——然而,团队的感觉是注解是值得的,这件事很酷。 3. 对抗类型系统
  在编写代码时,我会尽量避免几件事,以免导致自己与类型系统作斗争:写出我知道可行的代码,并强迫 Mypy 接受。
  首先是 @overload   ,来自typing   模块:非常强大,但很难正确使用。当然,如果需要重载一个方法,我就会使用它——但是,就像我说的,如果可以的话,我宁可避免它。
  基本原理很简单: @overload def clean(s: str) -> str:     ...  @overload def clean(s: None) -> None:     ...  def clean(s: Optional[str]) -> Optional[str]:     if s:         return s.strip().replace(" ", " ")     else:         return None
  但通常,我们想要做一些事情,比如"基于布尔值返回不同的类型,带有默认值",这需要这样的技巧: @overload def lookup(     paths: Iterable[str], *, strict: Literal[False] ) -> Mapping[str, Optional[str]]:     ...   @overload def lookup(     paths: Iterable[str], *, strict: Literal[True] ) -> Mapping[str, str]:     ...   @overload def lookup(     paths: Iterable[str] ) -> Mapping[str, Optional[str]]:     ...   def lookup(     paths: Iterable[str], *, strict: Literal[True, False] = False ) -> Any:     pass
  即使这是一个 hack——你不能传一个 bool  到 find_many_latest  ,你必须传一个字面量 True   或False  。
  同样地,我也遇到过其它问题,使用  @typing.overload   或者@overload   、在类方法中使用@overload   ,等等。
  其次是 TypedDict   ,同样来自typing   模块:可能很有用,但往往会产生笨拙的代码。
  例如,你不能解构一个 TypedDict   ——它必须用字面量 key 构造——所以下方第二种写法是行不通的:from typing import TypedDict  class Point(TypedDict):     x: float     y: float  a: Point = {"x": 1, "y": 2}  # error: Expected TypedDict key to be string literal b: Point = {**a, "y": 3}
  在实践中,很难用 TypedDict  对象做一些 Pythonic 的事情。我最终倾向于使用 dataclass   或 typing.NamedTuple   对象。
  第三是装饰器。Mypy 的 文档 对保留签名的装饰器和装饰器工厂有一个规范的建议。它很先进,但确实有效: F = TypeVar("F", bound=Callable[..., Any])  def decorator(func: F) -> F:     def wrapper(*args: Any, **kwargs: Any):         return func(*args, **kwargs)      return cast(F, wrapper)  @decorator def f(a: int) -> str:     return str(a)
  但是,我发现使用装饰器做任何花哨的事情(特别是不保留签名的情况),都会导致代码难以类型化或者充斥着强制类型转换。
  这可能是一件好事! Mypy 确实改变了我编写 Python 的方式:耍小聪明的代码更难被正确地类型化,因此我尽量避免编写讨巧的代码。
  (装饰器的另一个问题是我前面提过的 @functools.lru_cache   :由于装饰器最终定义了一个全新的函数,所以如果你不正确地注解代码,就可能会出现严重而令人惊讶的错误。)
  我对循环导入也有类似的感觉——由于要导入类型作为注解使用,这就可能导致出现本可避免的循环导入(这也是 Zulip 团队强调的一个痛点)。虽然循环导入是 Mypy 的一个痛点 , 但这通常意味着系统或代码本身存在着设计缺陷,这是 Mypy 强迫我们去考虑的问题。
  不过,根据我的经验,即使是经验丰富的 Mypy 用户,在类型检查通过之前,他们也需对本来可以正常工作的代码进行一两处更正。
  (顺便说一下:Python 3.10 使用 ParamSpec   对装饰器的情况作了重大的改进。)提示与技巧
  最后,我要介绍几个在使用 Mypy 时很有用的技巧。 1. reveal_type
  在代码中添加 reveal_type   , 可以让 Mypy 在对文件进行类型检查时,显示出变量的推断类型。这是非常非常非常有用的。
  最简单的例子是: # No need to import anything. Just call `reveal_type`. # Your editor will flag it as an undefined reference -- just ignore that. x = 1 reveal_type(x)  # Revealed type is "builtins.int"
  当你处理泛型时, reveal_type   特别地有用,因为它可以帮助你理解泛型是如何被"填充"的、类型是否被缩小了,等等。2. Mypy 作为一个库
  Mypy 可以用作一个运行时库!
  我们内部有一个工作流编排库,看起来有点像 Flyte 或 Prefect。细节并不重要,但值得注意的是,它是完全类型化的——因此我们可以静态地提升待运行任务的类型安全性,因为它们被链接在一起。
  把类型弄准确是非常具有挑战性的。为了确保它完好,不被意外的 Any  毒害,我们在一组文件上写了调用 Mypy 的单元测试,并断言 Mypy 抛出的错误能匹配一系列预期内的异常:def test_check_function(self) -> None:    result = api.run(        [            os.path.join(                os.path.dirname(__file__),                "type_check_examples/function.py",            ),            "--no-incremental",        ],    )      actual = result[0].splitlines()    expected = [        # fmt: off        "type_check_examples/function.py:14: error: Incompatible return value type (got "str", expected "int")",  # noqa: E501        "type_check_examples/function.py:19: error: Missing positional argument "x" in call to "__call__" of "FunctionPipeline"",  # noqa: E501        "type_check_examples/function.py:22: error: Argument "x" to "__call__" of "FunctionPipeline" has incompatible type "str"; expected "int"",  # noqa: E501        "type_check_examples/function.py:25: note: Revealed type is "builtins.int"",  # noqa: E501        "type_check_examples/function.py:28: note: Revealed type is "builtins.int"",  # noqa: E501        "type_check_examples/function.py:34: error: Unexpected keyword argument "notify_on" for "options" of "Expression"",  # noqa: E501        "pipeline.py:307: note: "options" of "Expression" defined here",  # noqa: E501        "Found 4 errors in 1 file (checked 1 source file)",        # fmt: on    ]      self.assertEqual(actual, expected) 3. GitHub 上的问题
  当搜索如何解决某个类型问题时,我经常会找到 Mypy 的 GitHub Issues (比 Stack Overflow 还多)。它可能是 Mypy 类型相关问题的解决方案和 How-To 的最佳知识源头。你会发现其核心团队(包括 Guido)对重要问题的提示和建议。
  主要的缺点是,GitHub Issue 中的每个评论仅仅是某个特定时刻的评论——2018 年的一个问题可能已经解决了,去年的一个变通方案可能有了新的最佳实践。所以在查阅 issue 时,一定要把这一点牢记于心。 4. typing-extensions
  typing   模块在每个 Python 版本中都有很多改进,同时,还有一些特性会通过typing-extensions   模块向后移植。
  例如,虽然只使用 Python 3.8,但我们借助 typing-extensions   ,在前面提到的工作流编排库中使用了3.10 版本的ParamSpec  。(遗憾的是,PyCharm 似乎不支持通过typing-extensions   引入的ParamSpec   语法,并将其标记为一个错误,但是,还算好吧。)当然,Python 本身语法变化而出现的特性,不能通过typing-extensions   获得。5. NewType
  在  typing   模块中有很多有用的辅助对象,NewType   是我的最爱之一。
  NewType   可让你创建出不同于现有类型的类型。例如,你可以使用NewType   来定义合规的谷歌云存储 URL,而不仅是str   类型,比如:from typing import NewType  GCSUrl = NewType("GCSUrl", str)  def download_blob(url: GCSUrl) -> None:     ...  # Incompatible type "str"; expected "GCSUrl" download_blob("gs://my_bucket/foo/bar/baz.jpg")  # Ok! download_blob(GCSUrl("gs://my_bucket/foo/bar/baz.jpg"))
  通过向 download_blob   的调用者指出它的意图,我们使这个函数具备了自描述能力。
  我发现  NewType  对于将原始类型(如 str   和 int   )转换为语义上有意义的类型特别有用。6. 性能
  Mypy 的性能并不是我们的主要问题。Mypy 将类型检查结果保存到缓存中,能加快重复调用的速度(据其文档称:"Mypy 增量地执行类型检查,复用前一次运行的结果,以加快后续运行的速度")。
  在我们最大的服务中运行  mypy  ,冷缓存大约需要 50-60 秒,热缓存大约需要 1-2 秒。
  至少有两种方法可以加速 Mypy,这两种方法都利用了以下的技术(我们内部没有使用): Mypy 守护进程在后台持续运行 Mypy,让它在内存中保持缓存状态。虽然 Mypy 在运行后将结果缓存到磁盘,但是守护进程确实是更快。(我们使用了一段时间的默认 Mypy 守护进程,但因共享状态导致一些问题后,我禁用了它——我不记得具体细节了。) 共享远程缓存。如前所述,Mypy 在每次运行后都会将类型检查结果缓存到磁盘——但是如果在新机器或新容器上运行 Mypy(就像在 CI 上一样),则不会有缓存的好处。解决方案是在磁盘上预置一个最近的缓存结果(即,预热缓存)。Mypy 文档概述了这个过程,但它相当复杂,具体内容取决于你自己的设置。我们最终可能会在自己的 CI 系统中启用它——暂时还没有去做。 结论
  Mypy 对我们产生了很大的影响,提升了我们发布代码时的信心。虽然采纳它需要付出一定的成本,但我们并不后悔。
  除了工具本身的价值之外,Mypy 还是一个让人印象非常深刻的项目,我非常感谢维护者们多年来为它付出的工作。在每一个 Mypy 和 Python 版本中,我们都看到了对  typing  模块、注解语法和 Mypy 本身的显著改进。(例如:新的联合类型语法( X|Y  )、 ParamSpec   和 TypeAlias  ,这些都包含在 Python 3.10 中。)
  原文发布于 2022 年 8 月 21 日。 作者:Charlie Marsh
  译者:豌豆花下猫@Python猫
  英文:Using Mypy in production at Spring (https://notes.crmarsh.com/using-mypy-in-production-at-spring)
  请关注我,收获更多优质的 Python 文章和资讯!

大咖云集!罗盘带你看数智论坛北京站多重亮点3月14日,环球旅讯数智论坛北京站圆满落下帷幕。罗盘作为酒旅一体化系统领域重要参展商,携QTELS一体化云PMS和2023全新数智酒店管理解决方案亮相,吸引了行业众多酒店客户合作伙书赞桉诺亚洲首个研创中心在上海落成书赞桉诺中国研创中心落成书赞桉诺供图中新网上海3月21日电(记者李佳佳)全球最大的商品浆生产商之一书赞桉诺在亚洲的首个研发与创新中心书赞桉诺中国研创中心21日在上海落成。书赞桉诺首宅男财经东方财富一天两崩!股民损失咋办?专家可联系券商取证视频加载中3月21日,东方财富APP两度宕机,而这并不是东方财富APP第一次出现故障。2022年11月9日早盘期间,东方财富同花顺APP等炒股软件曾发生过崩了等情况。和讯信息首席策搞设计的快看!2023流行色彩趋势分析详解今天给大家分享的是易涂得2023年艺术涂料色彩趋势2023年艺术涂料色彩趋势分为8个部分来介绍,分别为一2023年我们身处的大环境二2023年的四个趋势三2023年的情绪定义年度主GPT4带来怎样的法律启示?第七届新兴法律服务业论坛启动报名昨天,百度人工智能对话平台文心一言发布会全网刷屏,微软震撼发布办公软件Microsoft365Copilot。在GPT的冲击下,各行各业都在准备新答案。也许,一切老问题只有从新技术行业风向标全面拥抱AIGC,网络游戏迎接供需共振每经记者刘明涛每经编辑赵云2022年以来,国际形势复杂多变,全球游戏市场普遍下行。国内新冠疫情影响也造成我国游戏行业投融资受阻企业生产研发受限用户消费意愿和能力下降,进而抑制了产业手术后有哪些流质饮食手术后流质饮食是患者在术后重要的营养支持,能够促进患者的康复。一流质饮食的产生原因术后口咽痛或受到影响,对咀嚼固体食物给人带来不适感另外,术后大部分患者都会出现胃不适呕吐腹泻等情况2023年3月22日上新电影汇总!1真人秀好友好有爱影片简介3月17日,由腾讯视频出品的恋爱综艺好友好有爱官宣定档,将于3月22日起每周三周四中午1200在腾讯视频独播。节目将邀请四组异性好友将在有爱小屋开启全新旅二胎故事千金难得,中医调理,喜从天降2023育儿季我的第二胎,来得真的不容易!生了第一胎儿子后,我们夫妻俩,深知自己的经济状况,一直不敢,再要第二胎。儿子出生不久,我的妻子,就配合政府的,计划生育政策,实施了上环节育依托赛事讲好苏河故事!首届上海苏州河半程马拉松赛4月22日鸣枪起跑继2023上海半马少儿马拉松赛陆续官宣,3月21日下午,上海又一项路跑赛事传来好消息。由上海市体育总会普陀区人民政府东浩兰生(集团)有限公司主办的首届上海苏州河半程马拉松赛,宣布将出游消费两旺!深圳网约车周末订单翻番,长里程订单涨超3成南都讯气温回升,桃红柳绿,景区乐园人潮涌动,踏青出游热,也带动了出行市场。近日,哈啰打车发布的数据显示,3月以来,平台内的出行需求持续上扬,尤其是周末出游类的出行需求活跃,带动平台
8月内13位网红因病相继去世,最年轻者19岁,3人选择捐遗体赠器官19岁本该是人生最美好的时刻,但抗癌女网红王晶的生命却永远停在了这一刻。王晶刚满19岁,踏入大学时却不幸查出急性白血病,而她的父亲也在3个月前也被查出白血病。父亲和女儿先后患白血病登记参选台南市长遇台独小党闹事,谢龙介不要傻傻地替人扫墓据台媒报道,台湾地区年底九合一选举8月29日至9月2日办理参选登记,1日上午台南市长参选人谢龙介,亲自带着中西区北区市议员参选人蔡宗豪,在国民党主席朱立伦陪同下,一起登记参选,谢龙相互赋能,国台酒业与南都打造酒媒融合全域营销新样本白酒与媒体除了跨界合作外,也能相互融合。今年7月31日,国台酒业与南方都市报签署战略框架合作协议,并宣布打造酒媒融合全域营销的新样本,把国台酒业最重视的广东市场打造成全域营销的样本斡旋美俄,土耳其凭什么在大国间走钢丝?当地时间2022年8月5日,俄罗斯索契,土耳其总统埃尔多安(左)和俄罗斯总统普京(右)会面。(人民视觉图)俄罗斯正试图利用土耳其,躲避西方国家一系列对俄制裁。路透社2022年8月2这个歇业通知,豪横送儿子去北大店铺歇业,喜糖自取近日,河南信阳罗山县一肉夹馍鸡蛋灌饼店挂出横幅网友羡慕表示这个通知真豪横!隔着屏幕都能感受到父母的骄傲!这家店面积不大,约6平方米考上北大的正是老板彭学生剐蹭私家车买烟饮料并留字条道歉,车主段子照进了现实8月30日,在江西吉安市,一名私家车车主在开车时发现后车门的门把手挂着一个红色塑料袋,里面放着两瓶饮料一包烟和一张字条。字条上写着不小心刮到了您的车,给您买一些水和烟,希望您消消气以色列之王沙龙从以色列国防军的小班长到沙漠战神从一名优秀的军人到一位受人尊崇的总理,从战场上的挥斥方遒到政局上的运筹帷幄,这个被誉为以色列之王的男人一生中给这个国家带来了及其重要的影响。他也凭借着自己的实力,在以色列的历史上留大街上高价收老酒,原来里面暗藏3种套路,行家别上当在酒圈之中,茅台占据了白酒之中的榜首,但其实要是对于懂行的人来说,茅台之上还有老酒占据了很多酒友心中的榜首。俗话说得好萝卜青菜各有所爱,茅台酒是很多人心中的NO。1,但其实很多人对学术中国马克思主义人类文明形态的深刻变革丰子义北京大学哲学系博雅讲席教授,北京大学马克思主义哲学研究中心主任,北京大学中国特色社会主义理论体系研究中心主任。中国的发展不仅创造了中国式现代化道路,而且创造了人类文明新形态。村民避雨挖到铜疙瘩,形似暖水瓶,当废品卖掉却因此发现西周古墓前言古代能人巧匠很多,也有很多技艺,即便是以现今的科技手法也不能实现。因为历史悠久,一些制作工艺也因此失传,在出土文物中,有很多堪称绝美的存在。文物和古墓的出土和发现,很多时候是有9月1日早盘两市机构大单抢筹40股股票名称股票代码收盘价涨跌幅大单(万股)买入净量占流通盘比列买入卖出买卖差当日T1T2一周新潮能源600777hr2。844。813985hr7798hr6187。00。97190