深入理解 python 虚拟机:花里胡哨的魔术方法

深入理解 python 虚拟机:花里胡哨的魔术方法

在本篇文章当中主要给大家介绍在 cpython 当中一些比较花里胡哨的魔术方法,以帮助我们自己实现比较花哨的功能,当然这其中也包含一些也非常实用的魔术方法。

深入分析 hash 方法

在 Python 中,__hash__() 方法是一种特殊方法(也称为魔术方法或双下划线方法),用于返回对象的哈希值。哈希值是一个整数,用于在字典(dict)和集合(set)等数据结构中进行快速查找和比较。__hash__() 方法在创建自定义的可哈希对象时非常有用,例如自定义类的实例,以便可以将这些对象用作字典的键或集合的元素。

下面是一些需要注意的问题和示例来帮助理解 __hash__() 方法:

  • 如果两个对象相等(根据 __eq__() 方法的定义),它们的哈希值应该相等。即,如果 a == b 为真,则 hash(a) == hash(b) 也为真,这一点非常重要,因为我们在使用集合和字典的时候,就需要保证容器当中每种对象只能够有一个,如果不满足这个条还的话,那么就可能会导致同一种对象在容器当中会存在多个。
  • 重写 __hash__() 方法通常需要同时重写 __eq__() 方法,以确保对象的相等性和哈希值的一致性。
  • 如果对象没有定义 __eq__方法,那么也不要定义 __hash__方法,因为如果遇到哈希值相等的对象时候,如果无法对两个对象进行比较的话,那么也会导致容易当中有多个相同的对象。
import random


class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return self.name == other.name and self.age == other.age

    def __hash__(self):
        return hash((self.name, self.age)) + random.randint(0, 1024)

    def __repr__(self):
        return f"[name={self.name}, age={self.age}]"


person1 = Person("Alice", 25)
person2 = Person("Alice", 25)


print(hash(person1))  
print(hash(person2))  


container = set()
container.add(person1)
container.add(person2)
print(container)

在上面代码当中我们重写了 __hash__ 函数,但是对象的哈希值每次调用的时候我们都加入一个随机数,因此即使 name 和 age 都相等,如果 hash 值不想等,那么可能会造成容器当中存在多个相同的对象,上面的代码就会造成相同的对象,上面的程序输出结果如下所示:

1930083569156318318
1930083569156318292
{[name=Alice, age=25], [name=Alice, age=25]}

如果重写上面的类对象:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return self.name == other.name and self.age == other.age

    def __hash__(self):
        return hash((self.name, self.age))

    def __repr__(self):
        return f"[name={self.name}, age={self.age}]"

那么容器器当中只会有一个对象。

如果我们只重写了 __hash__方法的时候也会造成容器当中有多个相同的对象。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # def __eq__(self, other):
    #     return self.name == other.name and self.age == other.age

    def __hash__(self):
        return hash((self.name, self.age)) # + random.randint(0, 1024)

    def __repr__(self):
        return f"[name={self.name}, age={self.age}]"

这是因为如果哈希值相同的时候还需要在比较两个对象是否相等,如果相等那么就不需要将这个对象保存到容器当中,如果不相等那么将会将这个对象加入到容器当中。

bool 方法

在 Python 中,object.__bool__() 方法是一种特殊方法,用于定义对象的布尔值。它在使用布尔运算符(如 if 语句和逻辑运算)时自动调用。__bool__() 方法应该返回一个布尔值,表示对象的真值。如果 __bool__() 方法未定义,Python 将尝试调用 __len__() 方法来确定对象的真值。如果 __len__() 方法返回零,则对象被视为假;否则,对象被视为真。

下面是一些需要注意的事项来帮助理解 __bool__() 方法:

  • __bool__() 方法在对象被应用布尔运算时自动调用。例如,在 if 语句中,对象的真值由 __bool__() 方法确定。
  • __bool__() 方法应该返回一个布尔值(TrueFalse)。
  • 如果 __bool__() 方法未定义,Python 将尝试调用 __len__() 方法来确定对象的真值。
  • 当对象的长度为零时,即 __len__() 方法返回零,对象被视为假;否则,对象被视为真。
  • 如果既未定义 __bool__() 方法,也未定义 __len__() 方法,则对象默认为真。

