【Python】科研代码学习:一

【Python】科研代码学习:一

  • 前言
  • 魔方方法 `__dict__, __setattr__ , __getattr__ , __getattribute__`
  • `hasattr(obj, name)`
  • `super()`
  • 类型注解
  • 解包 `unpacking`
  • zip() 函数

前言

  • 搞科研,最重要的还是得看懂别人的源代码。
    这就意味着python不能太差
    看到比较有用的,或者不怎么看懂的代码,就搜索并学习,放在这里,供学习参考。
  • 最重要的技能:
    ∗ ∗ 在编译器中对包或者类或者方法,点击 F 12 查看源码,而不是百度问怎么获得啥啥参数 ∗ ∗ \color{red}** 在编译器中对包或者类或者方法,点击F12查看源码,而不是百度问怎么获得啥啥参数** 在编译器中对包或者类或者方法,点击F12查看源码,而不是百度问怎么获得啥啥参数
  • 可能会有错误,但都给出了程序的运行结果,可自行判断
    ∗ ∗ ( P y t h o n 3.9.18 ) ∗ ∗ \color{red}**(Python 3.9.18)** Python3.9.18

魔方方法 __dict__, __setattr__ , __getattr__ , __getattribute__

  • 类对象的属性会被放在 __dict__
class myClass():
    def __init__(self):
        print(self.__dict__)
        self.name = "Alice"
        print(self.__dict__)
        print(type(self.__dict__))
        
c = myClass()
"""
{}
{'name': 'Alice'}

"""
  • 自然,每次设置属性和获取属性的时候,会调用对应的 __setattr____getattribute__ / __getattr__方法
    那么后面两个有什么区别吗?
    • 如果属性存在,那么只进入 __getattribute__,否则才会再进入 __getattr__
    • 注意:在 __getattribute__ 中返回 self.xxx 当然会递归报错,需要调用 object.__getattribute()
      即不能在 __getattribute__ 中写 return self__dict__[xxx]
from typing import Any


class myClass():
    def __init__(self):
        self.name = "Alice"
        
    def __setattr__(self, __name: str, __value: Any) -> None:
        print("Now set " + __name + " to " + __value)
        self.__dict__[__name] = __value
            
        
    def __getattribute__(self, __name: str) -> Any:
        print("__getattribute__ : Now get " + __name)
        return object.__getattribute__(self, __name)
    
    def __getattr__(self, __name: str) -> Any:
        print("__getattr__ : Now get " + __name)
        if __name in self.__dict__:
            return self.__dict__[__name]
        else:
            return "Not Exist"
    
    
c = myClass()
print("\n**********\n")
print(c.name)
print("\n**********\n")
print(c.name2)
"""
Now set name to Alice
__getattribute__ : Now get __dict__

**********

__getattribute__ : Now get name
Alice

**********

__getattribute__ : Now get name2
__getattr__ : Now get name2
__getattribute__ : Now get __dict__
Not Exist
"""
  • 还有一个是 __delattr__(self, __name),在删除该属性的时候调用,不赘述了。

hasattr(obj, name)

  • 判断对象是否有某个属性
    如果对象有该属性返回 True,否则返回 False
    这里不需要在类里面使用也可以

super()

  • 在 python3 中,可以直接调用 super().xxx 调用直接继承父类的方法
  • 注意把下面代码中 CB 类的 super().__init__() 注释掉之后
    CC 类调用 super().__init__() 是没法进入到 CA 类中去的,尽管 CC 类是间接继承自 CA 类。
from typing import Any


class CA():
    def __init__(self):
        print("In A")
        self.name = "Alice"
        
class CB(CA):
    def __init__(self):
        print("In B")
        super().__init__()
        self.name = "Bob"

class CC(CB):
    def __init__(self):
        print("In C")
        super().__init__()
        self.name = "Cindy"
    
A = CA()
print("\n*****************\n")
B = CB()
print("\n*****************\n")
C = CC()
print("\n*****************\n")

print(A.name)
print(B.name)
print(C.name)

"""
In A

*****************

In B
In A

*****************

In C
In B
In A

*****************

Alice
Bob
Cindy
"""
  • 如果你希望修改或者返回父类的属性,可以:
super().__setattr__(__name, __value)
super().__getattr__(__name)

注意:也可以直接 super().name 之类的,获得父类的属性。
但使用 super().__setattr__() 貌似更规范

类型注解

  • 随着项目越来越大,就越来越需要开发者对函数参数做类型的注解
    知乎:python的类型注解【type hints】
    里面很多例子都很好,建议看一看。
    注意:只是作为注解,在运行中并不会限制参数类型!(有些编译器可能会有警告,大部分没有)
    可以看到下面的例子,仍然运行成功了。
from typing import Any


def foo(x : str):
    print("TYPE : " + str(type(x)))
    print("VALUE : " + str(x))


foo({"123":456})
foo("123")
foo(123)
foo(["123"])
foo
"""
TYPE : 
VALUE : {'123': 456}
TYPE : 
VALUE : 123
TYPE : 
VALUE : 123
TYPE : 
VALUE : ['123']
"""
  • 所有的类型注解可以查看 typing
  • 下面代码,List是来源于typing.List, 而小写的list来源是class 'list'
def foo(x : list):
	pass
	
from typing import List
def foo2(x : List):
	pass
  • 那么到底如何限定传入参数的类型呢?
    比如 module: Optional['Module'] ,那么就写:
if not isinstance(module, Module) and module is not None:
	raise TypeError(f"{torch.typename(module)} is not a Module subclass")

或者多用 assert 诊断也可以

解包 unpacking

  • unpacking 是一种将序列(例如元组或列表)的元素分解为单独变量的操作。这可以通过在变量前使用 * 操作符(asterisk)来实现。
a = (1,2)
b, c = a
print(b,c)


a = (1,2)
(b, c) = a
print(b,c)



a = [1,2]
(b, c) = a
print(b,c)

a = [1,2,3,4,5]
b, *c = a
print(b,c)

"""
1 2
1 2
1 2
1 [2, 3, 4, 5]
"""
  • 补充:
a,b,c = "123"
print(a,b,c)

a,b = 1,2
a,b = b,a
print(a,b)

a = 1,
print(a)

a, = [1]
print(a)

a, *b, c = [1,2,3,4,5]
print(a,b,c)


"""
1 2 3
2 1
(1,)
1
1 [2, 3, 4] 5
"""

zip() 函数

  • 可以将多个序列 ‘压缩’ 成一个 zip 对象,用迭代器访问
    迭代器的次数等于多个序列的长度最小值。
  • 序列,当然可以传入列表,元组,字典
a = [1,2,3,4]
b = ['a','b','c',6 ,7]

for x,y in zip(a,b):
    print(x,y)

print(list(zip(a,b)))

"""
1 a
2 b
3 c
4 6
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 6)]
"""
  • 也可以利用这个来构建字典
a = [1,2,3,4]
b = ['a','b','c',6 ,7]

dc = dict(zip(a,b))

for x,y in dc.items():
    print(x,y)

"""
1 a
2 b
3 c
4 6
"""

你可能感兴趣的:(【科研】,python,学习)