美文网首页【学习记录】Python
【学习记录】Python3版本(5:模块)

【学习记录】Python3版本(5:模块)

作者: 天有三光 | 来源:发表于2020-03-01 18:36 被阅读0次

综述

为了防止函数重名以及便于修正管理,大型工程文件一般都会有“模块”。

python用目录来查看和组织模块,这种方法称为包“package”

这些目录之下也可以有子目录。

而Python识别目录的方法是通过一个叫init.py的文件,因此,此文件不能删除。

除此之外,假设有一个包名为"AO3",他底下有一个文件叫"Works.py",那么该Works的访问应该是:AO3.Works。

与windows类似,同一个文件夹下面不可以有重名文件,但不同文件夹下可以有同名文件。

使用模块

心情开始逐渐崩溃,这都啥玩意啊。

硬着头皮看了一下sys是啥子,感觉好像也没那么难懂,简单测试了一下,果然计算机是要在实践里学习的

以下是廖大神源代码,我看着打了一遍。

#!/usr/bin/env python3

# -*- coding: utf-8 -*-



'test module:Liao xue feng====https://www.liaoxuefeng.com/wiki/1016959663602400/1017455068170048'



__author__='Michael Liao'



import sys



def test():

    args=sys.argv

    if len(args)==1:

        print('Hello,world!')

    elif len(args)==2:

        print('Hello,%s!'%args[1])

    else:

        print('Too many arguments!')



if __name__=='__main__':

    test()

另外,name与main的关系,其实就是看你是否是被载入的主程序。如果是,就直接调用一次函数。免得你打字了。

就好像,在公共场合你就得注意形象,在自己的屋子里你是主人你就可以放开了耍。

Run->Run Module之后,命令行窗口:

============= RESTART: D:/ZQC/2020寒假学习计划/python/Sy_12_Modual.py =============

Hello,world!

#上来就直接跳出helloworld,可知程序已经运行,并且已经调用一次test()了

#接下来,廖大神说argv是sys模块的变量,如果没有变量,那么argv至少有第一个参数为该.py文件的名称。

>>> aab=1

>>> aab

1

>>> test()

Hello,world!

#犯傻过程:命令行里的变量是否会被argv存进去,答案是不可以。

>>> args=[1,2]

>>> test()

Hello,world!

#继续犯傻:我改args会不会有用。然后发现test每调用一次给args重新赋一次值

>>> sys.argv

['D:/ZQC/2020寒假学习计划/python/Sy_12_Modual.py']

#犯傻*3:今天我胖虎就要看看你argv里有啥,

#果然argv里只有文件名

>>> sys.argv=[1,2]

>>> test()

Hello,2!

#我直接改argv会咋样:果然返回了参数2.同理



==========

#在廖大神源代码中if之前加入了新语句a='a'

#预期结果为>>>hello,a

#结果为
>>>hello,world



#突然意识到的犯傻*4:廖大神用的是cmd命令行窗口啊!(win+R->cmd->Enter出来的那个黑洞洞的窗口)

#等会儿,idel的窗口能不能叫命令行来着......???????

作用域

函数、变量是有一定的作用范围的。

比如说globle n就是将n定义为全局变量。

正常的函数、变量名是公开的,如abs、PI

__xxx__,是特殊变量可以直接引用,但有特殊用途。例如name

_xx,__xx,这类是非公开的函数名或者变量。它们应当是不进行直接调用的。但是,python也办法没禁止调用。

安装第三方模块.......

一切这个话题,我都觉得......我一直都没学到要用anaconda的地步orz......passpass#动态过程为类或者实例绑上一个方法

​>>> def set_age(std,age):

std.age=age

#idle界面中敲出函数

>>> Student.set_age=MethodType(set_age,Student)

Traceback (most recent call last):File "<pyshell#41>", line 1, in <module>Student.set_age=MethodType(set_age,Student)

NameError: name 'MethodType' is not defined

#直接使用MethodType语句,发现不对

>>> from types import MethodType

>>> Student.set_age=MethodType(set_age,Student)

>>> bart=Student('bart',61,'male')

>>> bart.set_age(99)

>>> bart.age

99

#大功告成
image
Student.set_score = set_score并不是给类绑定了方法只是调用,而Student.set_score=MethodType(set_score,Student)才是给类绑定方法
1
Student.set_score=set_scor
print(Student.set_score,set_score)

2

Student.set_score=MethodType(set_score,Student)
print(Student.set_score,set_score)
分别运行上面两段代码就能体会到区别

限制类里的属性__slots__

class Animals(object):

    __slots__=('name','age')

class Cat(Animals):

    pass

====

>>> Dogs=Animals()

>>> Dogs.name='doge'

>>> Dogs.age=7

>>> Dogs.number='A'

Traceback (most recent call last):File "<pyshell#52>", line 1, in <module>Dogs.number='A'

AttributeError: 'Animals' object has no attribute 'number'

#使用__slots__之后,Animal类的Dogs无法传入number属性

>>> Cats=Cat()

>>> Cats.number='A'

>>> Cats.number

'A'

#Animal的子类Cat却可以传入number属性

@property

为了解决调用函数代码复杂,直接暴露参数无法检查参数输入的矛盾,该语句应运而生。

class Student(object):
    
    def __init__(self,name,score,gender):
        self.__name=name
        self.__score=score
        self.__gender=gender

    @property
    #相当于调用时,使用变量名.函数名。即s.gender=,且表示该函数是只读的,不会修改
    def gender(self):
        return self.__gender

    @gender.setter
    #表示这是修改gender变量的函数
    def set_gender(std, gender):
        if gender=='male':
            std.__gender=gender
        elif gender=='female':
            std.__gender=gender
        else:
            print('Type error')

