设为首页 收藏本站
查看: 456|回复: 0

[经验分享] 翻译-精通python设计模式-工厂模式

[复制链接]

尚未签到

发表于 2017-5-3 11:15:01 | 显示全部楼层 |阅读模式
  Creationaldesignpatternsdealwithanobjectcreation.Theaimofacreationaldesignpatternistoprovide
  better alternativesforsituationswhereadirectobjectcreation(whichinPythonhappensbythe__init__()
  function) isnotconvenient.
  

  创建型设计模式主要负责处理对象的创建。对于不适合直接创建对象的情况(一般在python__init__()方法初始化对象的时候),它能够给我们提供更好的替代方案,同时这也是创建型设计模式的目标。
  

  IntheFactorydesignpattern,aclientasksforanobjectwithoutknowingwheretheobjectiscomingfrom
  (thatis,whichclassisusedtogenerateit).Theideabehindafactoryistosimplifyanobjectcreation.
  Itiseasiertotrackwhichobjectsarecreatedifthisisdonethroughacentralfunction,incontrasttoletting
  aclientcreateobjectsusingadirectclassinstantiation.Afactoryreducesthecomplexityofmaintaining
  anapplicationbydecouplingthecodethatcreatesanobjectfromthecodethatusesit.
  

  在工厂设计模式中,客户端只需要知道如何调用对象,而不需要知道对象是从哪里来的(也就是说,它不用知道对象是由哪个类来创建)。工厂模式背后的思想就是简化对象的创建。相对于直接实例化类来创建对象,如果可以通过中央函数来创建对象,将会使得对象更容易跟踪管理。使用工厂方法,可以分离对象的创建和使用,从而解耦代码,降低维护应用的复杂程度。
  

  Factoriestypicallycomeintwoforms:theFactoryMethod,whichisamethod(orinPythonicterms,
  afunction)thatreturnsadifferentobjectperinputparameter;theAbstractFactory,whichisagroup
  ofFactoryMethodsusedtocreateafamilyofrelatedproducts.
  工厂模式主要有两种形式:
  第一,工厂方法,它是根据不同的输入返回不同对象的方法;
  第二,抽象工厂,它是创建系列相关对象的方法组。
  FactoryMethod
  工厂方法
  IntheFactoryMethod,weexecuteasinglefunction,passingaparameterthatprovidesinformation
  aboutwhatwewant.Wearenotrequiredtoknowanydetailsabouthowtheobjectisimplemented
  andwhereitiscomingfrom.
  在工厂方法中,我们只需要执行一个函数,然后当我们向函数传递一个参数,它就会返回我们想要的对象。关于对象创建的细节(对象是从哪里来的,是如何实现的),我们根本不需要知道。
  Areal-lifeexample
  一个生活实例
  AnexampleoftheFactoryMethodpatternusedinrealityisinplastictoyconstruction.Themolding
  powderusedtoconstructplastictoysisthesame,butdifferentfigurescanbeproducedusing
  differentplasticmolds.ThisislikehavingaFactoryMethodinwhichtheinputisthenameofthefigure
  thatwewant(duckandcar)andtheoutputistheplasticfigurethatwerequested.
  Thetoyconstructioncaseisshowninthefollowingfigure,whichisprovidedby.
  在实际的生活当中,工厂生产塑料玩具就是一个应用工厂方法模式的实例。虽然制造塑料玩具的原料(成型粉)是相同的,但是工厂可以通过使用不同的模具,制造出不同的玩具。这就像工厂方法模式一样,只要输入玩具的名称(例如:鸭和汽车),工厂就会生产出我们想要的塑料玩具。生产玩具案例的用例图如下图所示。
  