下面是一个示例,展示了如何在自定义类中使用 __bool__() 方法:

class NonEmptyList:
    def __init__(self, items):
        self.items = items
    
    def __bool__(self):
        return len(self.items) > 0

my_list = NonEmptyList([1, 2, 3])

if my_list:
    print("The list is not empty.")
else:
    print("The list is empty.")

对象的属性访问

在Python中,我们可以通过一些特殊方法来定制属性访问的行为。本文将深入介绍这些特殊方法,包括__getitem__()__setitem__()__delitem__()__getattr__()方法,以帮助更好地理解属性访问的机制和应用场景。

__getitem__()方法是用于索引操作的特殊方法。当我们通过索引访问对象的属性时,Python会自动调用该方法,并传入索引值作为参数。我们可以在该方法中实现对属性的获取操作,并返回相应的值。

class MyList:
    def __init__(self):
        self.data = []
    
    def __getitem__(self, index):
        return self.data[index]

my_list = MyList()
my_list.data = [1, 2, 3]

print(my_list[1])  # 输出: 2

在上面的例子中,我们定义了一个名为MyList的类,它具有一个属性data,该属性是一个列表。通过重写__getitem__()方法,我们使得可以通过索引来访问MyList对象的data属性。当我们使用my_list[1]的形式进行索引操作时,Python会自动调用__getitem__()方法,并将索引值1作为参数传递给该方法。

__setitem__()方法用于属性的设置操作,即通过索引为对象的属性赋值。当我们使用索引操作并赋值给对象的属性时,Python会自动调用__setitem__()方法,并传入索引值和赋值的值作为参数。

class MyList:
    def __init__(self):
        self.data = [0 for i in range(2)]

    def __setitem__(self, index, value):
        self.data[index] = value


my_list = MyList()

my_list[0] = 1
my_list[1] = 2

print(my_list.data)  # 输出: [1, 2]

在上述示例中,我们重写了__setitem__()方法来实现对对象属性的设置操作。当我们执行my_list[0] = 1和my_list[1] = 2的赋值操作时,Python会自动调用__setitem__()方法,并将索引值和赋值的值传递给该方法。在__setitem__()方法中,我们将值赋给了对象的data属性的相应索引位置。

__delitem__()方法用于删除对象属性的特殊方法。当我们使用del语句删除对象属性时,Python会自动调用__delitem__()方法,并传入要删除的属性的索引值作为参数。

class MyDict:
    
    def __init__(self):
        self.data = dict()

    def __delitem__(self, key):
        print("In __delitem__")
        del self.data[key]


obj = MyDict()
obj.data["key"] = "val"
del obj["key"] # 输出 In __delitem__

__getattr__() 是一个特殊方法,用于在访问不存在的属性时自动调用。它接收一个参数,即属性名,然后返回相应的值或引发 AttributeError 异常。

class MyClass:
    def __getattr__(self, name):
        if name == 'color':
            return 'blue'
        else:
            raise AttributeError(f"'MyClass' object has no attribute '{name}'")

my_obj = MyClass()
print(my_obj.color)  # 输出: blue
print(my_obj.size)   # 引发 AttributeError: 'MyClass' object has no attribute 'size'

在上面的示例中,当访问 my_obj.color 时,由于 color 属性不存在,Python 会自动调用 __getattr__() 方法,并返回预定义的值 'blue'。而当访问 my_obj.size 时,由于该属性也不存在,__getattr__() 方法会引发 AttributeError 异常。

__setattr__() 是一个特殊方法,用于在设置属性值时自动调用。它接收两个参数,即属性名和属性值。我们可以在该方法中对属性进行处理、验证或记录。

class MyClass:
    def __init__(self):
        self.color = 'red' # 输出:Setting attribute 'color' to 'red'

    def __setattr__(self, name, value):
        print(f"Setting attribute '{name}' to '{value}'")
        super().__setattr__(name, value)


my_obj = MyClass()
my_obj.color = 'blue'  # 输出: Setting attribute 'color' to 'blue'

当我们使用 . 的方式去访问对象属性的时候,首先会调用对象的 __getattribute__ 函数,如果属性不存在才会调用 __getattr__。当 __getattribute__ 方法无法找到指定的属性时,Python 会调用 __getattr__ 方法。以下是在之前的示例类 CustomClass 上添加 __getattr__ 方法的代码:

