反射:

使用字符串数据类型的变量名来使用变量

wwwh即what,where,why,how  这4点是一种学习方法

反射 :使用字符串数据类型的变量名来使用变量
  1.文件中存储的都是字符串
  2.网络上能传递的也最接近字符串
  3.用户输入的也是字符串

上面的3种情况都是字符串,如果有这种情况的,需要操作类或者模块时,就需要用到反射

有4种应用

类调用静态属性
对象调用属性 和 方法
模块调用模块中的名字
调用自己模块中的名字

a = 1
import sys
b = getattr(sys.modules['__main__'],'a')
print(b) # 输出变量a的值,即1 def func():print('11')
c = getattr(sys.modules['__main__'],'func')
print(c) # 输出func的内存地址
getattr(sys.modules['__main__'],'func')() # 执行方法,输出11

执行输出:

1
<function func at 0x000002189E107F28>
11

Teacher类 wahaha方法的连续反射

import sys
class Teacher():
def wahaha(self):print('wa')
alex = getattr(sys.modules['__main__'],'Teacher')() # 获取当前模块的Teacher,并执行
print(alex) # Teacher类的内存地址
getattr(alex,'wahaha')() # 执行方法wahaha

执行输出:

<__main__.Teacher object at 0x00000203554EBF28>
wa

反射静态方法

import sys
class Teacher(object):
@staticmethod
def wahaha():print('wa') Teacher = getattr(sys.modules['__main__'],'Teacher') # # 获取当前模块的Teacher类
getattr(Teacher,'wahaha')() # 执行类方法,注意加括号

执行输出:

wa

找对象

import sys
class Teacher(object):
def wahaha(self):print('wa')
@staticmethod
def qqxing():print('qq') alex = Teacher()
b = getattr(sys.modules['__main__'],'alex')
print(b)

输出:

<__main__.Teacher object at 0x0000015469531048>

内置方法
__len__ len(obj)
obj对应的类中含有__len__方法,len(obj)才能正常执行

__hash__ hash(obj)  是object类自带的

只有实现了__hash__方法,hash(ojb)才能正常执行

hash是加加速寻址

print(hash('str'))

执行输出: 8500378945365862541

hash之后的数字,就是内存地址
hash之后,将value存储在对应的内存地址中

字典占用的内存相对的比,较用空间换时间
list占用的内存比较少,但是没有字典快

过一分钟,再次查看,发现数据都变了

-8079646337729346465

二、__str__,__repr__

repr() 函数将对象转化为供解释器读取的形式

print(repr('1'))
print(repr(1))

执行输出:

'1'
1

看起来,没啥作用

print(str('1'))
print(str(1))

执行输出:

1
1

li = [1,2,3,4]
print(li)

执行输出:

[1, 2, 3, 4]

class A:
def __init__(self,*args):
self.args = list(args)
li = A(1,2,3,4,5)
print(li)

执行输出:

<__main__.A object at 0x000001AAB3CDB9E8>

在类中,所有对象,默认打印的是内存地址

改变对象的字符串显示__str__,__repr__

class A:
def __init__(self,*args):
self.args = list(args)
def __str__(self):
return '[%s]' % (','.join([str(i) for i in self.args]))
li = A(1,2,3,4,5)
print(li) # 输出的结果是obj.__str__()的结果
print(str(li)) # 结果同上
print('%s'%li) # 结果同上

执行输出:

[1,2,3,4,5]

[1,2,3,4,5]

每一个对象,都有__str__方法

print执行时,实际是调用了__str__方法

class Teacher:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
return "Teacher's object %s" % self.name a = Teacher('alex',80)
b = Teacher('egon',80)
print(a) # 实际调用了__str__
print(b)
print(repr(a))  # 打印对象的内存地址

执行输出:

Teacher's object alex
Teacher's object egon
<__main__.Teacher object at 0x0000012346B9BF28>

class Teacher:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self): # 重新定义内置方法
return "Teacher's object %s" % self.name def __repr__(self): # 重新定义内置方法,为了做个性化输出
return 'repr function %s'%self.name a = Teacher('alex',80)
b = Teacher('egon',80)
print(repr(a)) # 打印repr函数的返回值
print(a.__repr__()) #调用__repr__方法
print('%r'%a)
print(str(a)) # 打印str函数的返回值