DSC0000.jpg

  

  Asoftwareexample
  一个软件实例
  TheDjangoframeworkusestheFactoryMethodpatternforcreatingthefieldsofaform.
  TheformsmoduleofDjangosupportsthecreationofdifferentkindsoffields(CharField,
  EmailField)andcustomizations(max_length,required).
  Django框架就是使用工厂方法模式来创建表单的输入域。Django框架的表单模块不但支持不同输入域的创建(例如:文本输入域,电子邮件输入域),而且还支持自定义输入域的属性(例如:最大长度、是否必填)。
  Usecases
  用例
  Ifyourealizethatyoucannottracktheobjectscreatedbyyourapplicationbecausethecode
  thatcreatesthemisinmanydifferentplacesinsteadofasinglefunction/method,
  youshouldconsiderusingtheFactoryMethodpattern.TheFactoryMethodcentralizes
  anobjectcreationandtrackingyourobjectsbecomesmucheasier.Notethatitisabsolutelyfine
  tocreatemorethanoneFactoryMethod,andthisishowitistypicallydoneinpractice.
  EachFactoryMethodlogicallygroupsthecreationofobjectsthathavesimilarities.Forexample,
  oneFactoryMethodmightberesponsibleforconnectingyoutodifferentdatabases(MySQL,SQLite),
  anotherFactoryMethodmightberesponsibleforcreatingthegeometricalobject
  thatyourequest(circle,triangle),andsoon.
  如果你已经意识到,由于对象的创建存在于代码的各种地方,而使得你不能踪管理它们,这个时候你就应该考虑使用工厂方法模式,通过统一函数/方法来创建管理它们。使用工厂方法可以集中创建对象,并且更加容易跟踪管理它们。请注意,在实际操作当中,人们通常会建立多个工厂方法。然后把工厂方法逻辑分组,创建相类似对象的方法放在一个工厂里面。例如,一个工厂方法可能负责连接到不同的数据库(MySQLSQLite),另一个工厂方法可能负责创造你请求的几何对象(圆,三角形),等等。
  TheFactoryMethodisalsousefulwhenyouwanttodecoupleanobjectcreationfrom
  anobjectusage.Wearenotcoupled/boundtoaspecificclasswhencreatinganobject,
  wejustprovidepartialinformationaboutwhatwewantbycallingafunction.Thismeansthat
  introducingchangestothefunctioniseasywithoutrequiringanychangestothecodethatusesit.
  工厂方法模式对于分离对象的创建和使用是非常合适的。在创建对象的时候,我们不会耦合特定的类,我们只需把部分对象的信息传递到特定函数,然后函数就会返回我们需要的对象。这意味着,当应用程序的功能发生变化时,我们只需要修改创建对象的函数,而不需要对调用对象的代码进行任何更改。
  Anotherusecaseworthmentioningisrelatedtoimprovingtheperformanceand
  memoryusageofanapplication.AFactoryMethodcanimprovetheperformance
  andmemoryusagebycreatingnewobjectsonlyifitisabsolutelynecessary.
  Whenwecreateobjectsusingadirectclassinstantiation,extramemoryisallocatedeverytime
  anewobjectiscreated(unlesstheclassusescachinginternally,whichisusuallynotthecase).
  Wecanseethatinpracticeinthefollowingcode(fileid.py),itcreatestwoinstances
  ofthesameclassAandusestheid()functiontocomparetheirmemoryaddresses.
  Theaddressesarealsoprintedintheoutputsothatwecaninspectthem.Thefactthat
  thememoryaddressesaredifferentmeansthattwodistinctobjectsarecreatedasfollows:
  另外还有一个值得一提的用例,是关于提高应用程序的性能和内存使用。因为使用了工厂方法,使得只有当对象是必要的时候,工厂方法才会创建它,所以,应用程序的性能和内存的使用得以相应的提升。每当我们直接使用类实例化对象,都会开销额外的内存(除非在类的内部使用缓存机制,但一般不是这样的)。我们从在下面的代码(id.py)可以看到,它使用同一类的创建两个实例,并使用的内建函数id()来比较两者的内存地址。并且两者的内存地址都打印输出到前台,这样方便我们观察他们。根据结果,两个实例的内存地址是不同的,这意味着它们创建了两个独立的实例,代码如下:

