S8-魔方方法与模块

  • 8 魔方方法和模块
    • 8.1 魔方方法
      • 8.1.1 基本的魔方方法
      • 8.1.2 算术运算符
      • 8.1.3 反算术运算符
      • 8.1.4 增量赋值运算符
      • 8.1.5 一元运算符
      • 8.1.6 属性访问
      • 8.1.7 描述符
      • 8.1.8 定制序列
      • 8.1.9 迭代器
      • 8.1.10 生成器
      • 8.1.11 【练习题】
    • 8.2 模块
      • 8.2.1 什么是模块?
      • 8.2.2 命名空间-NameSpace
      • 8.2.3 导入模块
      • 8.2.4 if __name__ == '__main__'
      • 8.2.4 搜索路径
      • 8.2.6 Package(包)
      • 8.2.7 【练习题】

本章节主要知识点是:魔方方法和模块

8 魔方方法和模块

8.1 魔方方法

魔方方法总是被双下划线包围,例如__init__。魔方方法是面向对象的python的一切。
魔方方法的“魔力”体现在他们总能够在适当的时候被自动调用。

  • 魔方方法的第一个参数应为cls(类方法)或者(实例方法):cls–指向自己的类 self–指向自己的一个实例对象

8.1.1 基本的魔方方法

  • init(self,[…])构造器,当一个实例被创建的时候调用的初始化方法。
    【例子】
class  Rectangle:def  __init__(self,x,y):self.x = xself.y = ydef  getPeri(self):return (self.x+self.y) * 2def  getArea(self):return self.x * self.yrect = Rectangle(4,5)
print(rect.getPeri())   # 18
print(rect.getArea) # 20
  • new(cls,[…])在一个对象实例化的时候所调用的第一个方法,在调用__init__初始化前,先调用__new__。
  1. new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由python解释器自动提供,后面的参数直接传递给__init
  2. new__对当前类进行了实例化,并将实例返回,传给__init__的self。但是,执行了__new,并不一定会进入__init__,只有__new__返回了,当前的类cls的实例,当前类的__init__才会进入。
    【例子】
class  A(object):def __init__(self,value):print("into A__init__")self.value = valuedef __new__(cls,*args,**kwargs):print("into A __new__")print("cls")return object.__new__(cls)class  B(A):def __init__(self,value):print("into B __init__")self.value = valuedef __new__(cls,*args,**kwargs):print("into B __new__")print(cls)return super().__new__(cls,*args,**kwargs)b = B(10)
# into B __new__
# <class '__main__.B'>
# into A __new__
# <class '__main__.B'>
# into B __init__
## 但是不知道怎么做;class A(object):def __init__(self,value):print("into A __init__")self.value = valuedef __new__(cls,*args,**kwargs):print("into A __new__")print(cls)return object.__new__(cls)class B(A):def __init__(self,value):print("into B __init__")self.value = valuedef __new__(cls,*args,**kwargs):print("into B __new__")print(cls)return super().__new__(A,*args,**kwargs)   # 改动了cls变为Ab = B(10)# into B __new__
# <class '__main__.B'>
# into A __new__
# <class '__main__.A'>
  • 若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行,将没有__init__被调用。

【例子】利用__new__实现单例模式

class Earth:passa = Earth()
print(id(a))    # 260728291456b = Earth(0
print(id(b))    # 260728291624class Earth:__instance = None    # 定义一个类属性做判断def __new__(cls):if cls.__instance is None:cls.__instance = object.__new__(cls)return cls.__instanceelse:cls.__instancea = Earth()
print(id(a))    # 512320401648
b = Earth()
print(id(b))  # 512320401648
  • __new__方法主要是当你继承一些不可变的class时(比如int,str,tuple),提供给你一个自定义这些类的实例化过程的途径。
    【例子】
class CapStr(str):def __new__(cls,string):string = string.upper()return str.__new_(cls,string)a = CapStr("i love lsgogroup")
print(a)    # I LOVE LSOGROUP
  • del(self)析构器,当一个对象将要被系统回收之时调用的方法
  1. Python 采用自动引用计数(ARC)方式来回收对象所占用的空间,当程序中有一个变量引用该 Python 对象时,Python 会自动保证该对象引用计数为 1;当程序中有两个变量引用该 Python 对象时,Python 会自动保证该对象引用计数为 2,依此类推,如果一个对象的引用计数变成了 0,则说明程序中不再有变量引用该对象,表明程序不再需要该对象,因此 Python 就会回收该对象。

  2. 大部分时候,Python 的 ARC 都能准确、高效地回收系统中的每个对象。但如果系统中出现循环引用的情况,比如对象 a 持有一个实例变量引用对象 b,而对象 b 又持有一个实例变量引用对象 a,此时两个对象的引用计数都是 1,而实际上程序已经不再有变量引用它们,系统应该回收它们,此时 Python 的垃圾回收器就可能没那么快,要等专门的循环垃圾回收器(Cyclic Garbage Collector)来检测并回收这种引用循环。