执行输出:

repr function alex
repr function alex
repr function alex
Teacher's object alex

repr(obj)的结果和obj.__repr__()是一样的
'%r'%(obj)的结果和obj.__repr__()是一样的

所有的输出,本质就是向文件中写

print执行时,是去内部中寻找__str__方法
所以print没有输出不了的数据,因为每一个对象都有__str__方法

print一个对象是,打印的是内存地址

def repr(obj):  # 归一化设计
return obj.__repr__()
print(repr('1'))

执行输出:'1'

repr执行时,其实是调用__repr__方法

repr(obj)的结果和obj.__repr__()是一样的

那么问题来了

repr(1)
repr('1')

的结果为什么不一样?

看下面的例子:

class int:
def __repr__(self):
return str(1)
a = int()
print(repr(a)) class str2:
def __repr__(self):
return "'%s'" % str(1)
b = str2()
print(repr(b))

执行输出:

1
'1'

repr的功能,之所以能还原数据原来的样子
是因为每一种数据对象的__reprt__都不一样

那么repr是做了归一化设计,接收一个对象。python一切皆对象

每个对象都有__repr__方法。执行rept,就执行了__repr__方法。

为什么做归一化设计呢?因为要更接近于面向函数编程

如果每一个对象,都要对象名.__str__这样执行,太麻烦了

使用函数的方法,要比类名.方法名 使用简单

当需要使用__str__的场景时找不到 __str__就找__repr__
当需要使用__repr__的场景时找不到__repr__的时候就找父类的repr
双下repr是双下str的备胎

总结:

len() obj.__len__() 返回值是一致的
len() 的结果是依赖 obj.__len__()
hash() 的结果是依赖 obj.__hash__()

str() 的结果是依赖 obj.__str__()
print(obj) 的结果是依赖 obj.__str__()
%s 的结果是依赖 obj.__str__() 语法糖
#
repr() 的结果是依赖 obj.__repr__()
%r 的结果是依赖 obj.__repr__()

repr是str的备胎

如果__str__和__repr__同时存在, 一定是选择repr

推荐几本书

《核心编程 第2版》 有很多基础知识
《核心编程 第3版》
《流畅的python》 有点难度,这本书比较火
《数据结构与算法》  机械工业出版社

对底层结构比较感兴趣的话,可以看《数据结构与算法》这本书

机械工业出版社,是比较权威的,
出的书是比较有代表性的
这本书,用例主要是用Python实现的

为什么int类型,可以使用%s,是因为int有___repr__方法

object.__repr__()
'%r' # __repr__()
int.__repr__()
str.__repr__()

%r 也是语法糖,不只是只有@
凡是不是调用函数,而是使用用一些符号之类的,都是语法糖
== 也是语法糖,它在内部执行时,是调用了内置方法,python解释器帮我们做了。

表面能使用的符号,内部其实是调用了方法,执行了计算过程。

三、__format__

format执行,就是调用了__format__方法

class A:
def __init__(self,name,school,addr):
self.name = name
self.school = school
self.addr = addr a = A('大表哥','oldboy','沙河')
print(format(a))

执行输出:

<__main__.A object at 0x000001AD3B07BF28>

对象之所以能用format,是因为object有这个__format__方法

查看object源码

    def __format__(self, *args, **kwargs): # real signature unknown
""" default object formatter """
pass

format执行时,必须要有参数format_spec才行

查看源码

def format(*args, **kwargs): # real signature unknown
"""
Return value.__format__(format_spec) format_spec defaults to the empty string
"""
pass

自定义一个__format__方法

class A:
def __init__(self,name,school,addr):
self.name = name
self.school = school
self.addr = addr def __format__(self, format_spec):
#format_spec = '{obj.name}-{obj.addr}-{obj.school}'
return format_spec.format(obj=self) #此行的format_spec等同于上面一行 a = A('大表哥','oldboy','沙河')
format_spec = '{obj.name}-{obj.addr}-{obj.school}'
print(format(a,format_spec))