class A(object):
pass
if __name__ == '__main__':
a = A()
b = A()
print(id(a) == id(b))
print(a, b)

  Executing id.py on my computer gives the following output:


  运行id.py,它输出如下内容:
  


>> python3 id.py
False
<__main__.A object at 0x7f5771de8f60> <__main__.A object at 0x7f5771df2208>


  NotethattheaddressesthatyouseeifyouexecutethefilearenotthesameasIsee
  becausetheydependonthecurrentmemorylayoutandallocation.Buttheresult
  mustbethesame:thetwoaddressesshouldbedifferent.There'soneexception
  thathappensifyouwriteandexecutethecodeinthePythonRead-Eval-PrintLoop(REPL)
  (interactiveprompt),butthat'saREPL-specificoptimizationwhichisnothappeningnormally.
  请注意,如果你运行该文件,你看到的输出的结果(两个实例的内存地址),应该跟我这里输出的结果不一样,因为它们依赖于当前的内存布局和分配。但是,两者对比的结果应该是一样的,就是输出的内存地址应该不一样。如果你编写与执行代码都是在Python的REPL(交互式解释器)里面进行,也是会有例外的,但是这种特殊的REPL优化一般不会出现
  Implementation
  实现
  Datacomesinmanyforms.Therearetwomainfilecategoriesforstoring/retrievingdata:
  human_readablefilesandbinaryfiles.Examplesofhuman_readablefilesareXML,Atom,
  YAML,andJSON.Examplesofbinaryfilesarethe.sq3fileformatusedbySQLiteand
  the.mp3fileformatusedtolistentomusic.
  数据在现实中是以多种形式存在。一般用于存储或者检索数据的文件格式主要有两种:文字文件格式和二进制文件格式。而文字文件的常用格式有:XMLAtom,YAML和JSON。二进制文件的常用格式有:用于SQLite存储数据的.sq3文件格式,用于保存音乐数据的.mp3文件格式。
  Inthisexample,wewillfocusontwopopularhuman-readableformats:XMLandJSON.
  Althoughhuman_readablefilesaregenerallyslowertoparsethanbinaryfiles,
  theymakedataexchange,inspection,andmodificationmucheasier.Forthisreason,
  itisadvisedtopreferworkingwithhuman_readablefiles,unlessthereareotherrestrictions
  thatdonotallowit(mainlyunacceptableperformanceandproprietarybinaryformats).
  在下面的例子中,我们将集中介绍XMLJSON这两种文字文件格式。虽然文字文件的解析速度一般比二进制文件慢,但它对于数据交换、检查和修改来得更简单。出于这个理由,我们推荐人们在工作的时候使用文字文件,除非有其他限制(一般是不能接收的性能问题或者是需要专有二进制格式)。
  Inthisproblem,wehavesomeinputdatastoredinanXMLandaJSONfile,
  andwewanttoparsethemandretrievesomeinformation.Atthesametime,
  wewanttocentralizetheclient'sconnectiontothose(andallfuture)externalservices.
  WewillusetheFactoryMethodtosolvethisproblem.
  TheexamplefocusesonlyonXMLandJSON,butaddingsupportformoreservices
  shouldbestraightforward.
  在下面的例子中,我们先输入一些数据,将它们分别存储在XML文件和JSON文件里面,然后解析它们,并且检索某些信息。同时,我们需要把解析这一部分外接服务集中起来管理。我们将使用工厂方法来解决这个问题。虽然这个例子仅仅只是XMLJSON解析,但是当应用程序添加更多支持服务的时候,代码必须具备良好的扩展能力。
  First,let'stakealookatthedatafiles.TheXMLfile,person.xml,isbasedon
  theWikipediaexampleandcontainsinformationaboutindividuals
  (firstName,lastName,gender,andsoon)asfollows:
  首先,让我们先看看这两个数据文件。第一个是xml文件,person.xml它是摘自维基百科的一个例子,包含一些个人信息(名字,姓氏,性别,等等),具体文件如下:
  