【例子】

class  C(object):def __init__(self):print('into C __init__')   def __del__(self):print("into C__del__")c1 = C()
# into C __init__
c2 = c1
c3 = c2
del c3
del c2
del c1
# into C __del__
  • str(self):

    1. 当你打印一个对象的时候,触发__str__
    2. 当你使用 %s 格式化的时候,触发 str
    3. 当使用str强制数据类型转换的时候,触发__str__
  • repr(self):
    1. repr是str 的备胎
    2. 有__str__的时候执行__str__,没有实现__str__的时候,执行__repr__
    3. repr(obj)内置函数对应的结果是__repr__的返回值
    4. 当你使用%r格式化的时候,触发__repr__
      【例子】
class Cat:""" 定义一个猫类 """def __init__(self,new_name,new_age):""" 在创建完对象之后,会自动调用,它完成对象的初始化的功能"""self.name = new_nameself.age = new_agedef __str__(self):"""返回一个对象的描述信息"""return  "名字是:%s,年龄是:%d" %(self.name,self.age)   def __repr__(self):"""返回一个对象的描述信息"""return "Cat:(%s,%d)" %(self.name,self.age)def eat(self):print("%s在吃鱼..." % self.name)def drink(self):print("%s在喝可乐..." % self.name)def introduce(slef):print("名字是:%s,年龄是:%d " %(self.name,self.age))# 创建了一个对象
tom = Cat("汤姆",30)
print(tom)  # 名字是:汤姆,年龄是:30
print(str(tom)) # 名字是:汤姆,年龄是:30
print(repr(tom))    #  Cat:(汤姆,30)tom.eat() # 汤姆在吃鱼...
tom.introduce() # 名字是:汤姆,年龄是:30

str(self)的返回结果代码可读性强。即__str__ 的意义是得到便于人们阅读的信息,就像下面的 ‘2019-10-11’ 一样。
repr(self) 的返回结果应更准确。怎么说,repr 存在的目的在于调试,便于开发者使用。
【例子】

import  datatime
today = datatime.date.today()
print(str(today))   # 2019-10-11
print(repr(today))  # datetime.date(2019,10,11)
print("%s " %today)   # 2019-10-11
print("%r" %today)    # datetime.date(2019,10,11)

8.1.2 算术运算符

类型工厂函数,指的是“不通过类而通过函数来创建对象”
【例子】

class  C:passprint(type(len))    # <class "builtin_function_or_method">
print(type(len))  # <class 'builtin_function_or_method'>
print(type(dir))  # <class 'builtin_function_or_method'>
print(type(int))  # <class 'type'>
print(type(list))  # <class 'type'>
print(type(tuple))  # <class 'type'>
print(type(C))  # <class 'type'>
print(int('123'))  # 123# 这个例子中list工厂函数把一个元组对象加工成了一个列表对象
print(list((1,2,3)))        # [1,2,3]
  • add(self,other)定义加法的行为:+
  • sub(self,other)定义减法的行为:-
    【例子】
class  MyClass:def  __init__(self,height,weight):self.height = heightself.weight = weight# 两个对象的长相加,宽不变,返回一个新的类def __add__(self,others):return MyClass(self.height+others.height, self.weight-others.weight)# 两个对象的宽相减,长不变.返回一个新的类def  __sub__(self,others):return MyClass(self.height-others.height,self.weight-others.weight)# 输出自己的参数def intro(self):print("Height: ", self.height,"Weight: ",self.weight)def  main():a = MyClass(10,5)a. introb = MyClass(20,10)b.introc = b-ac.intro()d = a+bd.intro()if  __name__ == "__main__":main() # 高为 10  重为 5
# 高为 20  重为 10
# 高为 10  重为 5
# 高为 30  重为 15

