百科问答小站 logo
百科问答小站 font logo



如何理解“from xxx import *这种写法会给你带来无穷无尽的噩梦?”? 第1页

  

user avatar   gao-tian-50 网友的相关建议: 
      

你写了一个程序:

       from some_module import * print("Hello World!")     

怎么运行都没有打印结果,然后打开some_module.py一看

       def print(*args):     exit(1)      

你气不气?

这就算善良的,它要给你写个os.remove() 之类的,你不更气?

当然了这是个很极端的情况,真的有恶意代码也不是不用from X import *就能解决的。这种写法的核心问题就是命名空间的冲突,因为你根本不知道你import进来了啥。

写程序这个事情,几乎在任何情况下,白名单都优于黑名单。白名单是可控的,黑名单是总会有漏网之鱼的。当你去拿车库拿工具的时候,需要锤子就拿锤子,需要锯子就拿锯子,不要把那个巨大的工具箱直接拿来,因为里面可能藏着爸爸拿来挖矿的炸药,见点火星子你就上天了。

在使用库的时候,基本上没有人对这个库是100%熟悉的,那你就只引入你想用的东西,显式地引入,这样可以在完全不了解这个库的情况下发现命名冲突的问题。如果你做了import *,那很可能会有大量的你并不熟悉甚至完全不知道的内容被引入,然后发生冲突,产生非常诡异的bug,严重浪费你的时间。

我不同意只要语言允许的,就应该去使用;就像我不同意家里存在的东西,小孩子就能玩一样。在使用任何一门语言的时候,都应该尽量选择这个语言允许范围内的效率更高、错误率更低的写法,这才是一个合格的程序员。


user avatar   huangzhe 网友的相关建议: 
      

谢邀。

from xxx import * 的后果

大家都讲得很明白了,from xxx import * 这种方法可能造成命名冲突。

例如A是卖数码产品的,B是卖水果的。A和B服务于同一个老板。他们都各有一个行李箱,现在他们都在老板面前,给老板供货。现在有两种情况:

  1. 在箱子里看一件件,要什么才拿出来(from B import apple)
  2. 为了方便,全部倒出来(from A import *, from B import * )

现在A和B箱子里都有一个iPhone包装盒(假设是同一款iphone)


A的iPhone盒子里面,装了个手机

B的iPhone盒子里,装了个红富士苹果(别问B为啥这么做,问就是创意)

如果A和B的行李箱物品都倒出来了(from A import * , from B import *),你能分辨出哪个盒子装的是手机,哪个盒子装的是红富士吗?

       from A import * from B import *  use(apple)     

但如果需要时再拿出来,我们就可以清楚知道,要红富士,直接去B的行李箱拿(from B import apple)

       from B import apple use(apple)      

如果包装盒不打开,仅凭盒子外观,就很难分辨哪个apple是iphone,哪个apple是苹果。

为啥「无论什么情况下」都不应该

我顺便来告诉大家为啥是「无论什么情况下」都不应该用这种方法。因为破窗效应。

以一幢有少许破窗的建筑为例,如果那些窗不被修理好,可能将会有破坏者破坏更多的窗户。最终他们甚至会闯入建筑内,如果发现无人居住,也许就在那里定居或者纵火。一面墙,如果出现一些涂鸦没有被清洗掉,很快的,墙上就布满了乱七八糟、不堪入目的东西

此理论认为环境中的不良现象如果被放任存在,会诱使人们仿效,甚至变本加厉。对于小工程还好,对于大的软件工程,如果你没有良好的代码规范,那么失控是非常容易的事。这也是为啥很多人抱怨在大公司做事没啥自由度,但事情做起来成功率要高。

你也许很清楚你的模块里面都有什么函数,你大胆使用from your_own_module import *,但你的代码不仅仅属于你,你的代码属于整个团队。当团队其他成员看到你这么写,那他很容易跟着模仿,毕竟项目代码风格这个东西,不就是团队之间互相配合出来的吗?你总不能写完这个代码后,告诉大家「虽然我用了import *,但这是我的特权,你们不能学我」吧?