class CustomClass:
    def __init__(self):
        self.attribute = "Hello, world!"

    def __getattribute__(self, name):
        print(f"Accessing attribute: {name}")
        return super().__getattribute__(name)

    def __getattr__(self, name):
        print(f"Attribute {name} not found")
        return None

在这个示例中,我们在 CustomClass 中添加了 __getattr__ 方法。当 __getattribute__ 方法无法找到指定的属性时,会自动调用 __getattr__ 方法,并打印出属性名称 "attribute" 以及未找到属性的提示信息。

我们执行下面的代码:

obj = CustomClass()
print(obj.attribute)
print(obj.nonexistent_attribute)

输出结果如下所示:

Accessing attribute: attribute
Hello, world!
Accessing attribute: nonexistent_attribute
Attribute nonexistent_attribute not found
None

首先,我们访问存在的属性 attribute,此时 __getattribute__ 方法被调用,并打印出属性名称 "attribute",然后返回属性的实际值 "Hello, world!"。接着,我们尝试访问不存在的属性 nonexistent_attribute,由于 __getattribute__ 方法无法找到该属性,因此会调用 __getattr__ 方法,并打印出属性名称 "nonexistent_attribute" 以及未找到属性的提示信息,然后返回 None

上下文管理器

当我们需要在特定的代码块执行前后进行一些操作时,上下文管理器是一种非常有用的工具。上下文管理器可以确保资源的正确分配和释放,无论代码块是否出现异常。在Python中,我们可以通过实现 __enter____exit__ 方法来创建自定义的上下文管理器。

下面是一个简单的上下文管理器示例,展示了如何使用 object.__enter__object.__exit__ 方法来创建一个文件操作的上下文管理器:

class FileContextManager:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        self.file = None

    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file

    def __exit__(self, exc_type, exc_value, traceback):
        self.file.close()

with FileContextManager('example.txt', 'w') as file:
    file.write('Hello, world!')

在上述示例中,FileContextManager 类实现了 __enter____exit__ 方法。在 __enter__ 方法中,我们打开文件并返回文件对象,这样在 with 语句块中就可以使用该文件对象。在 __exit__ 方法中,我们关闭文件。

无论代码块是否抛出异常,__exit__ 方法都会被调用来确保文件被正确关闭。这样可以避免资源泄露和文件锁定等问题。使用上下文管理器可以简化代码,并提供一致的资源管理方式,特别适用于需要打开和关闭资源的情况,如文件操作、数据库连接等。

上述上下文管理器的 __exit__ 方法有三个参数:exc_typeexc_valuetraceback。下面是对这些参数的详细介绍:

  • exc_type(异常类型):这个参数表示引发的异常的类型。如果在上下文管理器的代码块中没有引发异常,它的值将为 None。如果有异常被引发,exc_type 将是引发异常的类型。

  • exc_value(异常值):这个参数表示引发的异常的实例。它包含了关于异常的详细信息,如错误消息。如果没有异常被引发,它的值也将为 None

  • traceback(回溯信息):这个参数是一个回溯对象,它包含了关于异常的堆栈跟踪信息。它提供了导致异常的代码路径和调用关系。如果没有异常被引发,它的值将为 None

总结

在本篇文章当中主要给大家介绍了一些常用和比较重要的魔术方法,这些方法在我们平时用的可能也比较多,比如 hash 和 eq 还有对象的属性访问,为了方便异常处理可以使用 exit 和 enter 这个方法,其实还有很多其他的魔术方法,这些方法在 python 官网都有介绍,可以直接访问 http://docs.python.org/3/reference/datamodel.html 。


本篇文章是深入理解 python 虚拟机系列文章之一,文章地址:http://github.com/Chang-LeHung/dive-into-cpython

更多精彩内容合集可访问项目:http://github.com/Chang-LeHung/CSCore

关注公众号:一无是处的研究僧,了解更多计算机(Java、Python、计算机系统基础、算法与数据结构)知识。

本文转载于网络 如有侵权请联系删除