执行输出:

大表哥-沙河-oldboy

这样就可以在外部规定format的输出格式

{obj.name}-{obj.addr}-{obj.school}是用花括号{}的

比如正常情况下,也是用{}表示一个占位符,它是不能边的

如果输出的字符串,需要加中括号[ ],可以这么写

class A:
def __init__(self,name,school,addr):
self.name = name
self.school = school
self.addr = addr
def __format__(self, format_spec):
return format_spec.format(obj=self) a = A('大表哥','oldboy','沙河')
format_spec = '[{obj.name}]-[{obj.addr}]-[{obj.school}]'
print(format(a,format_spec))

执行输出:

[大表哥]-[沙河]-[oldboy]

下面一个列子

format_dict={
'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
}
class School:
def __init__(self,name,addr,type):
self.name=name
self.addr=addr
self.type=type def __format__(self, format_spec): #format_spec = 'nat'
if not format_spec or format_spec not in format_dict: #判断参数是否为空或者是否在format_dict字典里
format_spec='nat' # 默认值为nat
fmt=format_dict[format_spec] #'{obj.name}-{obj.addr}-{obj.type}'
return fmt.format(obj=self) #'{obj.name}-{obj.addr}-{obj.type}'.format(obj=self) s1=School('oldboy1','北京','私立')
print(format(s1,'nat')) #s1.__format__('nat')
print(format(s1,'tna'))
print(format(s1,'tan'))
print(format(s1,'asfdasdffd')) # 字典不存在,走默认值。s1.__format__('nat')

执行输出:

oldboy1-北京-私立
私立:oldboy1:北京
私立/北京/oldboy1
oldboy1-北京-私立

重新回忆一下if判断的知识

if True:print('执行if中的代码')
if False:print('不执行if中的代码')

if True or False:print('or两端的条件有一个为True就执行这个if中的代码')
if not True or False:pass  结果为False,不执行if代码
if not False or False:pass  结果为True,执行if代码
if not format_spec or format_spec not in format_dict  有一个条件为True,执行if代码

当数据为以下值时,分别是数字0,空列表,空字符串,空字典,空元组,None

0 [] '' {} () None

表示False,否则为True

四、__call__

对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Teacher():
def __call__(self):
print(123)
t = Teacher()
t() # 对象名() 相当于调用类内置的__call__
Teacher()() #效果同上

执行输出:

123
123

有些源码会出现类名()()这种的,它其实是调用了__call__方法。所以一定要注意!!!

把__call__注释掉,再次执行

class Teacher():
pass
# def __call__(self):
# print(123)
t = Teacher()
t()

执行报错:

TypeError: 'Teacher' object is not callable

object默认没有__call__方法

使用callable方法,判断对象是否可调用

class Teacher():
pass
# def __call__(self):
# print(123)
t = Teacher()
print(callable(Teacher))
print(callable(t))

执行输出:

True
False

一个对象是否可调用 完全取决于这个对象对应的类是否实现了__call__

看Teacher类是否有__call__方法

print('__call__' in Teacher.__dir__(Teacher))

执行输出: True

查看callabble方法的解释,有一句话

Note that classes are callable (calling
a class returns a new instance); instances are callable if their class has a __call__() method.

翻译解释:

注意类是可调用的(调用)
一类返回一个新实例);实例调用如果类有一个__call __()方法。

print(callable(Teacher))的返回值是True

__call __()方法是针对对象的,而不是类。

python一切皆对象

class Teacher(object):
def __call__(self):
print(123)
def call(self):
print(456) t = Teacher()
t.call() # 手动执行call方法

执行输出: 456

五、__eq__

__eq__ 定义了类的等号(==)行为

class A:pass
a = A()
b = A()
print(a)
print(b)

执行输出:

<__main__.A object at 0x000001D32763BF28>
<__main__.A object at 0x000001D327641320>

从结果上来看,内存地址是不一样的

判断是否相等

class A:pass
a = A()
b = A()
print(a == b)

执行输出:False

==实际是调用了 __eq__方法,它是判断内存地址,是否一致

自定义__eq__方法