在idle界面中

>>> bart=Student('bart',60,'male')
>>> bart.gender
'male'
>>> bart.set_gender='female'
>>> bart.gender
'female'

廖老师布置的作业:

# -*- coding: utf-8 -*-
class Screen(object):

    def __init__(self,width=0,height=0):
        self.__width=width
        self.__height=height

    @property
    def width(self):
        return self.__width

    @property
    def height(self):
        return self.__height

    @property
    def resolution(self):
        return self.__width*self.__height

    @width.setter
    def width(self,value):
        if value>0:
            self.__width=value
        else:
            print('Type Error')

    @height.setter
    def height(self,value):
        if value>0:
            self.__height=value
        else:
            print('Type Error')


多重继承

人类面临分类的时候经常会发现的问题:它既是一种分类方法的A类,又是另一种分类方法的B类。
此时,为了使得类可以完成它的使命,我们需要让他能够继承到他需要的属性,这就涉及了多重继承的问题。

class Animals(object):

    __slots__=('name','age')

class Flyable(object):
    pass

class Bat(Animals,Flyable):
    pass

相当于tag标签一样的分类。

MixIn

摸不太着头脑,是说上面的那个Bat类还可以写成

class Bat(Animal,FlyableMixIn):
    pass

吗?


定制类

__xxx__类有特殊用途
注意,这些都是要自己写函数的,而不是可以直接在idle窗口调用的。它们写好后,可以让类的访问变得像是一个list型(或者其他类型)。

1 __str____repr__

>>> a=Screen()
>>> a
<__main__.Screen object at 0x000001FA828B48D0>

此处返回的就是调用__repr__()的,返回的是开发者看到的字符串,是为调试服务的。
可以这么写:

class Student(object):
    
    def __init__(self,name,score,gender):
        self.__name=name
        self.__score=score
        self.__gender=gender
    def __str__(self):
        return 'Student object (name=%s)' % self.__name
    __repr__=__str__

idle界面:

>>> bart=Student('bart',60,'male')
>>> bart
Student object (name=bart)

2 __iter__返回迭代

使用此语句返回一个迭代对象,使得在idle界面可以使用for循环访问。

3 __getitem__返回一个可用下标访问的迭代对象

比如之前__iter__返回的可迭代对象,用__getitem__可以在idle界面使用下标如数列一样的访问。
但是要注意的是,在编写此函数时,要同时包含切片对象的处理方式。
同类还有,__setitem____delitem__等等

4 __getattr__

当用户访问一个不存在的属性时,python会调用__getattr__函数。
因此,可以写:

    #当访问一个不存在的属性时
    def __getattr__(self,attr):
        if attr=='age':
            return 'unknown'
        raise AttributeError('\'Student\' object has no attribute\'%s\''%attr)

idle中:

>>> bart=Student('bart',60,'male')
>>> bart.age
'unknown'
>>> bart.number
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    bart.number
  File "D:\ZQC\2020寒假学习计划\python\Sy_13_WhereisDuiXiang.py", line 17, in __getattr__
    raise AttributeError('\'Student\' object has no attribute\'%s\''%attr)
AttributeError: 'Student' object has no attribute'number'
#这个到底对不对啊,我好懵啊orz

5 __call__

可以将类的实例对象当成函数一样:

    #类的实例当函数调用
    def __call__(self):
        print('I\'m class \'Student\'.')

idle中:

>>> bart=Student('bart',60,'male')
>>> bart()
I'm class 'Student'.

通过callable可以判断一个对象是否可以调用。


使用枚举类

枚举类是一种定义常数的方法。
一般常量都是用全大写表示,如:PI=3.1415。当然,这种定义方式太简单了,而且它本身是int型的变量。因此,就引出了,枚举类。

>>> from enum import Enum
>>> Week=Enum('week',('Mon','Tue','Wed','Thu','Fri','Sat','Sun'))
>>> for name,member in Week.__members__.items():
    print(name,'-->',member.value)#列举所有枚举量

Mon --> 1
Tue --> 2
Wed --> 3
Thu --> 4
Fri --> 5
Sat --> 6
Sun --> 7

另外,还可以从Enum派生出自定义类:

>>> from enum import Enum
>>> class Weekday(Enum):
    Sun=0
    Mon=1
    Tue=2
    Wed=3
    Thu=4
    Fri=5
    Sat=6

>>> day1=Weekday.Mon
>>> print(day1,Weekday.Tue,Weekday.Tue.value,day1==Weekday.Wed,Weekday(4))
Weekday.Mon Weekday.Tue 2 False Weekday.Thu

这里的访问两种方式都可以用。
成员值允许相同,第二个成员的名称被视作第一个成员的别名


使用元类

1 type()

>>> print(type(Weekday))#type()可以查看类型
<class 'enum.EnumMeta'>
>>> def fn(self,name='world'):#先定义函数
    print('hello,%s'%name)

>>> Hello=type('Hello',(object,),dict(hello=fn))
#依次传入三个参数:class名,tuple表示的继承父类,class方法名绑定函数
>>> h=Hello()
>>> h.hello()
hello,world
>>> h.hello('Bob')
hello,Bob

2 metaclass

个人觉得,这玩意吧,会降低的代码可读性,因此放弃加载本节。

相关文章

网友评论

    本文标题:【学习记录】Python3版本(5:模块)

    本文链接:https://www.haomeiwen.com/subject/ubgkhhtx.html