mul(self, other)定义乘法的行为:*
truediv(self, other)定义真除法的行为:/
floordiv(self, other)定义整数除法的行为://
mod(self, other) 定义取模算法的行为:%
divmod(self, other)定义当被 divmod() 调用时的行为
divmod(a, b)把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)。
【例子】

print(divmod(7,2))   # (3,1)
print(divmod(8,2))  # (4,0)

8.1.3 反算术运算符

反运算魔方方法,与算术运算符保持一一对应,不同之处就是反运算的魔方方法多了一个"r"。
当文件做操作不支持相应的操作时被调用。
radd(self, other)定义加法的行为:+
rsub(self, other)定义减法的行为:-
rmul(self, other)定义乘法的行为:*
rtruediv(self, other)定义真除法的行为:/
rfloordiv(self, other)定义整数除法的行为://
rmod(self, other) 定义取模算法的行为:%
rdivmod(self, other)定义当被 divmod() 调用时的行为
rpow(self, other[, module])定义当被 power() 调用或 ** 运算时的行为
rlshift(self, other)定义按位左移位的行为:<<
rrshift(self, other)定义按位右移位的行为:>>
rand(self, other)定义按位与操作的行为:&
rxor(self, other)定义按位异或操作的行为:^
ror(self, other)定义按位或操作的行为:

a + b
这里的加数是a,被加数是b,因此是a主动,,反运算就是如果a对象的__add__()方法没有实现或者不支持相应的操作,那么python就会调用b的__radd__()方法。
【例子】

class Nint(int):def __radd__(self,other):return int.__sub__(other,self)  #注意self在后面a = Nint(5)
b = Nint(3)
print(a + b)  # 8
print(1 + b)  # -2
#  结果没有看懂没有看懂

8.1.4 增量赋值运算符

iadd(self, other)定义赋值加法的行为:+=
isub(self, other)定义赋值减法的行为:-=
imul(self, other)定义赋值乘法的行为:*=
itruediv(self, other)定义赋值真除法的行为:/=
ifloordiv(self, other)定义赋值整数除法的行为://=
imod(self, other)定义赋值取模算法的行为:%=
ipow(self, other[, modulo])定义赋值幂运算的行为:**=
ilshift(self, other)定义赋值按位左移位的行为:<<=
irshift(self, other)定义赋值按位右移位的行为:>>=
iand(self, other)定义赋值按位与操作的行为:&=
ixor(self, other)定义赋值按位异或操作的行为:^=
ior(self, other)定义赋值按位或操作的行为:|=

8.1.5 一元运算符

neg(self)定义正号的行为:+x
pos(self)定义负号的行为:-x
abs(self)定义当被abs()调用的时候
invert(self)定义按位求反的行为:~x

8.1.6 属性访问

getattr(self,name):定义当用户试图获取一个不存在的属性的行为;
getattribute(self,name):定义当该类的属性被访问的时候(先调用该方法,查看是否存在该属性,若不存在,接着去调用__getattr__)。
setattr(self,name,value):定义当一个属性被设置时的行为
delattr(self,name): 定义当一个属性被删除时的行为
【例子】

class C:def __getattribute__(self,item):print('__getattribute__')return super().__getattribute__(item)def __getattr__(self,item):print('__getattr__')def __setattr__(self,key,value):print('__setattr__')super().__setattr__(key,value)def __delattr__(self,item):print('__delattr__')super().__delattr__(item)c = C()
c.x
# __getattribute__
# __getattr__c.x = 1
# __setattr__del c.x
# __delattr__

** 采用object(所有类的基类)调用方法,super()也是用来调用方法**

8.1.7 描述符

描述符就是将某种特殊类型的类的实例指派给另一个类的属性。
get(self, instance, owner)用于访问属性,它返回属性的值。
set(self, instance, value)将在属性分配操作中调用,不返回任何内容。
del(self, instance)控制删除操作,不返回任何内容。
【例子】

class  MyDecriptor:def  __get__(self,instance,owner):print('__get__',instance,owner)def __set__(self,instance,value):print('__set__',self,instance,value)def __delete__(self,instance):print('__delete__',self,instance)class Test:x = MyDecriptor():t = Test()
t.x
# __get__<__main__.MyDecriptor object at 0x000000CEAAEB6B00> <__main__.Test object at 0x000000CEABDC0898> <class '__main__.Test'>
t.x = 'x-man'
# __set__ <__main__.MyDecriptor object at 0x00000023687C6B00> <__main__.Test object at 0x00000023696B0940> x-mandel t.x
# __delete__ <__main__.MyDecriptor object at 0x000000EC9B160A90> <__main__.Test object at 0x000000EC9B160B38>