class A:
def __eq__(self, other):
return True
a = A()
b = A()
a.name = 'alex' # 增加一个属性
b.name = 'egon'
print(a == b)

执行输出:True

== 是由__eq__的返回值来决定的

虽然明知道,a和b是不可能相等的。但是类方法__eq__强制改变了结果,不管是什么,结果总是为True

为了让__eq__方法更有意义,再改动一下。

class A:
def __eq__(self, other):
if self.__dict__ == other.__dict__:
return True
else:
return False a = A()
b = A()
a.name = 'alex' # 增加一个属性
b.name = 'egon'
print(a == b)

执行输出:False

六、__del__

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

class A:
def __init__(self):
pass
def __del__(self):
print('执行我啦') a = A()
print('aaa')

执行输出:

aaa
执行我啦

当类执行完毕时,自动执行析构方法

删除一个对象

class A:
def __init__(self):
pass
def __del__(self):
print('执行我啦') a = A()
del a # 主动删除对象
print('aaa')

执行输出:

执行我啦
aaa

当对象在内存中被释放时,自动触发执行

看下面的例子

class A:
def __init__(self):
self.f = open('文件','w') # 打开文件句柄
# def __del__(self):
# print('执行我啦') a = A()
del a
print('aaa')

执行输出:aaa

这段代码,有一个问题,文件打开了,但是文件句柄没有释放。那么就浪费内存了。

这个时候,需要在析构方法中,关闭文件句柄

class A:
def __init__(self):
self.f = open('文件','w')
def __del__(self):
self.f.close() # 关闭文件句柄
print('文件关闭了') a = A()
del a

七、__new__

 __new__方法是创建类实例的方法,它的调用是发生在__init__之前的

object默认就有了

看__new__的源码

@staticmethod # known case of __new__
def __new__(cls, *more): # known special case of object.__new__
""" Create and return a new object. See help(type) for accurate signature. """
pass

它是一个静态方法,没有self,因为此刻还没有self
__new__()面试必考

先有对象,才能初始化
__new__方法不需要写,object自带

先来讲一个设计模式-->单例模式

如果面试中,只要 是问单例模式,就是问__new__
单例模式 就是一个类只能有一个实例

应用场景

1.当一个类,多次实例化时,每个实例都会占用资源,而且实例初始化会影响性能,这个时候就可以考虑使用单例模式,它给我们带来的好处是只有一个实例占用资源,并且只需初始化一次

2.当有同步需要的时候,可以通过一个实例来进行同步控制,比如对某个共享文件(如日志文件)的控制,对计数器的同步控制等,这种情况下由于只有一个实例,所以不用担心同步问题

看下面的代码:

class A:pass
a = A()
b = A()
print(a)
print(b)

执行输出:

<__main__.A object at 0x00000299A8D9BF28>
<__main__.A object at 0x00000299A8DA1320>

这不是单例模式,因为内存地址不一样
不是__init__的锅,是__new__的锅

__new__每次实例化,会创建一个新的内存地址

下面看一个真正的单例模式,使用__new__方法

class B:
__instance = None
def __new__(cls, *args, **kwargs): # cls表示类
if cls.__instance is None: # 判断类变量__instance是否为None
obj = object.__new__(cls) # 创建一个实例对象
cls.__instance = obj # 赋值
return cls.__instance # 返回私有静态属性 a = B()
b = B()
print(a)
print(b)

执行输出:

<__main__.B object at 0x00000267F570BB00>
<__main__.B object at 0x00000267F570BB00>

上面的结果,内存地址是一样的。

注意:__new__每次实例化,都会执行!!!

实例化时,先执行__new__,再执行__init__

第一次执行时,cls.__instance 是None,创建一个对象
第二次执行时,cls.__instance 不是None,返回私有静态属性

再添加几个属性

class B:
__instance = None def __new__(cls, *args, **kwargs):
if cls.__instance is None:
obj = object.__new__(cls)
cls.__instance = obj
return cls.__instance def __init__(self,name,age):
self.name = name
self.age = age
def func(self):
print(self.name) a = B('alex',80) #实例化,传值
b = B('egon',20) #实例化,覆盖值
print(a)
print(b)
print(a.name)
print(b.name)