<persons>
<person>
<firstName>John</firstName>
<lastName>Smith</lastName>
<age>25</age>
<address>
<streetAddress>21 2nd Street</streetAddress>
<city>New York</city>
<state>NY</state>
<postalCode>10021</postalCode>
</address>
<phoneNumbers>
<phoneNumber type="home">212 555-1234</phoneNumber>
<phoneNumber type="fax">646 555-4567</phoneNumber>
</phoneNumbers>
<gender>
<type>male</type>
</gender>
</person>
<person>
<firstName>Jimy</firstName>
<lastName>Liar</lastName>
<age>19</age>
<address>
<streetAddress>18 2nd Street</streetAddress>
<city>New York</city>
<state>NY</state>
<postalCode>10021</postalCode>
</address>
<phoneNumbers>
<phoneNumber type="home">212 555-1234</phoneNumber>
</phoneNumbers>
<gender>
<type>male</type>
</gender>
</person>
<person>
<firstName>Patty</firstName>
<lastName>Liar</lastName>
<age>20</age>
<address>
<streetAddress>18 2nd Street</streetAddress>
<city>New York</city>
<state>NY</state>
<postalCode>10021</postalCode>
</address>
<phoneNumbers>
<phoneNumber type="home">212 555-1234</phoneNumber>
<phoneNumber type="mobile">001 452-8819</phoneNumber>
</phoneNumbers>
<gender>
<type>female</type>
</gender>
</person>
</persons>

  TheJSONfile,donut.json,comesfromtheGitHubaccountofAdobeand
  containsdonutinformation(type,price/unitthatis,ppu,topping,andsoon)asfollows:
  第二个是json文件,donut.json它由Adobe在GitHub上面的账户提供的,主要描述甜甜圈的信息,包括种类、价格等等),具体文件如下:
  


