Python学习记录-高级1

元类

类就是一组用来描述如何生成一个对象的代码段。但是Python中的类还远不止如此,它的类同样也是一种对象,当使用关键字class时,Python解释器在执行的时候就会创建一个对象。

class ObjectCreator(object):  #创建了一个名为ObjectCreator的对象
    pass                      #这个对象拥有创建对象(实例对象)的能力

print(ObjectCreator)                #可以打印一个类

def echo(o):
    print(o)

echo(ObjectCreator)                 #可以将类做为参数传给函数
ObjectCreator.new_attribute = 'foo' #可以为类增加属性
print(ObjectCreator.new_attribute)
ObjectCreatorMirror = ObjectCreator #可以将类赋值给一个变量
print(ObjectCreatorMirror)
#outputs:
#<class '__main__.ObjectCreator'>
#<class '__main__.ObjectCreator'>
#foo
#<class '__main__.ObjectCreator'>

可以将它赋值给一个变量;可以拷贝它;可以为它增加属性;可以将它作为函数参数进行传递
动态地创建类:类也是对象,可以在运行时动态的创建它们,就像其他任何对象一样

def choose_class(name):
    if name == 'foo':
        class Foo(object):
            pass
        return Foo     # 返回的是类,不是类的实例
    else:
        class Bar(object):
            pass
        return Bar

MyClass = choose_class('foo')
print(MyClass)      # 函数返回的是类,不是类的实例
print(MyClass())    # 可以通过这个类创建类实例,也就是对象

使用type创建类:type可以接受一个类的描述作为参数,然后返回一个类。

#type(类名, 由父类名称组成的元组,包含属性的字典)
class Test:
    pass

print(Test())  #创建了一个Test类的实例对象;
#output:<__main__.Test object at 0x0000022E319D9860>
Test2 = type("Test2",(),{})     #定了一个Test2类
print(Test2())                  #创建了一个Test2类的实例对象
MyDogClass = type('MyDog', (), {})
print(MyDogClass)               #output:<class '__main__.MyDog'>
Foo = type('Foo', (), {'bar':True}) #使用type创建带有属性的类Foo
print(Foo,',',Foo.bar)      #outputs:<class '__main__.Foo'> , True
FooChild = type('FooChild', (Foo,),{}) #类继承
print(FooChild,',',FooChild.bar)  #添加的属性是类属性,并不是实例属性

def echo_bar(self): #定义了一个普通的函数
    print(self.bar)
#让FooChild类中的echo_bar属性,指向了上面定义的函数
FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar}) 
my_foo = FooChild()
my_foo.echo_bar()  #output:True

元类:元类就是用来创建类的“东西”。元类就是用来创建这些类(对象)的,元类就是类的类。函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类。
Python中所有的东西,注意,我是指所有的东西——都是对象。包括整数、字符串、函数以及类。它们全部都是对象,而且它们都是从一个类创建而来,这个类就是type。
元类就是创建类这种对象的东西。type就是Python的内建元类
__metaclass__属性:在定义一个类的时候为其添加__metaclass__属性,Python就会用元类来创建类

Python动态语言

在运行时可以改变其结构的语言 ,例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。
动态语言:可以在运行的过程中,修改代码
静态语言:编译时已经确定好代码,运行过程中不能修改
1 运行的过程中给对象绑定(添加)属性

class Person(object):
    def __init__(self, name = None, age = None):
        self.name = name
        self.age = age
P = Person("小明", "24")
P.sex = "male"          # 动态给实例绑定属性

2 运行的过程中给类绑定(添加)方法

import types
class Person(object):
    def __init__(self, name = None, age = None):
        self.name = name
        self.age = age
    def eat(self):
        print("eat food")

def run(self, speed):   #定义在类外的函数
    print("%s is running, his speed is %d km/h"%(self.name, speed))

P = Person("hill", 24)  #实例
P.eat()     #output:eat food
#P.run()     #Error直接添加出错
P.run = types.MethodType(run, P) #使用types模块添加实例方法
P.run(100)   #output:hill is running, his speed is 100 km/h

语法:types.MethodType ( function, instance )
对于静态方法:可以直接绑定并调用

@staticmethod
def testStatic():
    print("---static method----")

Person.testStatic = testStatic
Person.testStatic()

对于类方法::也可以直接绑定和调用

@classmethod
def testClass(cls):
    print("---class method----")
    cls.num = 100

Person.testClass = testClass
print(Person.num)
Person.testClass()

__slots__的作用

Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:

class Person(object):
    __slots__ = ("name", "age") #此时只能添加这两种属性

import导入模块:

按以下路径搜索

import sys
sys.path

添加路径:sys.path.append(‘/路径名’)
如:

['',
 'E:\\Anaconda3\\python36.zip',
 'E:\\Anaconda3\\DLLs',
 'E:\\Anaconda3\\lib',
 'E:\\Anaconda3',
......]

重新导入模块(导入模块之后如果模块发生修改,则无法获取新的内容),需要reload:

from imp import *
reload(模块名)

循环导入:几个模块之间相互重复调用,可以另建一个主模块分别导入子模块使用。

作用域

命名空间、局部变量、全局变量
LEGB 规则

locals -> enclosing function -> globals -> builtins

locals:当前所在命名空间(如函数、模块),函数的参数也属于命名空间内的变量
enclosing:外部嵌套函数的命名空间(闭包中常见)
globals:全局变量,函数定义所在模块的命名空间
builtins:内建模块的命名空间
内建:Python 在启动的时候会自动载入很多内建的函数、类,比如 dict,list,type,print,这些都位于 __builtin__ 模块中