相关文章

  • Java | if-else代码优化方案

    优化方案一:提前return,去除不必要的else如果if-else代码块包含return语句,可以考虑通过提前return,把多余else⼲掉,使代码更加优雅。优化前:if(condition){ //doSomething }else{ return } 复制优化后:if(!condition){ return } //doSomething复制优化方案二:使用条件三目运算符使⽤条件三⽬运算符可以简化某些if-else,使代码更加简洁,更具有可读性。优化前:intprice; if(condition){ price=80; }else{ price=100; } 复制优化后:intprice=condition?80:100;复制优化方案三:使用枚举在某些时候,使⽤枚举也可以优化if-else逻辑分⽀,按个⼈理解,它也可以看作⼀种表驱动⽅法。优化前:StringOrderStatusDes; if(orderStatus==0){ OrderStatusDes="订单未⽀付"; }elseif(OrderStatus==1){ OrderStatusDes=&

  • 【AICAMP —— Python】入门系列!(1.Python简介与环境配置)

    Python介绍1.Python简介相信你听过很多关于python的介绍,不论是朋友圈里或者各大广告都会说Python很好,python很强!确实如此。Python是一种解释型、面向对象、动态数据类型的高级程序设计语言(先不用纠结什么是解释型,什么是面向对象,知道有种语言叫python就行了,后面会讲的)。由GuidovanRossum(下图最右边一个,看这茂密的头发,你还要盘C++?)于1989年底发明,第一个公开发行版发行于1991年。像Perl语言一样,Python源代码同样遵循GPL(GNUGeneralPublicLicense)协议(一个开源协议,perl也是一种语言,听听就好)。官方宣布,2020年1月1日,停止Python2的更新。Python2.7被确定为最后一个Python2.x版本。(正经人现在谁还盘着python2不放呢?)同样,python具有以下几个特点:Python是一种解释型语言:这意味着开发过程中没有了编译这个环节,类似于PHP和Perl语言。(这个没什么太多解释的,像C++与java是需要编译的,python更省事!)Python是交互式语言:这意味

  • ​【LeetCode每日一题】87. 扰乱字符串

    【LeetCode每日一题】87.扰乱字符串题目:使用下面描述的算法可以扰乱字符串s得到字符串t:如果字符串的长度为1,算法停止如果字符串的长度>1,执行下述步骤:在一个随机下标处将字符串分割成两个非空的子字符串。即,如果已知字符串s,则可以将其分成两个子字符串x和y,且满足s=x+y。随机决定是要「交换两个子字符串」还是要「保持这两个子字符串的顺序不变」。即,在执行这一步骤之后,s可能是s=x+y或者s=y+x。在x和y这两个子字符串上继续从步骤1开始递归执行此算法。给你两个长度相等的字符串s1和s2,判断s2是否是s1的扰乱字符串。如果是,返回true;否则,返回false。示例1:输入:s1="great",s2="rgeat" 输出:true 解释:s1上可能发生的一种情形是: "great"-->"gr/eat"//在一个随机下标处分割得到两个子字符串 "gr/eat"-->"gr/eat"//随机决定:「保持这两个子字符串的顺序不变」 &

  • ECLIPSE中创建ABAP项目的步骤

    正文部分因为我看到很多人都问过关于Eclipse的ABAP开发工具的问题。所以写了这篇配置。在Eclipse中可以采取不同的方法来引入ABAP开发工具。1、首先要把eclipse安装上,去官网下载eclipsehttps://www.eclipse.org/downloads/2、然后打开eclipse,开始abap配置选择help-installnewsoftware3、选择添加并提供ABAP开发工具4、输入网址:https://tools.hana.ondemand.com/kepler或者https://tools.hana.ondemand.com/mars5、出现如下选择内容6、选择后,点击下一步7、开始安装8、安装后重启eclipse9、然后按照这个路径找:Window–>Perspective–>Other–选择ABAP10、然后选择file-选择创建ABAPPROJECT11、完成,开始ABAP开发

  • codeforces 1305C(思维)

    题意描述AC代码#include<bits/stdc++.h> #definexfirst #defineysecond #definePBpush_back #definemst(x,a)memset(x,a,sizeof(x)) #defineall(a)begin(a),end(a) #definerep(x,l,u)for(llx=l;x<u;x++) #definerrep(x,l,u)for(llx=l;x>=u;x--) #definesz(x)x.size() #defineIOSios::sync_with_stdio(false);cin.tie(0); usingnamespacestd; typedefunsignedlonglongull; typedefpair<int,int>PII; typedefpair<char,char>PCC; typedeflonglongll; typedefpair<ll,ll>PLL; constintN=2*1e5+10; constintM=1e5+10;

  • mysqldump命令详解 Part 9 --hex-blob 参数的使用

    实验环境:MySQL8.0.19Redhat7.4前面我们建立了数据库并建立相关的对象数据库表存储过程函数触发器事件今天的内容为--hex-blob的使用1.--hex-blob该参数将下面数据类型的栏位的数据以十六进制的形式导出BINARYVARBINARYBLOBBIT以及binary字符集的数据其中MySQL的BLOB类型可以有如下类型tinyblob:仅255个字符blob:最大限制到65K字节mediumblob:限制到16M字节longblob:可达4GB2.使用--hex-blob备份数据库备份数据库mysqldump-uroot-p--single-transaction--set-gtid-purged=OFF--databasestest--hex-blob>/tmp/hex.sql复制备份单表mysqldump-uroot-p--single-transaction--set-gtid-purged=OFF--databasestest--hex-blob--tablespictures>/tmp/hex.sql复制3.该参数影响3.1内容比较我们首先

  • 破解某滑动验证码

    首先申明:历时八天,本文作者(在多位好友的帮助下)已经成功破解该验证码成功率73%,但是出于网络安全与知识产权等因素(破解只是兴趣,不能咂人家饭碗),不会提供完整源代码。仅发布破解的思路和部分代码。如有转载请告知原作者,关于本文,原作者拥有最终解释权。0.目录:破解思路分析研究资料分享图像计算处理算法模拟鼠标轨迹破解成功。1.破解思路分析该验证码的在百度搜索极验即可找到。目前应用与6.5w家网站,,是目前相当安全的第二代验证码,比12306的好看而且实用多了。好夸完了,咱们来谈谈弱点。在爬虫届的终极大招就是phantomjs(无界面浏览器)。有意思的是他其实是用来做自动化测试的,那么能自动化测试就能自动化抓取(大雾)so。因为特别好用就被用来做爬虫的工具了。他具有截图鼠标键盘模拟获取源代码等方便的功能,想进一步学习请移步:http://phantomjs.org/api/webpage/method/send-event.html整体思路与流程:1:获取截图数据用phantomjs,首先打开这个网址,然后自然可以捕获到源代码。发现是需要验证,则截取整个界面的屏幕,一般而言每次出现验证码

  • 前端常见技术点-Javascript扫盲(26问)

    这里总结一下WEB前端面试JS部分的常见问题,同时这些问题也是对一些基础的技术概念和思想的理解。对这些基本知识的掌握程度和深度决定了你的技术层级。高级工程师是必须掌握本文列出的这些知识的,资深工程师则要对这些基本概念的纵向深度进行挖掘。Javascript技术部分1、JS有几种类型的值?(堆:原始数据类型和栈:引用数据类型),你能画一下他们的内存图吗?Stack为自动分配的内存空间,它由系统自动释放;而Heap则是动态分配的内存,大小不定也不会自动释放。基本类型:存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配。5种基本数据类型有undefined、null、boolean、number和string,它们是直接按值存放的,所以可以直接访问。引用类型:存放在堆内存中的对象,变量实际保存的是一个指针,这个指针指向另一个位置。每个空间大小不一样,要根据情况开进行特定的分配。当我们需要访问引用类型(如对象,数组,函数等)的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。2、JS如何实现继承?构造函数使用call、apply继承prototype原型模式Ca

  • webIDE里创建extension project时遇到错误的解决方案

    Supposeyoutrytocreateanewextensionprojectbasedononeexistingproject:ifyoumeetwiththiserrormessagebelow:(thenextbuttonisdisabled) ThisiscausedbythefactthatthenecessaryprojectjsonfileisnotcreatedbystandarddevelopmentforMynoteapplication.Allyouneedtodoistocreatea.project.jsonfilemanuallyandpastethefollowingsourcecode:{ "translation":{ "translationDomain":"", "supportedLanguages":"en,fr,de", "defaultLanguage":"en", "defau

  • Linux GDB jump 命令介绍

    jump命令基本用法是:jump<location>复制location可以是程序的行号或者函数的地址,jump会让程序执行流跳转到指定位置执行,当然其行为也是不可控制的,例如您跳过了某个对象的初始化代码,直接执行操作该对象的代码,那么可能会导致程序崩溃或其他意外行为。jump命令可以简写成j,但是不可以简写成jmp,其使用有一个注意事项,即如果jump跳转到的位置后续没有断点,那么GDB会执行完跳转处的代码会继续执行。举个例子:1intsomefunc() 2{ 3//代码A 4//代码B 5//代码C 6//代码D 7//代码E 8//代码F 9}复制假设我们的断点初始位置在行号3处(代码A),这个时候我们使用jump6,那么程序会跳过代码B和C的执行,执行完代码D(跳转点),程序并不会停在代码6处,而是继续执行后续代码,因此如果我们想查看执行跳转处的代码后的结果,需要在行号6、7或8处设置断点。jump命令除了跳过一些代码的执行外,还有一个妙用就是可以执行一些我们想要执行的代码,而这些代码在正常的逻辑下可能并不会执行(当然可能也因此会产生一些意外的结果,这需要读者自行

  • 对话 | 华为Fellow艾伟:Mate20的心脏——麒麟980性能全揭秘

    机器之心原创作者:李泽南8月31日,华为在德国柏林的IFA上向人们展示了旗下最新AI手机芯片麒麟980的强大实力。昨天,华为又在上海举行了一场发布会。这一次,我们与华为芯片和硬件的产品和技术规划负责人,华为Fellow艾伟聊了聊,深入了解了麒麟980更多的细节,以及华为在新一代芯片背后的研发历程。今天我们看到的麒麟980芯片,是华为三年多努力的成果。「从2015年麒麟950推出时,我们就与合作伙伴一道开始了对7纳米FinFIT工艺的探索。」艾伟表示。三年,对于一款采用新制程的芯片来说并不算长。华为表示,麒麟980在验证技术之后只有一次修改机会就面临量产了,这意味着几乎不能出错。在这个过程中研究人员花费了大量时间进行验证,幸运的是,今天我们看到的麒麟980已经成为了全球第一款7纳米手机芯片。作为为数不多自研芯片的通信厂商,华为对此感到非常自豪。「芯片集成度的创新是所有创新的基础,因为它必须在面积功耗一定的情况下保持性能的提升,为其他东西腾出空间。芯片是唯一一个『反通货膨胀』的行业。」艾伟表示。直到今天,麒麟芯片的发展仍然遵循摩尔定律。麒麟980率先搭载了定制化的CortexA76处理器。

  • MIT 6.S094· 深度增强学习 | 学霸的课程笔记,我们都替你整理好了

    MIT6.S094完整版授权中译视频戳文末「阅读原文」翻译|田茜涂世文蒋成整理|吴璇本篇是MIT6.S094第三讲深度强化学习的课程笔记。如果你想对增强学习有一个简要的了解,这次课程超级适合你。怎样教会系统在数据中感知世界并采取行动?一个人工智能系统需要实现的任务栈1.环境:系统工作的世界。2.传感器:采集物理世界的信息并将其转换成机器可以处理的原始数据。是机器人在物理世界工作的输入端。3.感知数据:传感器采集的原始数据。4.特征提取:从感知数据中提取特征。提取数据结构以便能够输入、识别、分割和理解数据。不同级别的抽象层都可以处理原始的感知数据。这个任务早期是由人类专家完成的,现在深度学习自动完成这个任务。 5.由于机器学习技术的应用,我们能够对感知数据实现更高级别的抽象表示。6.一旦机器学习技术将这些数据转换成简单、可操作的信息,我们就将这些信息聚合起来,称为知识。深度学习网络能够实现监督学习任务、生成任务、非监督技术。知识具有简洁的使用价值。这些价值可以是单一的价值,比如语音、图像等等。7.我们建立了一个分类系统,知识库,把所有的知识连接起来。8.代理推理基于这个分类系统:连接过去

  • iOS 动画(理论篇)

    在一段时间内显示的内容发生变化,这个过程称之为Animation(动画)。Animation作用于图层,图层也提供了接口用于添加Animation。当需要对图层进行Animation或者需要对Animation做出更多自定义行为的时候,就必须用到显示动画。显示动画基类CAAnimation,能用的动画类只有CABasicAnimation、CAKeyframeAnimation、CATransition、CAAnimationGroup。UIView层动画(+(void)animateWithDuration:.....) CALayer层动画(CABasicAnimation,CAKeyframeAnimation)接下来我会根据简单到复杂的顺序解释如何使用这些动画,注意事项和分析什么时候使用他们。1.先说简单的UIView层动画简单哪几种就不说了,介绍下iOS7之后有的弹簧动画.+(void)animateWithDuration:(NSTimeInterval)durationdelay:(NSTimeInterval)delayusingSpringWithDamping:(C

  • JUC 源码分析之CountDownLatch1 概述2 数据结构3 源码解析

    1概述CountDownLatch是一个同步辅助类,通过AQS实现的一个闭锁。 在其他线程完成它们的操作之前,允许一个多个线程等待。 简单来说,CountDownLatch中有一个锁计数,在计数到达0之前,线程会一直等待。运行机制2数据结构继承关系 CountDownLatch是一个"共享锁”",内部定义了自己的同步器Sync,Sync继承自AQS,实现了tryAcquireShared和tryReleaseShared两个方法。CountDownLatch中的锁是响应中断的,如果线程在对锁进行操作期间发生中断,会直接抛出InterruptedException3源码解析构造方法 CountDownLatch中的count其实就是AQS的state 从构造函数中可以看出,CountDownLatch"锁计数"本质上就是AQS的资源数state下面我们将通过await()和countDown()分析CountDownLatch的"latch"原理3.1await()await()AQS中`acquireSharedInt

  • javascript ES6 初次相见

    JS的ES6网上也热炒了好久了,我一直也没怎么太细看,今天想起来就写个东西,也为分享,也为学习。我喜欢接地气一点,所以网上的那些新名词我就不写了,就写点我理解的,它里面确实有许多新东西,----------有class,extends,constructor,,这样可以写类,写继承了,就这样:classaaaextendsbbb{ constructor(xx){ this.xx=xx; } returnVal(){ returnxx } }复制直接就把构造器写在类里了----------==>,箭头定义函数,多像php、Python啊,,这写法,真是晃眼。varxx=(a,b)=>a*b;xx(2,3)//6这种写法有什么意义?目前俺不理解----------functionfunc(){ console.log(arguments) } func(xx);//复制貌似arguments不能用了,啥也输出不出来----------var好像也不用了,改let和const了,以后局域变量就let;全局常量就const,这个跟PHP好像啊,----------又多了个foro

  • 适用于 Azure 虚拟网络的常见 PowerShell 命令

    如果想要创建虚拟机,需要创建虚拟网络或了解可在其中添加VM的现有虚拟网络。通常情况下,创建VM时,还需考虑创建本文所述资源。 有关安装最新版AzurePowerShell、选择订阅和登录到帐户的信息,请参阅如何安装和配置AzurePowerShell。 如果运行本文中的多个命令,以下一些变量可能将对你有用: $location-网络资源的位置。可以使用 Get-AzureRmLocation 查找适合你的地理区域。 $myResourceGroup-网络资源所在的资源组名称。 创建网络资源 任务命令 创建子网配置 $subnet1= New-AzureRmVirtualNetworkSubnetConfig -Name"mySubnet1"-AddressPrefixXX.X.X.X/XX$subnet2=New-AzureRmVirtualNetworkSubnetConfig-Name"mySubnet2"-AddressPrefixXX.X.X.X/XX典型的网络可能包含用于面向Internet的负载均衡器的子网,以及用于内部

  • 利用TM1650控制键盘操作

    文章地址:https://www.cnblogs.com/jqdy/p/13865153.html 1.TM1650简介   TM1650是深圳市天微电子股份有限公司系列数码管驱动芯片的一个型号,在驱动数码管的同时,可以控制键盘操作,数据手册下载。 驱动8段4位共阴数码管 工作电压3-5V 驱动7×4=28个按键 2.特点 价格比较便宜:淘宝上大约0.2元/个左右,加上外围电阻、电容,大概总共0.5元 占用I/O资源少:数据线(第3脚SDA)、时钟线(第2脚SCL)各一条 有按键后,第16脚DP会提供低电平,可用作单片机的外部中断,这样可省去单片机轮询按键的动作(7段开屏时) 3.原理图 CN2连接键盘,适用于最多4×4的键盘(将E、F、G都引出后可适用于4×7键盘) DIG1~DIG4分别连接键盘的4行 A~G分别连接键盘的7列,图中只用到4列,因此E、F、G未连线 MCU使用的是STC8G1K08-20PIN的 sbitKEY_SCL=P1^7 sbitKEY_SDA=P1^6 sbitKEY_IRQ=P3^7   4.根据时序图写

  • SpringMVC(十三)异常注解

    使用异常注解更方便 异常处理类 packagedemo15AnnotationException; importorg.springframework.stereotype.Controller; importorg.springframework.web.bind.annotation.ExceptionHandler; importorg.springframework.web.bind.annotation.RequestMapping; importorg.springframework.web.servlet.ModelAndView; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; /** *Createdbymycomon2018/3/30. */ @Controller publicclassExceptionController{ /** *这个标签就代表有异常的话就走这个方法 *@ExceptionHandler() *这个

  • html 基础

    1、文档声明头 任何一个标准的HTML页面,第一行一定是一个以 <!DOCTYPE...复制 开头的这一行,就是文档声明头,DocTypeDeclaration,简称DTD。此标签可告知浏览器文档使用哪种HTML或XHTML规范。 2、头标签(head) head标签都放在头部分之间。这里面包含了:<title>、<meta>、<link>,<style> <title>:指定整个网页的标题,在浏览器最上方显示。 <meta>:提供有关页面的基本信息 <link>:定义文档与外部资源的关系。 <style>:定义内部样式表与网页的关系 HTML标题 HTML标题(Heading)是通过<h1>-<h6> 标签来定义的. h是英文header标题的缩写,标题无处不在,它的应用范围十分广泛:网站结构、写作文、PPT等。h1是主标题,h2是副标题,h3、h4、h5、h6依次递减字体的大小。 实例 <h1>这是一个标题</h1>

  • HDU 1288 Hat&#39;s Tea

    Hat'sTea ProblemDescription HatisamemberofPGStudio.Hatcodesalotandsoheoftenbuysteaatteavendingmachine.Buttheteavendingmachinejusteatcoinsandspitouttea,ifyoufeedthemachinemorecoinsthanthetea’spriceandthemachinewillnotspitoutyourchange. YourprogramwillbegivennumbersandtypesofcoinsHathasandtheteaprice.Theteavendingmachineacceptscoinsofvalues1,5,10RMB(Jiao).TheprogramshouldoutputwhichcoinsHathastousepayingtheteasothatheusesasmanycoinsaspossible. Input Eachlineoftheinputcontainsfourintegernumbersse

  • Codeforces 766E

    题意:给一棵树(1e5),每个节点上有对应权值(0<=ai<=1e6)定义树上两个节点间的距离为路径中节点的异或,求所有节点对间的距离和(包括节点自身也作为节点对,距离为节点权值)。 解题思路:   做了771C后这道题就有感觉了。关键在于将每个权值的二进制位拆开计算,以dp[u][i][0]和dp[u][i][1]记录到达节点u的子树上的节点的距离的第i位为0和1的个数有多少,维护计算就可以了。比较僵的是开始写的时候没有考虑单独一个节点作为一个节点对,所以在每个递归的最后面单独加上到全局变量res中。   每一个递归的最开始,用局部变量num数组记录u的权值的二进制形式,同时初始化dp[u]数组。对每个子节点的遍历转移:   先递归子节点,返回后则已计算完毕。则有如果u的第i位为1,dp[u][i][1]+=dp[v][i][0],dp[u][i][0]+=dp[v][i][1];否则dp[u][i][1]+=dp[v][i][1],dp[u][i][0]+=dp[v][i][0];这里应该不难理解。   至于统计答案,只计算为1的即可,即intcnt1=dp[u][i]

相关推荐

推荐阅读