[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters": {
"batter": [
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping": [
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
},
{
"id": "0002",
"type": "donut",
"name": "Raised",
"ppu": 0.55,
"batters": {
"batter": [
{ "id": "1001", "type": "Regular" }
]
},
"topping": [
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
},
{
"id": "0003",
"type": "donut",
"name": "Old Fashioned",
"ppu": 0.55,
"batters": {
"batter": [
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" }
]
},
"topping": [
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
]

  WewillusetwolibrariesthatarepartofthePythondistributionforworkingwithXMLandJSON:
  xml.etree.ElementTreeandjsonasfollows:
  我们将使用PythonXML库和JSON库来实现功能,它们是xml.etree.elementtreejson具体引入代码如下:
  


import xml.etree.ElementTree as etree
import json

  TheJSONConnectorclassparsestheJSONfileandhasaparsed_data()method
  thatreturnsalldataasadictionary(dict).Thepropertydecoratorisusedto
  makeparsed_data()appearasanormalvariableinsteadofamethodasfollows:
  我们使用JSONConnector来解析JSON文件,json库里面parsed_data()这个方法,它可以以字典的形式返回所有数据。通过@property这个装饰器,使得parsed_data()当成变量使用而不是作为方法使用,具体代码如下:
  


class JSONConnector:
def __init__(self, filepath):
self.data = dict()
with open(filepath, mode='r', encoding='utf-8') as f:
self.data = json.load(f)
@property
def parsed_data(self):
return self.data

  TheXMLConnectorclassparsestheXMLfileandhasaparsed_data()methodthat
  returnsalldataasalistofxml.etree.Elementasfollows:
  我们使用XMLConnector解析XML文件,xml库里面parsed_data()这个方法,它以xml.etree.element列表的形式返回所有数据,具体代码如下:
  


class XMLConnector:
def __init__(self, filepath):
self.tree = etree.parse(filepath)
@property
def parsed_data(self):
return self.tree

  Theconnection_factory()functionisaFactoryMethod.Itreturnsaninstance
  ofJSONConnectororXMLConnectordependingontheextensionoftheinputfilepath
  asfollows:
  connection_factory()函数是一个工厂方法。它根据输入的文件路径,返回JSONConnector者XMLConnector的实例,具体代码如下:
  


def connection_factory(filepath):
if filepath.endswith('json'):
connector = JSONConnector
elif filepath.endswith('xml'):
connector = XMLConnector
else:
raise ValueError('Cannot connect to {}'.format(filepath))
return connector(filepath)


  Theconnect_to()functionisawrapperofconnection_factory().Itaddsexceptionhandling
  asfollows:
  connect_to()方法封装了connection_factory(),并且增加了异常处理功能,具体代码如下:
  


def connect_to(filepath):
factory = None
try:
factory = connection_factory(filepath)
except ValueError as ve:
print(ve)
return factory

  Themain()functiondemonstrateshowtheFactoryMethoddesignpatterncanbeused.
  Thefirstpartmakessurethatexceptionhandlingiseffectiveasfollows:
  main()方法演示如何使用工厂方法,方法的第一部分测试异常处理的有效性,具体代码如下:

def main():
sqlite_factory = connect_to('data/person.sq3')

  ThenextpartshowshowtoworkwiththeXMLfilesusingtheFactoryMethod.XPathisusedto
  findallpersonelementsthathavethelastnameLiar.Foreachmatchedperson,
  thebasicnameandphonenumberinformationareshownasfollows:
  跟着那部分代码演示如何使用工厂方法来解析这个xml文件。它使用XPath来查询所有姓Liar的人。对于匹配的人,需要把他的姓名以及电话号码显示出来,具体代码如下:

xml_factory = connect_to('data/person.xml')
xml_data = xml_factory.parsed_data()
liars = xml_data.findall(".//{person}[{lastName}='{}']".format('Liar'))
print('found: {} persons'.format(len(liars)))
for liar in liars:
print('first name: {}'.format(liar.find('firstName').text))
print('last name: {}'.format(liar.find('lastName').text))
[print('phone number ({}):'.format(p.attrib['type']), p.text) for p in liar.find('phoneNumbers')]
  ThefinalpartshowshowtoworkwiththeJSONfilesusingtheFactoryMethod.Here,
  there'snopatternmatching,andthereforethename,price,andtoppingofalldonuts
  areshownasfollows:
  

  最后一部分的代码演示如何使用工厂方法来解析这个JSON文件。在这里,不需要匹配甜甜圈的信息,因此,所有甜甜圈的信息(包括名称,价格等)都会显示出来,具体代码如下:
  


  json_factory = connect_to('data/donut.json')
json_data = json_factory.parsed_data
print('found: {} donuts'.format(len(json_data)))
for donut in json_data:
print('name: {}'.format(donut['name']))
print('price: ${}'.format(donut['ppu']))
[print('topping: {} {}'.format(t['id'], t['type'])) for t in donut['topping']]
  Forcompleteness,hereisthecompletecodeoftheFactoryMethodimplementation
  (factory_method.py)asfollows:
  下面是完整的工厂方法实现代码(factory_method.py,具体代码如下:
  


import xml.etree.ElementTree as etree
import json
class JSONConnector:
def __init__(self, filepath):
self.data = dict()
with open(filepath, mode='r', encoding='utf-8') as f:
self.data = json.load(f)
@property
def parsed_data(self):
return self.data
class XMLConnector:
def __init__(self, filepath):
self.tree = etree.parse(filepath)
@property
def parsed_data(self):
return self.tree
def connection_factory(filepath):
if filepath.endswith('json'):
connector = JSONConnector
elif filepath.endswith('xml'):
connector = XMLConnector
else:
raise ValueError('Cannot connect to {}'.format(filepath))
return connector(filepath)
def connect_to(filepath):
factory = None
try:
factory = connection_factory(filepath)
except ValueError as ve:
print(ve)
return factory
def main():
sqlite_factory = connect_to('data/person.sq3')
print()
xml_factory = connect_to('data/person.xml')
xml_data = xml_factory.parsed_data
liars = xml_data.findall(".//{}[{}='{}']".format('person', 'lastName', 'Liar'))
print('found: {} persons'.format(len(liars)))
for liar in liars:
print('first name: {}'.format(liar.find('firstName').text))
print('last name: {}'.format(liar.find('lastName').text))
[print('phone number ({}):'.format(p.attrib['type']), p.text) for p in liar.find('phoneNumbers')]
print()
json_factory = connect_to('data/donut.json')
json_data = json_factory.parsed_data
print('found: {} donuts'.format(len(json_data)))
for donut in json_data:
print('name: {}'.format(donut['name']))
print('price: ${}'.format(donut['ppu']))
[print('topping: {} {}'.format(t['id'], t['type'])) for t in donut['topping']]
if __name__ == '__main__':
main()
  

  Hereistheoutputofthisprogramasfollows:
  下面是程序的输出,具体如下:
  


>>> python3 factory_method.py
Cannot connect to data/person.sq3
found: 2 persons
first name: Jimy
last name: Liar
phone number (home): 212 555-1234
first name: Patty
last name: Liar
phone number (home): 212 555-1234
phone number (mobile): 001 452-8819
found: 3 donuts
name: Cake
price: $0.55
topping: 5001 None
topping: 5002 Glazed
topping: 5005 Sugar
topping: 5007 Powdered Sugar
topping: 5006 Chocolate with Sprinkles
topping: 5003 Chocolate
topping: 5004 Maple
name: Raised
price: $0.55
topping: 5001 None
topping: 5002 Glazed
topping: 5005 Sugar
topping: 5003 Chocolate
topping: 5004 Maple
name: Old Fashioned
price: $0.55
topping: 5001 None
topping: 5002 Glazed
topping: 5003 Chocolate
topping: 5004 Maple
  

  NoticethatalthoughJSONConnectorandXMLConnectorhavethesameinterfaces,
  whatisreturnedbyparsed_data()isnothandledinauniformway.Differentpythoncode
  mustbeusedtoworkwitheachconnector.Althoughitwouldbenicetobeableto
  usethesamecodeforallconnectors,thisisatmosttimesnotrealisticunless
  weusesomekindofcommonmappingforthedatawhichisveryoftenprovided
  byexternaldataproviders.Assumingthatyoucanuseexactlythesamecode
  forhandlingtheXMLandJSONfiles,whatchangesarerequiredtosupportathirdformat,
  forexample,SQLite?FindanSQLitefileorcreateyourownandtryit.
  注意,虽然JSONConnectorXMLConnector具有相同的接口,但是,parsed_data()返回的数据不是以统一的方式处理。不同的Python代码必须使用不同的连接器工作。虽然所有连接器能使用相同的代码是非常好的,但是在大多数时间里,这是不现实的,除非我们使用数据供应商提供的常见映射来处理数据。假设,你是使用相同的代码来处理XMLJSON文件,现在需要增加处理第三种文件格式,例如,SQLite呢?你可以找一个SQLite文件,然后尝试一下。
  Asitisnow,thecodedoesnotforbidadirectinstantiationofaconnector.Isitpossibletodothis?Trydoingit.
  到现在为止,代码都不禁止直接实例化一个连接器。它有可能用这种方式实现吗?你可以自己尝试一下。
  Tip
  

  提示
  

  Hint:FunctionsinPythoncanhavenestedclasses.
  

  提示:在Python函数可以有嵌套类。
  

  

  译者:由于水平有限,暂时只能翻译成这样子了,请大家指出相应的问题,谢谢。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-372510-1-1.html 上篇帖子: python built-in function 学习笔记 下篇帖子: 为什么选择Python - FROM 新浪网友博客
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表