执行输出:

<__main__.B object at 0x000002483F7DFF28>
<__main__.B object at 0x000002483F7DFF28>
egon
egon

b实例化时,a对象的值指向就中断了。由于a和b共用一个内存空间,所以最终结果为egon

八、item系列

对象使用中括号的形式去操作 

__getitem__ 当访问不存在的属性时会调用该方法

__setitem__属性被赋值的时候都会调用该方法

__delitem__删除属性时调用该方法

class Foo:
def __init__(self,name):
self.name=name def __getitem__(self,item):
return self.__dict__[item] def __setitem__(self, key, value):
self.__dict__[key]=value def __delitem__(self, key):
print('del obj[key]时,我执行')
self.__dict__.pop(key) f = Foo('alex')
# f.name = ...
print(f['name']) # f.__getitem__('name')
f['age'] = 18 # 赋值
print(f.age) # 自带的语法
print(f['age']) # 修改
f['age'] = 80
print(f['age']) # 通过实现__getitem__得到的
del f['age'] # 删除
#print(f.age) # 删除

执行输出:

alex
18
18
80
del obj[key]时,我执行

想要用对象名.[名字]
必须实现__getitem__方法

__getitem __只能有一个参数

__setitem__能接收2个参数,一个是等号左边,一个是等号右边的

__delitem__很少用

__delattr不用实现,因为object自带就有

class Foo:
def __init__(self,name):
self.name=name
def __delattr__(self, item):
print('del obj.key时,我执行')
self.__dict__.pop(item)
f = Foo('alex')
del f.name #相当于执行了__delattr__
# delattr(f,'name')

执行输出:

del obj.key时,我执行

面试题:

有一个类Person,它有3个属性,分别是name,sex,age。
实例化100次,每个对象的内存地址是不一样的。
其中有2个对象,name和sex是一样的,age不同
那么如何,去掉这2个重复的对象?

  

答案:

class Person:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex def __hash__(self): # 实例化时,执行此方法
return hash(self.name + self.sex) # 对name和sex做hash,因为有2个对象name和sex一样,age不同 def __eq__(self, other): # 实例化时,执行此方法
if self.name == other.name and self.sex == other.sex: # 判断每一个对象的name和sex是否相同
return True p_lst1 = [] #定义一个列表
#生成98个实例对象
for i in range(98):
p_lst1.append(Person('egon' + str(i),i,'male'))
#手动增加2个重复的,name和sex值是一样的,age不同
p_lst1.append(Person('egon50',200,'male'))
p_lst1.append(Person('egon50',300,'male'))
#查看p_lst1的长度
print(len(p_lst1))
#使用集合去重,查看p_lst1的长度
print(len(set(p_lst1)))

执行输出:

100
98

注意:__hash__和__eq__方法,必须自己定义,否则无法去重

明日默写:

class B:
__instance = None def __new__(cls, *args, **kwargs):
if cls.__instance is None:
obj = object.__new__(cls)
cls.__instance = obj
return cls.__instance def __init__(self,name,age):
self.name = name
self.age = age
def func(self):
print(self.name) a = B('alex',80)
b = B('egon',20)
print(a)
print(b)
print(a.name)
print(b.name)

  