所以,倒不如直接一刀切,制定好代码规范。让人自律很难,但让人遵守规则,则容易得多


user avatar   lokinko 网友的相关建议: 
      

可以抽象一点看代码

       import numpy     

可以理解为在第一层创建了一个文件夹,

       main.py  def function1()  def function2()  numpy      |-  numpy.random()      |-  numpy.exp()     

函数放在了第二层文件夹里,

所以调用时要用完整的函数名定向的指向。

       numpy.random()     

如果

       from numpy import *     

就会成为

       main.py  def function1()  def function2()  np.random()  np.exp()     

当你自定义的函数或者几个库的函数重名,

就会把先前的函数覆盖掉,

特别当大型工程时,调用的库复杂繁多,灾难性的后果......

引申的操作就是:

当你的工程文件长这样

       - project    |- file1      |- test1.py    |- file2      |- test2.py     

想在 test1.py 用 test2.py 里面的东西

可以用

       import sys sys.path.append('..') from file2 import test2.py     

就像先访问本文件上层的文件夹,再 import 同层的文件.


所以一般最好就写成

       import numpy as np import torch from torchvision import datasets, transforms     

这三种写法比较易读,而且记不住调用情况的时候可以随时搜索找到 import 的地方。


user avatar   levelpp_edu 网友的相关建议: 
      

这个问题本质很简单:因为给孩子起名怕重名,写程序同样也怕重名。

几乎所有的现代编程语言都采用这种方法避免重名:用完整的“包名称 + 标识符”的方式写清楚变量名或者函数名。

比如 random.randint(1,9) 再比如 math.cos(0)

这就类似于叫王强的人很多,但可以通过 志强小学.三年级二班.王强 的方式来命名,避免了重名的情况。

而在我们编写简单小程序的时候,不愿意写很长的函数名称,可以用简便写法:

from random import *

这样做的好处是用random库的函数非常方便,直接写randint就行,很省事。坏处是如果程序大了,几乎一定会发生重名的问题。

而且对于Python这种动态语言来说,重名会导致变量直接被覆盖,简直就是灾难:

       def randint():     print("这是一个随机函数")  from random import *  randint() # 运行结果:TypeError: randint() missing 2 required positional arguments: 'a' and 'b' # 原因:import * 的时候直接把前面定义的randint覆盖掉了     


所以结论是:

对于足够小的练习、测试程序,想怎么写怎么写。

一旦略微有一点规模的程序,就尽可能不要用from xxxx import * 的写法,一不小心就会发生变量重名的问题。只为省了几个字,惹出一大堆麻烦。

其实其它语言也是一样,比如C++的:using namespace xxx; 也会造成类似的问题。

————————回应评论补充——————————

方便性和安全性兼顾的写法,是这样:

       from random import randint from time import sleep, clock     

这样写既能方便的使用randint和sleep函数,不用加前缀;又能把潜在冲突放在一个极小的范围内。比用 星号* 好很多,很多大型项目都采用这种写法。




  

相关话题

  爬虫究竟是合法还是违法的? 
  如何让停留在语法层面的 C++,变成实际工程中的 C++? 
  为什么有人说 Python 的多线程是鸡肋呢? 
  创业公司如何能吸引一名优秀的 Python 开发者? 
  为什么有些人宁愿花费很多时间去自己手工配置Python环境, 也不用Anaconda? 
  Top2博士毕业,几乎不会编程,没写过python,是不是人生没有希望了? 
  怎么理解元编程? 
  3Blue1Brown 的视频是怎么制作的? 
  为什么企业微信没有Linux版本? 
  Python函数中*和**的内涵究竟是什么呢? 

前一个讨论
如何看待腾讯申请的「游戏手柄」外观设计专利疑似高度缝合?和此前的「游戏掌机」专利有什么关联?
下一个讨论
如何评价rog冰刃5双屏?





© 2024-11-24 - tinynew.org. All Rights Reserved.
© 2024-11-24 - tinynew.org. 保留所有权利