is和==

a=[1];b=[1]
a == b
a is b
c=a
print(a,b,c)
print(id(a),id(b),id(c))
输出为:
Ture
False
[1] [1] [1]
2160069216008 2160068308424 2160069216008

即:is用于比较两个引用是否指向同一个对象;==用于比较两个对象是否相等

深拷贝、浅拷贝

浅拷贝:指向同一块内存地址

a=[1];b=a
print(id(a),id(b))
a.append(2)
print(a,b)
输出:
2160069215432 2160069215432
[1, 2] [1, 2]

深拷贝:不同的存储1单元

import copy
a=[1]; c = copy.deepcopy(a)
print(id(a),id(c))
a.append(2)
print(a,c)
输出
2160069013448 2160069216136
[1, 2] [1]

deepcopy对嵌套的引用同样是另起一块内存来存储。(完全深拷贝)
copy.copy和copy.deepcopy的区分:copy.copy不能对嵌套的内容深拷贝
copy对不可变类型(如元组)不执行深拷贝。

进制转换

bin(10)        #10→2
int("1001",2)  #2→10
hex(10)        #10→16
int('ff', 16)  #16→10
bin(0xa)       #16→2
hex(0b1001)    #2→16

位运算

print(9&8,9&5,9|5,9^5,~9,~5)
结果:
8 1 13 12 -10 -6

私有化

xx: 公有变量
_x: 单前置下划线,私有化属性或方法,from somemodule import *禁止导入,类对象和子类可以访问
__xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部直接访问(名字重整所以访问不到)
__xx__:双前后下划线,用户名字空间的魔法对象或属性。例如:__init__ , __ 不要自己发明这样的名字
xx_:单后置下划线,用于避免与Python关键词的冲突
父类中属性名为: __名字 的,子类不继承,子类不能访问
如果在子类中向 __名字 赋值,那么会在子类中定义的一个与父类相同名字的属性
_名 的变量、函数、类在使用from xxx import *时都不会被导入
通过name mangling(名字重整(目的就是以防子类意外重写基类的方法或者属性)如:_Class__object)机制就可以访问私有。

property的使用

对私有属性,可以添加getter和setter方法来访问:

class Money(object):
    def __init__(self):
        self.__money = 0
    def getMoney(self):                    #使用getMoney方法访问私有属性self.__money
        return self.__money
    def setMoney(self, value):             #使用setMoney方法访问私有属性self.__money
        if isinstance(value, int):
            self.__money = value
        else:
            print("error:不是整型数字")

使用property升级getter和setter方法

class Money(object):
    def __init__(self):
        self.__money = 0
    def getMoney(self):
        return self.__money
    def setMoney(self, value):
        if isinstance(value, int):
            self.__money = value
        else:
            print("error:不是整型数字")
    money = property(getMoney, setMoney)   #property的使用
a = Money()
a.money              #此时为0
a.money = 100        #相当于a.setMoney(100)
a.money              #此时为100
a.getMoney()         #100
print(a.money)       #相当于调用了a.getMoney

使用装饰器 @property 成为属性函数,可以对属性赋值时做必要的检查
作用:将方法转换为只读、重新实现一个属性的设置和读取方法,可做边界判定

class Money(object):
    def __init__(self):
        self.__money = 0
    @property
    def money(self):
        return self.__money
    @money.setter
    def money(self, value):
        if isinstance(value, int):
            self.__money = value
        else:
            print("error:不是整型数字")

垃圾回收

小整数对象池:小整数的定义是 [-5, 257) 这些整数对象是提前建立好的,不会被垃圾回收,即常驻于内存。在一个 Python 的程序中,所有位于这个范围内的整数使用的都是同一个对象。单个字符共用对象,也常驻内存
大整数对象池:每一个大整数,均创建一个新的对象。
intern机制:单个单词(没有空格),不可修改,默认开启intern机制,共用对象,引用计数为0,则销毁 ;字符串(含有空格),不可修改,没开启intern机制,不共用对象,引用计数为0,销毁
Garbage collection(GC垃圾回收):python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略
引用计数机制:python里每一个东西都是对象,它们的核心就是一个结构体:PyObject

typedef struct_object {
    int ob_refcnt;
    struct_typeobject *ob_type;
} PyObject;

它是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少。当引用计数为0时,该对象生命就结束了。
优点:简单、实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时。
缺点:维护引用计数消耗资源、循环引用

垃圾回收机制

导致引用计数+1的情况:1对象被创建,例如a=23;2对象被引用,例如b=a;3对象被作为参数,传入到一个函数中,例如func(a);4对象作为一个元素,存储在容器中,例如list1=[a,a]
导致引用计数-1的情况:1对象的别名被显式销毁,例如del a;2对象的别名被赋予新的对象,例如a=24;3一个对象离开它的作用域,例如f函数执行完毕时,func函数中的局部变量(全局变量不会);4对象所在的容器被销毁,或从容器中删除对象
查看一个对象的引用计数

import sys
a = "hello world"   #比正常计数大1
sys.getrefcount(a)  #因调用函数时传入a,让a的计数+1

循环引用导致内存泄露
触发垃圾回收:调用gc.collect();当gc模块的计数器达到阀值的时候;程序退出的时候

调试

猜你喜欢

转载自blog.csdn.net/muerjie5669/article/details/82467955
今日推荐