python 全栈开发,Day24(复习,__str__和__repr__,__format__,__call__,__eq__,__del__,__new__,item系列)的更多相关文章

  1. Python全栈开发【面向对象进阶】

    Python全栈开发[面向对象进阶] 本节内容: isinstance(obj,cls)和issubclass(sub,super) 反射 __setattr__,__delattr__,__geta ...

  2. Python全栈开发【基础二】

    Python全栈开发[基础二] 本节内容: Python 运算符(算术运算.比较运算.赋值运算.逻辑运算.成员运算) 基本数据类型(数字.布尔值.字符串.列表.元组.字典) 其他(编码,range,f ...

  3. python 全栈开发,Day99(作业讲解,DRF版本,DRF分页,DRF序列化进阶)

    昨日内容回顾 1. 为什么要做前后端分离? - 前后端交给不同的人来编写,职责划分明确. - API (IOS,安卓,PC,微信小程序...) - vue.js等框架编写前端时,会比之前写jQuery ...

  4. python全栈开发从入门到放弃之迭代器生成器

    1.python中的for循环 l = [1,2,3,4,5,6] for i in l: #根据索引取值 print(i) 输出结果: 1 2 3 4 5 6 2.iterable  可迭代的 可迭 ...

  5. Python全栈开发【面向对象】

    Python全栈开发[面向对象] 本节内容: 三大编程范式 面向对象设计与面向对象编程 类和对象 静态属性.类方法.静态方法 类组合 继承 多态 封装 三大编程范式 三大编程范式: 1.面向过程编程 ...

  6. Python全栈开发【模块】

    Python全栈开发[模块] 本节内容: 模块介绍 time random os sys json & picle shelve XML hashlib ConfigParser loggin ...

  7. Python全栈开发【基础四】

    Python全栈开发[基础四] 本节内容: 匿名函数(lambda) 函数式编程(map,filter,reduce) 文件处理 迭代器 三元表达式 列表解析与生成器表达式 生成器 匿名函数 lamb ...

  8. Python全栈开发【基础三】

    Python全栈开发[基础三]  本节内容: 函数(全局与局部变量) 递归 内置函数 函数 一.定义和使用 函数最重要的是减少代码的重用性和增强代码可读性 def 函数名(参数): ... 函数体 . ...

  9. Python全栈开发【基础一】

    Python全栈开发[第一篇] 本节内容: Python 的种类 Python 的环境 Python 入门(解释器.编码.变量.input输入.if流程控制与缩进.while循环) if流程控制与wh ...

随机推荐

  1. 部署支持 https 的 Nginx 服务

    通过 Certbot 为 nginx 开启https支持. 环境 CentOS 7.1 python2.x(这玩意系统里本来就有) 安装Nginx sudo yum install nginx -y ...

  2. ruby导出exl方式

    class Demo print "hello world" require "spreadsheet" #设置表格的编码为utf-8 Spreadsheet. ...

  3. css before after基本用法【转】

    <HTML><HEAD> <meta http-equiv="content-Type"content="text/html;charset ...

  4. 机器学习课程-第8周-聚类(Clustering)—K-Mean算法

    1. 聚类(Clustering) 1.1 无监督学习: 简介 在一个典型的监督学习中,我们有一个有标签的训练集,我们的目标是找到能够区分正样本和负样本的决策边界,在这里的监督学习中,我们有一系列标签 ...

  5. 机器学习课程-第7周-支持向量机(Support Vector Machines)

    1. 优化目标 在监督学习中,许多学习算法的性能都非常类似,因此,重要的不是你该选择使用学习算法A还是学习算法B,而更重要的是,应用这些算法时,所创建的大量数据在应用这些算法时,表现情况通常依赖于你的 ...

  6. Jena搭建SPARQL查询RDF数据

    1 Jena搭建SPARQL查询RDF数据 1.1 Jena概要 · SPARQL是W3C的RDF数据工作组设计的一种查询语言和协议,用于RDF数据的查询.经过类似于JDK安装时候的配置,可以在命令行 ...

  7. WPS, 破解WPA/WPA2密钥的捷径

    1.关于WPS(WIFI保护设置) WPS(WIFI保护设置)主要致力于简化无线网络的安全加密设置. 传统方式下,用户新建一个无线网络时,必须在接入点手动设置网络名(SSID)和安全密钥,然后在客户端 ...

  8. UDP网络程序,客户端和服务端交互原理

    创建一个udp客户端程序的流程是简单,具体步骤如下: 创建客户端套接字 发送/接收数据 关闭套接字 UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实 ...

  9. android AysncTask使用

    1.继承AysncTask类 例子: class downloadTask extends AsyncTask<Void,Integer,Boolean> 第一个参数是传入的参数 第二个参 ...

  10. python学习笔记:"爬虫+有道词典"实现一个简单的英译汉程序

    1.有道的翻译 网页:www.youdao.com Fig1 Fig2 Fig3 Fig4 再次点击"自动翻译"->选中'Network'->选中'第一项',如下: F ...