8.1.8 定制序列

协议(Protocols)与其他编程语言中的接口很相似,它规定你哪些方法必须要定义。然而,在python中的协议就显得那么不正式。在Python中,协议更像是一种指南。

  1. 容器类型的协议
  • 如果希望定制的容器是不可变的,只需要定义__len__()和__gettiem__()方法。
  • 如果希望定制的容器是可变的话,除了__len__和__getitem__方法,还需要定义__setitem__和__delitem__两个方法。
    【例子】编写一个不可改变的自定义列表,要求记录列表中每个元素被访问的次数
class CountList:def __init__(self,*args):self.values = [x for in args]self.count = {}.fromkeys(range(len(self.values)),0)def __len__(self):return len(self.values)def __getitem__():self.count[item] +=1return self.values[item]c1 = CountList(1,3,5,7,9)
c2 = CountList(2,4,6,8,10)print(c1[1]) # 3
print(c2[2])    # 6
print(c1[1]+c2[1])     # 7print(c1.count)      # {0:0,1:2,2:0,3:0,4:0}
print(c2.count)     # {0:0,1:1,2:1,3:0,4:0}

len(self)定义当被len()调用时的行为(返回容器中元素的个数)
getitem(self,key)定义获取容器中元素的行为,相当于self[key]
setitem(self, key, value)定义设置容器中指定元素的行为,相当于self[key] = value。
delitem(self, key)定义删除容器中指定元素的行为,相当于del self[key]。
【例子】编写一个可改变的自定义列表,要求记录列表中每个元素被访问的次数

class CountList:def __init__(self,*args):self.values = [x for i in args]self.count = {}.fromkeys(range(len(self.values)),0)def __len__(self):return len(self.values)def __getitem__(self,item):self.count[item] += 1return self.values[item]def __setitem__(self,key,value):self.values[key] = valuedef __delitem__(self,key):del self.values[key]for i in range(0,len(self.values)):if i >=key:self.count[i] = self.count[i+1]self.count.pop(len(self.values))c1 = CountList(1,3,5,7,9)
c2 = CountList(2,4,6,8,10)
print(c1[1])    # 3
print(c2[2])    # 6c1 = CountList(1, 3, 5, 7, 9)
c2 = CountList(2, 4, 6, 8, 10)
print(c1[1])  # 3
print(c2[2])  # 6
c2[2] = 12
print(c1[1] + c2[2])  # 15
print(c1.count)
# {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
print(c2.count)
# {0: 0, 1: 0, 2: 2, 3: 0, 4: 0}
del c1[1]
print(c1.count)
# {0: 0, 1: 0, 2: 0, 3: 0}

8.1.9 迭代器

迭代器是Python中最强大的功能之一,是访问集合元素的一种方式
迭代器是一个可以记住遍历的位置的对象
迭代器对象从集合的第一个元素开始访问,知道所有的元素被访问结束
迭代器只能往前不会后退
字符串,列表,字典或元祖对象都可用于作为创建迭代器

string = 'lsgogroup'
for c in string:print(c)'''
l
s
g
o
g
r
o
u
p
'''for c in iter(string):print(c)

【例子】

links = {'B':'baidu,'A':'alibaba','T':'Tencent'}
for each in link:print('%s ->%s' %(each,links[each]))# B -> 百度
# A -> 阿里
# T -> 腾讯
for each in iter(links):print('%s -> %s' % (each, links[each]))
  • 迭代器有两个基本的方法:iter()和next():
    1.iter(object)函数用来生成迭代器

    1. next(iterator,[default])返回迭代器的下一个项目: iterator–可迭代对象,default–可选,用于设置在没有下一个元素时返回默认值,如果不设置,又没有下一个元素则会触发StopIteration异常。
      【例子】
links = {'B':'baidu','A':'Alibaba','T':'Tencent'}
it = iter(links)
print(next(it)) # B
print(next(it)) # A
print(next(it)) # T
print(next(it)) # StopIterationit = iter(links)
while true:try:each = next(it)except StopIteration:breakprint(each)# B
# A
# T

把一个类作为一个迭代器使用需要在类中实现两个魔方方法__ietr__()与__next__()
iter(self)定义当迭代容器中的元素的行为,返回一个特殊的迭代器对象, 这个迭代器对象实现了 next() 方法并通过 StopIteration 异常标识迭代的完成。
next() 返回下一个迭代器对象。
StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 next() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。
【例子】

class Fibs:def __init__(self,n=10):self.a = 0self.b = 1self.n = ndef __iter__(self):return selfdef __next__(self):self.a,self.b = self.b, self.a+self.bif self.a > self.n:raise StopIterationreturn self.a
fibs = Fibs(100)
for each in fibs:print(each,end = ' ')
# 1 1 2 3 8 13 21 34 55 89

8.1.10 生成器

在Python中,使用了yield的函数被称为生成器(generator)。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
在调用生成器运行的过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield的值,并在下一次执行next()方法时从当前位置继续运行。
调用一个生成器函数,返回的是一个迭代器对象
【例子】

def myGen():print('生成器执行!')yield 1yield 2myG = myGen()
print(next(myG))
# 生成器执行!
# 1print(next(myG))
# 2
print(next(myG))
# StopIterationmyG = myGen()
for each in myG:print(each)
# 生成器执行
# 1
# 2

【例子】

def libs(n):a = 0b = 1while True:a,b = b,a+bif a>n:returnyield afor each in libs(100):print(each,end = ' ')
# 1 1 2 3 5 8 13 21 34 55 89

8.1.11 【练习题】

1、上面提到了许多魔法方法,如__new__,init, str,rstr,getitem,__setitem__等等,请总结它们各自的使用方法。
2、利用python做一个简单的定时器类
要求:
定制一个计时器的类。
start和stop方法代表启动计时和停止计时。
假设计时器对象t1,print(t1)和直接调用t1均显示结果。
当计时器未启动或已经停止计时时,调用stop方法会给予温馨的提示。
两个计时器对象可以进行相加:t1+t2。
只能使用提供的有限资源完成。

8.2 模块

模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py。模块可以被别的程序引入,以使用该模块中的函数等功能。这也是使用 Python 标准库的方法。

  • 解释器和编译器的区别?
    定义上:

    1. 编译器:把编程代码转换成机器码指令(不同CPU的机器指令不同),往往是在「执行」之前完成,产出是一种可执行的文件,产物是「另一份代码」。
    2. 解释器:直接执行由编程语言或脚本语言编写的代码,并不会把源代码预编译成机器码。把程序源代码一行一行的读懂然后执行,发生在运行时,产物是「运行结果」。
      主要观点仍然是:解释器立即执行代码,编译器为稍后的执行准备好源代码。所有实际的差异都因为他们有不同的目标。

8.2.1 什么是模块?

容器–>数据的封装
函数–>语句的封装
类—>属性和方法的封装
模块–>程序文件
【例子】创建一个hello.py文件

hello.py
def hi():print('Hi,everyone,I Love Isgogroup')

8.2.2 命名空间-NameSpace

命名空间因为对象的不同,也有所区别,分为如下几种:
内置命名空间(Built-in NameSpace):Python运行起来,他们就存在了。内置函数的命名空间都属于内置命名空间,所以我们可以在任何程序中直接运行它们,比如Id()不需要做什么操作,拿过来就直接使用了。
全局命名空间(modual :Global NameSpace):每个创建它自己所拥有的全局命名空间,不同模块的全局命名空间彼此相互独立,不同模块中相同名称的命名空间,也会因为模块的不同而不相互干扰。
本地命名空间(Function & Class: Local NameSpaces):模块中有函数或者类,每个函数或者类所定义的命名空间就是本地命名空间。如果函数返回了结果或者抛出异常,则本地命名空间也就结束了。
程序在查询上述三种命名空间的时候,就按照从里到位的顺序,即:Local NameSpaces–>Global NamesSpaces—>Built-in-NameSpaces。
【例子】

import hellohello.hi()   # Hi everyone,I love Lsgogroup
hi()            # NameError: name 'hi' is not defined

8.2.3 导入模块

【例子】创建一个模块 TemperatureConversion.py

# TempratureConversion.py
def c2f(cel):fah = cel*1.8 +32return fahdef f2c(fah):cel = (fah-32)/ 1.8
  • 第一种:import 模块名
    【例子】
import TempratureConversionprint('32摄氏度 = %.2f华氏度' % TempratureConversion.c2f(32))
print('99华氏度 = %.2f摄氏度' % TempratureConversion.f2c(99))# 32摄氏度 = 89.6华氏度
# 00华氏度 = 37.22摄氏度
  • 第二种:from 模块名 import 函数名。但是这种就是需要担心函数名重复的问题

【例子】

from TemperatureConversion import c2f, f2cprint('32摄氏度 = %.2f华氏度' % c2f(32))
print('99华氏度 = %.2f摄氏度' % f2c(99))# 32摄氏度 = 89.60华氏度
# 99华氏度 = 37.22摄氏度
  • 第三种:import 模块名 as 新名字
    【例子】
import TempratureConversion as tc
print('32摄氏度 = %.2f华氏度' % tc.c2f(32))
print('99华氏度 = %.2f摄氏度' % tc.f2c(99))

8.2.4 if name == ‘main

  1. 程序入口
    对于编程语言来说,程序必须要有一个执行入口,而Python不同,属于脚本语言。不像编译型语言那样先将程序编译成二进制再运行,而是动态的逐行解释运行。也就是从脚本第一行开始运行,没有统一的入口。
    假设有一个const.py文件,内容如下:
# const.py文件
PI = 3.14def main():print("PI: ",PI)main()
# PI: 3.14

现在,我们写一个用于计算圆面积的area.py文件,area.py文件需要用到const.py文件中的PI变量。从const.py中,我们把PI变量导入area.py:

from const import PIdef calc_round_area(radius):return PI*(radius **2)
def main():print('round area',calc_round_area(2))main()

PI:3.14
round area: 12.56

我们看到const.py中的main函数也被运行了,实际上不希望它被执行,因为const.py提供的main函数只是为了测试常量定义。这时 if __name__ ==' __main__'派上了用场,我们把const.py改一下,添加 if __name__ =='__main__':
```py
# 修改const.py文件
PI = 3.14def main():print("PI:", PI)if __name__ == "__main__":main()

运行 const.py,输出如下:
PI: 3.14
运行 area.py,输出如下:
round area: 12.56
name:是内置变量,可用于表示当前模块的名字

import constprint(__name__)
# __main__
print(const.__name__)
# const
  • name == ‘main’:假如你叫小明.py,在朋友眼中,你是小明(name == ‘小明’);在你自己眼中,你是你自己(name == ‘main’)。
  • 如果一个 .py 文件(模块)被直接运行时,其__name__值为__main__,即模块名为__main__(在自己眼中)。
  • if name =='main’的意思是:当.py文件被直接运行时,if name == ‘main’ 之下的代码块将被运行;当.py文件以模块形式被导入时,if name == 'main’之下的的代码块不被运行。
  • 目的是为了选择程序入口;由于模块之间相互引用,不同模块可能有这样的定义,而程序入口只有一个。到底哪个程序入口被选中,这取决于__name__的值。
  1. __name__反映一个包的结构
    __name__是内置变量,可用于反映一个包的结构。假设有一个包,包的结构如下:
a
├── b
│     ├── c.py
│        └── __init__.py
└── __init__.py

在Package(包)中,文件c.py,init.py,init.py的内容都为:
print(name)
当一个.py文件(模块)被其他.py文件(模块)导入时,我们在命令行执行:

Python -c "import a.b.c"
# a
# a.b
# a.b.c

由此可见:name__可以清晰地反映一个模块在包中的层次。
3. main.py文件与Python -m
Python的-m参数用于将一个模块或者包作为一个脚本执行,而__main
.py文件相当于是一个包"入口程序"。
运行Python程序的两种方式:
python xxx.py,直接运行xxx.py文件
python -m xxx.py,把xxx.py当做模块运行
4. mian.py的作用
一个包的结构:
package
├── init.py
└── main.py
其中文件__init__.py的内容

import sysprint("__init__")
print(sys.path)

其中文件__main__.py的内容:

import sysprint("__main__")
print(sys.path)

接下来,我们运行这个package,使用python -m package运行,输出结果:

__init__
['', ...]__main__
['', ...]

使用python package运行,输出结果:

__main__
['package', ...]

【小结】
当加上-m参数时,Python会把当前工作目录添加到sys.path中;而不加-m时,Python则会把脚本所在目录添加到sys.path中。
当加上-m参数时,Python会先将模块或者包导入,然后再执行。
main.py文件是一个包或者目录的入口程序。不管是用python package还是用python -m package运行,main.py文件总是被执行。
【参考来源】:https://blog.csdn.net/yjk13703623757/article/details/77918633

8.2.4 搜索路径

当解释器遇到import语句,如果模块在当前的搜索路径就会被导入。
【例子】

import sys
print (sys.path)

我们使用 import 语句的时候,Python 解释器是怎样找到对应的文件的呢?
这就涉及到 Python 的搜索路径,搜索路径是由一系列目录名组成的,Python 解释器就依次从这些目录中去寻找所引入的模块。
这看起来很像环境变量,事实上,也可以通过定义环境变量的方式来确定搜索路径。
搜索路径是在 Python 编译或安装的时候确定的,安装新的库应该也会修改。搜索路径被存储在 sys 模块中的 path 变量中。

8.2.6 Package(包)

包是一种管理Python模块命名空间的形式,采用“点模块名称”。
创建包分为三个步骤:
创建一个文件夹,用于存放相关的模块,文件夹的名字即包的名字。
在文件夹中创建一个 init.py 的模块文件,内容可以为空。
将相关的模块放入文件夹中。
【包的创建模板】

sound/                          顶层包__init__.py               初始化 sound 包formats/                  文件格式转换子包__init__.pywavread.pywavwrite.pyaiffread.pyaiffwrite.pyauread.pyauwrite.py...effects/                  声音效果子包__init__.pyecho.pysurround.pyreverse.py...filters/                  filters 子包__init__.pyequalizer.pyvocoder.pykaraoke.py...

在导入一个包的时候,Python会根据sys.path中的目录来寻找这个包中包含的子目录。
【访问包中模块】

  1. 访问一:目录只有包含一个叫做 init.py 的文件才会被认作是一个包,最简单的情况,放一个空的 init.py 就可以了。
    import sound.effects.echo
    这将会导入子模块 sound.effects.echo。 他必须使用全名去访问:
    sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

  2. 访问二:导入子模块:from sound.effects import echo,是直接导入本文件中,会有担心函数名重复
    这同样会导入子模块: echo,但是不再不需要那些冗长的前缀,所以可以这样使用:
    echo.echofilter(input, output, delay=0.7, atten=4)

  3. 访问三:直接导入一个函数或者变量:from sound.effects.echo import echofilter
    同样的,这种方法会导入子模块: echo,并且可以直接使用他的 echofilter() 函数:
    echofilter(input, output, delay=0.7, atten=4)
    【注意】
    注意当使用 from package import item 这种形式的时候,对应的 item 既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量。
    设想一下,如果我们使用 from sound.effects import * 会发生什么?
    Python 会进入文件系统,找到这个包里面所有的子模块,一个一个的把它们都导入进来。
    导入语句遵循如下规则:如果包定义文件 init.py 存在一个叫做 all 的列表变量,那么在使用 from package import * 的时候就把这个列表中的所有名字作为包内容导入。
    这里有一个例子,在 sounds/effects/init.py中包含如下代码:
    all = [“echo”, “surround”, “reverse”]
    这表示当你使用 from sound.effects import *这种用法时,你只会导入包里面这三个子模块。
    如果 all 真的没有定义,那么使用from sound.effects import *这种语法的时候,就不会导入包 sound.effects 里的任何子模块。他只是把包 sound.effects 和它里面定义的所有内容导入进来(可能运行__init__.py里定义的初始化代码)。
    这会把 init.py 里面定义的所有名字导入进来。并且他不会破坏掉我们在这句话之前导入的所有明确指定的模块。

import sound.effects.echo
import sound.effects.surround
from sound.effects import *

这个例子中,在执行 from…import 前,包 sound.effects 中的 echo 和 surround 模块都被导入到当前的命名空间中了。

通常我们并不主张使用 * 这种方法来导入模块,因为这种方法经常会导致代码的可读性降低。

8.2.7 【练习题】

1、怎么查出通过 from xx import xx导⼊的可以直接调⽤的⽅法?

2、了解Collection模块,编写程序以查询给定列表中最常见的元素。

题目说明:

输入:language = [‘PHP’, ‘PHP’, ‘Python’, ‘PHP’, ‘Python’, ‘JS’, ‘Python’, ‘Python’,‘PHP’, ‘Python’]

输出:Python

“”"
Input file
language = [‘PHP’, ‘PHP’, ‘Python’, ‘PHP’, ‘Python’, ‘JS’, ‘Python’, ‘Python’,‘PHP’, ‘Python’]

Output file
Python
“”"
def most_element(language):
“”" Return a list of lines after inserting a word in a specific line. “”"

# your code here

S9-魔方方法与模块相关推荐

  1. Python基础刻意练习:魔方方法

    task11 Python的对象天生拥有一些神奇的方法,它们总是被双下划线包围,它们是面向对象的Python的一切. 下面针对几个常用的魔方方法来展开: 1.-str-和-repr- __str__相 ...

  2. Python基础day08【面向对象(类、对象、属性)、魔方方法(init、str、del、repr)】

    视频.源码.课件.软件.笔记:超全面Python基础入门教程[十天课程]博客笔记汇总表[黑马程序员]   目录 0.复习 1.类外部添加和获取对象属性 2.类内部操作属性 3.魔法方法 3.1.__i ...

  3. 内置方法及模块初识,set的hash算法面试题

    析构方法__del__ 构造方法 申请一个空间 析构方法 释放一个空间之前执行 某对象借用了操作系统的资源,还要通过析构方法归还回去 : 文件资源 网络资源垃圾回收机制 class A:def __d ...

  4. python之有关魔方方法的内容

    魔方方法: 在python的类中,以下划线开头,两个下划线结尾的方法,如常见的:init,str,__del__等,就被称为魔方方法,这些方法在类或对象进行特定的操作时会被自动调用,我们可以使用或重写 ...

  5. Python —— 魔方方法

    在Python中 方法名为:XXX() 就是魔方方法 init() 初始化函数,用于完成默认的设置 new() 返回一个对象的实例,init() 无返回值 new()是一个类方法 del() 析构方法 ...

  6. Python Day11 魔方方法

    Python种的魔方方法 Python种有许多魔方方法供我们使用 魔法方法被双下划线包围,例如__init__. 魔法方法的第一个参数应为cls(类方法) 或者self(实例方法). 下面介绍常见的魔 ...

  7. php实现魔方变换颜色,php魔方方法

    php5中有三个魔方方法: _sleep() 可以控制对象序列化时真正处理的部分 _wakeup() 在反序列化后还原对象属性 _toString() 对象转换成为字符串的机制 把php变量转换成一串 ...

  8. 【循序渐进学Python】面向对象知多少——魔方方法

    [循序渐进学Python]面向对象知多少--魔方方法 据说,Python 的对象天生拥有一些神奇的方法,它们总被双下划线所包围,他们是面向对象的 Python 的一切. 他们是可以给你的类增加魔力的特 ...

  9. python魔方方法__getitem__、__setitem__和__len__

    python魔方方法__getitem__.setitem__和__len 目录 python魔方方法__getitem__.__setitem__和__len__ 一.简介 二.详解 三.代码 四. ...

最新文章

  1. 禁用windows更新完成后的重启提示
  2. 简单探讨可牛影像软件中具有肤质保留功能的磨皮算法及其实现细节。
  3. 【POJ】1505 Copying Books
  4. php把表情去掉,php如何去除表情
  5. SAP CRM Service Order search Tool
  6. pytorch load state dict_学习Pytorch过程遇到的坑(持续更新中)
  7. WORD网址单词自动换行留下大量空白区?
  8. VS2005-此计算机上已安装了试用版。必须先卸载以前安装的试用版后才能安装另一个试用版
  9. 修改mysql连接回收时间_Druid无效链接回收策略(源码分析)(mysql 8小时连接失效问题)...
  10. E WORD 0410
  11. jQuery动态星级评分效果实现方法
  12. FFT:快速傅里叶变换与高精度乘法
  13. 【博客话题】人在囧途之“运维囧”
  14. 刀客羽朋面向对象pdf
  15. 查找python安装路径
  16. 以大数据重塑K12在线教育
  17. 虾皮广告投放优化策略有哪些?
  18. 群晖 NAS 与 百度云网盘互相进行同步
  19. 华为nova7se和华为nova7的区别 哪个好
  20. linux查找以c开头的的文件夹,文件查找命令find详解

热门文章

  1. 嵌入式有什么值得学习的软硬件技术?
  2. 研发程序员求职简历表-Word简历可编辑下载
  3. iOS配置证书:Provisioning profile xx_Distribution doesn't include signing certificate iPhone Developer
  4. RealmObject-粗心操作引发的巨坑
  5. SQL语法分析-基础篇
  6. Android 获取联系人姓名和电话号码信息
  7. 在 LaTeX 中创建文档
  8. 关于BeanUtils.populate()方法使用时的报错解决
  9. Java实现手写数字的识别(BP神经网络的运用)
  10. 学编程和乐高机器人的区别